Ajax

Ajax简介

AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。

  • 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
  • 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
  • AJAX局部刷新

jQuery实现的ajax

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script>
//.shadow{position: fixed;left: 0;top: 0;right: 0;bottom: 0;background-color: black;opacity: 0.4;z-index: 999;}
 
$( "#m_add_ok" ).click( function (){
         $.ajax({
                     url: '/m_user_add/' // 要提交的地址
                     type: 'POST' ,     // GET或POST,提交方式
                     //dataType:'JSON',
                     data: {           // 提交的数据
                          'name' : $( "#m_add_box input[name='name']" ).val(),
                             'gender' :$( "#m_add_box input[name='gender']:checked" ).val(),
                             'email' :$( "#m_add_box input[name='email']" ).val(),
                             'depart_id' :$( "#m_add_box select[name='depart_id']" ).val()
                     },
                     success: function (data){
                         // 当服务端处理完成后,返回数据时,该函数自动调用
                         // data=服务端返回的值 默认是字符串
                         // console.log(data);
                         // JSON.parse(字符串) => 对象
                         // JSON.stringify(对象) => 字符串
                         var data=JSON.parse(data) //如果上面写了dataType:'JSON'  就相当于把success函数的参数data字符串转化成json对象,这就不需要写了json.parse(data)
                         if (data.status){
                             location.reload();
                             // location.href='/user_list/';
                         } else {
                             $( '#titlemsg' ).text(data.titlemsg);
                         }
                     }
                 })
         });
</script>

一、jQuery.ajax()

1、请求参数

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
######################------------data---------################
 
        data: 当前ajax请求要携带的数据,是一个json的 object 对象,ajax方法就会默认地把它编码成某种格式
              (urlencoded:?a = 1 &b = 2 )发送给服务端;此外,ajax默认以get方式发送请求。
 
              function testData() {
                $.ajax( "/test" ,{     / / 此时的data是一个json形式的对象
                   data:{
                     a: 1 ,
                     b: 2
                   }
                });                   / / ?a = 1 &b = 2
######################------------processData---------################
 
processData:声明当前的data数据是否进行转码或预处理,默认为true,即预处理; if 为false,
              那么对data:{a: 1 ,b: 2 }会调用json对象的toString()方法,即{a: 1 ,b: 2 }.toString()
              ,最后得到一个[ object Object ]形式的结果。
             
######################------------contentType---------################
 
contentType:默认值: "application/x-www-form-urlencoded" 。发送信息至服务器时内容编码类型。
              用来指明当前请求的数据编码格式;urlencoded:?a = 1 &b = 2 ;如果想以其他方式提交数据,
              比如contentType: "application/json" ,即向服务器发送一个json字符串:
                $.ajax( "/ajax_get" ,{
              
                   data:JSON.stringify({
                        a: 22 ,
                        b: 33
                    }),
                    contentType: "application/json" ,
                    type : "POST" ,
              
                });                          / / {a: 22 , b: 33 }
 
              注意:contentType: "application/json" 一旦设定,data必须是json字符串,不能是json对象
 
              views.py:   json.loads(request.body.decode( "utf8" ))
 
 
######################------------traditional---------################
 
traditional:一般是我们的data数据有数组时会用到 :data:{a: 22 ,b: 33 ,c:[ "x" , "y" ]},
               traditional为false会对数据进行深层次迭代; 

2、响应参数

?
1
2
3
4
5
6
7
8
9
10
11
12
/*
 
dataType:  预期服务器返回的数据类型,服务器端返回的数据会根据这个值解析后,传递给回调函数。
             默认不需要显性指定这个属性,ajax会根据服务器返回的content Type来进行转换;
             比如我们的服务器响应的content Type为json格式,这时ajax方法就会对响应的内容
             进行一个json格式的转换,if转换成功,我们在success的回调函数里就会得到一个json格式
             的对象;转换失败就会触发error这个回调函数。如果我们明确地指定目标类型,就可以使用
             data Type。
             dataType的可用值:html|xml|json|text|script
             见下dataType实例
 
*/

二、jQuery.serialize()

该函数主要根据用于提交的有效表单控件的name和value,将它们拼接为一个可直接用于表单提交的文本字符串,该字符串已经过标准的URL编码处理(字符集编码为UTF-8)。

  • jQuery 1.0 新增该函数。语法:jQueryObject.serialize()
  • 返回值:serialize()函数的返回值为String类型,返回将表单元素编码后的可用于表单提交的文本字符串。
  • 不在标签内的、没有name属性的、带有disabled属性的、没有被选中的表单控件不会被提交。
  • serialize()函数通常用于将表单内容序列化,以便通过AJAX方式提交。
  • serialize()函数用于序列化所有表单元素。$("form").serialize()
  • serialize()函数用于序列化部分表单元素。$(":text, select, :checkbox").serialize()
def ajax_login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    else:
        import json
        ret = {'status': True,'msg': None}
        obj = LoginForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
        else:
            # print(obj.errors) # obj.errors对象
            ret['status'] = False
            ret['msg'] = obj.errors
        v = json.dumps(ret)
        return HttpResponse(v)


<body>
    <h1>用户登录</h1>
    <form id="f1" >
        {% csrf_token %}
        <p>
            <input type="text" name="user" />
        </p>
        <p>
            <input type="password" name="pwd" />
        </p>

        <a οnclick="submitForm();">提交</a>
    </form>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        function submitForm(){
            $('.c1').remove();
            $.ajax({
                url: '/ajax_login/',
                type: 'POST',
                data: $('#f1').serialize(),// user=alex&pwd=456&csrftoen=dfdf\
                dataType:"JSON",
                success:function(arg){
                    console.log(arg);
                    if(arg.status){

                    }else{
                        $.each(arg.msg,function(index,value){
                            console.log(index,value);
                            var tag = document.createElement('span');
                            tag.innerHTML = value[0];
                            tag.className = 'c1';
                            $('#f1').find('input[name="'+ index +'"]').after(tag);
                        })
                    }
                }
            })
        }
    </script>
</body>

csrf跨站请求伪造

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<body>
   
<!--
{% csrf_token %} 生成input框
{{ csrf_token }} 生成随机字符串
-->
   
     <form method= "POST" action= "/csrf1.html" >
         {% csrf_token %}
         <input id= "user" type= "text" name= "user" />
         <input type= "submit" value= "提交" />
         <a id= "a_sub" >Ajax提交</a>
     </form>
   
     <script src= "/static/jquery-1.12.4.js" ></script>
     <script>
   
         $( "#a_sub" ).click( function (){
             var user = $( '#user' ).val();
             $.ajax({
                 url: '/csrf1.html' ,
                 type: 'POST' ,
                 //方式1:
                 data: { "user" :user, 'csrfmiddlewaretoken' : $( "[name='csrfmiddlewaretoken']" ).val()},
                 //方式2:
                 // data: { "user":user,'csrfmiddlewaretoken': '{{ csrf_token }}'},
                 success: function (arg){
                     console.log(arg);
                 }
   
             })
         });
   
     </script>
   
   
     <script src= "/static/jquery.cookie.js" ></script>
     <script>
         $( "#a_sub" ).click( function (){
             var user = $( '#user' ).val();
             $.ajax({
                 url: '/csrf1.html' ,
                 //方式3:放在请求头中
                 headers:{ 'X-CSRFToken' : $.cookie( 'csrftoken' )},
                 type: 'POST' ,
                 data: { "user" :user},
                 success: function (arg){
                     console.log(arg);
                 }
   
             })
         });
</script>
   
</body>

stringify与parse方法

?
1
2
3
4
5
6
7
8
JSON.parse():     用于将一个 JSON 字符串转换为 JavaScript 对象 
eg:
console.log(JSON.parse( '{"name":"tom"}' ));
console.log(JSON.parse( '{name:"tom"}' )) ;   // 错误
console.log(JSON.parse( '[12,undefined]' )) ;   // 错误
 
JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串。 
eg:  console.log(JSON.stringify({ 'name' : "tom" }));

上传文件

一、Ajax(FormData)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
 
<style>
 
    .avatar_con {
        height: 100px;
        width: 100px;
        position: relative;
 
    }
 
    .avatar_con iframe {
        display: none
    }
 
    .avatar_con img {
        height: 100%;
        width: 100%;
        border: 0;
        overflow: hidden;
        max-height: 100px;
    }
 
    .avatar_con #previewImg {
        border-radius: 50%;
        border: 1px solid #dddddd;
        padding: 3px;
        height: 96px;
        width: 96px;
    }
 
    .avatar_con #avatarImg {
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        opacity: 0;
        position: absolute;
        z-index: 102;
    }
    .avatar-avatar_con .text {
        position: absolute;
        left: 0;
        bottom: 0;
        text-align: center;
    }
 
</style>
 
<body>
 
 
<h1>jQuery Ajax上传文件</h1>
<div class="avatar_con">
        <label for="avatar">
        <img id="previewImg" src="/media/avatar/default.png">
        <div class="text">点击图片更换</div>
        </label>
        <input id="avatarImg" name="avatar" type="file"/>
 
</div>
 
<script src="http://code.jquery.com/jquery-1.12.3.min.js"></script>
<script type="text/javascript">
    $(function () {
        bindChangeAvatar();
    });
 
    // ajax上传文件
 
    function bindChangeAvatar() {
        $('#avatarImg').change(function () {
 
            /*
                // 头像预览 方法1:
                // 获取用户选中的文件对象
                var file_obj = $(this)[0].files[0];
                // 获取文件对象的路径
                var reader = new FileReader();
                reader.readAsDataURL(file_obj);
                // 修改img的src属性 ,src=文件对象的路径
                reader.onload = function () {
                    $("#previewImg").attr("src", reader.result)
                };
             */


            /*  本地上传预览 方法2:
            var obj = $(this)[0].files[0];
                // Ajax发送后台,并获取路径
                // img.src = 获取路径
                var v = window.URL.createObjectURL(obj);
                $('#previewImg').attr('src',v);
                $('#previewImg').load(function(){
                    window.URL.revokeObjectURL(v);
                });
            */

            /*
            本地上传预览 方法3:  Ajax上传
             */
 
                var formdata=new FormData();
                formdata.append("avatar",$("#avatarImg")[0].files[0]);
                formdata.append("csrfmiddlewaretoken","{{ csrf_token }}");  //csrf
 
 
                $.ajax({
                    url:"",  //不填写就是当前 /upload/
                    type:"post",
                    contentType:false,  // 用formdata的时候需要设置
                    processData:false,  // 用formdata的时候需要设置
                    data:formdata,
                    success:function(arg){
                        arg = JSON.parse(arg);
                        if (arg.status) {
                            console.log(arg.data);
                            // 头像预览 方法3:
                            $('#previewImg').attr('src', '/' + arg.data);
                        }
                    }
                })
 
        })
    }
 
</script>
</body>
</html>

二、伪Ajax上传文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<style>

    .avatar_con {
        height: 100px;
        width: 100px;
        position: relative;

    }

    .avatar_con iframe {
        display: none
    }

    .avatar_con img {
        height: 100%;
        width: 100%;
        border: 0;
        overflow: hidden;
        max-height: 100px;
    }

    .avatar_con #previewImg {
        border-radius: 50%;
        border: 1px solid #dddddd;
        padding: 3px;
        height: 96px;
        width: 96px;
    }

    .avatar_con #avatarImg {
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        opacity: 0;
        position: absolute;
        z-index: 102;
    }
    .avatar-avatar_con .text {
        position: absolute;
        left: 0;
        bottom: 0;
        text-align: center;
    }

</style>

<body>

<h1>伪 Ajax上传文件</h1>
<div class="avatar_con">
    <iframe id="upload_iframe" name="upload_iframe"></iframe>
    <form method="POST" action="/upload/" enctype="multipart/form-data" target="upload_iframe">
        <!--target和iframe的name 进行关联-->
        <!--别忘了 编码格式 enctype="multipart/form-data"-->
        {% csrf_token %}
        <img id="previewImg" src="/media/avatar/default.png">
        <div class="text">点击图片更换</div>
        <input id="avatarImg" name="avatar" type="file"/>
    </form>
</div>


<script src="http://code.jquery.com/jquery-1.12.3.min.js"></script>
<script type="text/javascript">
    $(function () {
        bindChangeAvatar();
    });

    function bindChangeAvatar() {
        $('#avatarImg').change(function () {
            $(this).parent().submit();

            $('#upload_iframe').load(function () {
                var con = this.contentWindow.document.body.innerText;
                con = JSON.parse(con);
                if (con.status) {
                    console.log(con.data);
                    $('#previewImg').attr('src', '/' + con.data);
                }

            })

        })
    }

</script>

</body>
</html>

三、原生Ajax上传文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<style>

    .avatar_con {
        height: 100px;
        width: 100px;
        position: relative;

    }

    .avatar_con iframe {
        display: none
    }

    .avatar_con img {
        height: 100%;
        width: 100%;
        border: 0;
        overflow: hidden;
        max-height: 100px;
    }

    .avatar_con #previewImg {
        border-radius: 50%;
        border: 1px solid #dddddd;
        padding: 3px;
        height: 96px;
        width: 96px;
    }

    .avatar_con #avatarImg {
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        opacity: 0;
        position: absolute;
        z-index: 102;
    }
    .avatar-avatar_con .text {
        position: absolute;
        left: 0;
        bottom: 0;
        text-align: center;
    }

</style>

<body>


<h1>原生Ajax上传文件</h1>
<div class="avatar_con">
        <label for="avatar">
        <img  id="previewImg" src="/media/avatar/default.png">
        <div class="text">点击图片更换</div>
        </label>
        <input οnchange="bindChangeAvatar()" id="avatarImg" name="avatar" type="file"/>

</div>



<script>

function bindChangeAvatar(){

    var formdata = new FormData();
    formdata.append("avatar",document.getElementById('avatarImg').files[0]);
    formdata.append("csrfmiddlewaretoken","{{ csrf_token }}");  //csrf

    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            var arg = JSON.parse(xhr.responseText);
            document.getElementById('previewImg').src='/' + arg.data
        }
    };
    xhr.open('POST','/upload/');
    /*xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
    发post请求必须设置Content-Type,request.POST才有数据,并且已转换成字典,
    不然就要去request.body中取值还是字节 b'a=1&b=2'
    如果发送的是formdata 则不需要设置
    */
    xhr.send(formdata);
}

</script>

</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>首页</h1>
    <input type="text" id="i1" />
    +
    <input type="text" id="i2" />
    =
    <input type="text" id="i3" />

    <input type="button" id="btn1" value="jQuery Ajax" onclick="add1();" />
    <input type="button" id="btn2" value="原生Ajax" onclick="add2();" />

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        function add1(){
            $.ajax({
                url: '/add1/',
                type: 'POST',
                data: {'i1': $('#i1').val(),'i2': $('#i2').val()},
                success:function(arg){
                    $('#i3').val(arg);
                }
            })
        }

        function add2(){
            /*
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    alert(xhr.responseText);
                }
            };
            xhr.open('GET','/add2/?i1=12&i2=19');
            xhr.send();
            */
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    alert(xhr.responseText);
                }
            };
            xhr.open('POST','/add2/');
            xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
            /*发post请求必须设置Content-Type,request.POST才有数据,并且已转换成字典,不然就要去request.body中取值还是字节 b'a=1&b=2'
            * 如果发送的是formdata 则不需要设置
            * */
            xhr.send("i1=12&i2=19");
        }
    </script>
</body>
</html>
get方式

四、服务端处理上传文件

# 配置文件:
# 与用户上传相关的配置
MEDIA_ROOT= os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"

# 路由中:
from django.urls import path, re_path
from django.views.static import serve
from django.conf import settings
from app01 import views

urlpatterns = [
    # media配置:
    re_path(r"media/(?P<path>.*)$", serve, {"document_root": settings.MEDIA_ROOT}),
    # 文本编辑器上传图片url
    path('upload/', views.upload),
]

# 视图中:
import os
import time


def upload(request):
    ret = {'status': False, 'data': None, }
    if request.method == 'POST':
        # print(request.body)  # 请求报文中的请求体    b'a=1&b=2'
        # print(request.POST)  # if contentType==urlencoded ,request.POST才有数据
        # print(request.FILES) #文件都在这下面
        file_obj = request.FILES.get('avatar') #文件对象
        file_obj.name = "%s%s" % (time.time(), file_obj.name)
        file_dir = 'media%savatar' % (os.sep)
        if not os.path.exists(file_dir):
            os.makedirs(file_dir)
        file_path = os.path.join("media", "avatar", file_obj.name)
        with open(file_path, 'wb') as f:
            for line in file_obj:
                f.write(line)
        ret['status'] = True
        ret['data'] = file_path

        # cur_nid = request.session['user_info'].get('nid')
        # row = models.UserInfo.objects.filter(nid=cur_nid).update(avatar='/%s'%(file_path))
        # request.session['user_info']['avatar']='/%s'%(file_path)

        return HttpResponse(json.dumps(ret))
    return render(request, "upload.html")

五、models.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
     """
     用户信息
     """
     nid = models.AutoField(primary_key = True )
     telephone = models.CharField(max_length = 11 , null = True , unique = True )
     avatar = models.FileField(upload_to = 'avatars/' , default = "avatars/default.png" )
     create_time = models.DateTimeField(verbose_name = '创建时间' , auto_now_add = True )
 
     blog = models.OneToOneField(to = 'Blog' , to_field = 'nid' , null = True , on_delete = models.CASCADE)
 
     def __str__( self ):
         return self .username
 
     class Meta:
         verbose_name = '用户信息'
         verbose_name_plural = '用户信息'

六、带form验证

"""
Myforms.py中:
from django import forms
class UploadFileForm(forms.Form):
    title = forms.CharField(max_length=32)
    avatar = forms.FileField()

视图中:
import os
import time
from .Myforms import UploadFileForm

def upload(request):
    if request.method == 'POST':
        # form = UploadFileForm(data = request.POST, files = request.FILES)  # 注意获取数据的方式
        form = UploadFileForm(request.POST, request.FILES)  # 注意获取数据的方式
        if form.is_valid():

            file_obj = request.FILES.get('avatar')
            file_obj.name = "%s%s" % (time.time(), file_obj.name)
            file_dir = 'media%savatar' % (os.sep)
            if not os.path.exists(file_dir):
                os.makedirs(file_dir)
            file_path = os.path.join("media", "avatar", file_obj.name)
            with open(file_path, 'wb') as f:
                for line in file_obj:
                    f.write(line)

            # cur_nid = request.session['user_info'].get('nid')
            # row = models.UserInfo.objects.filter(nid=cur_nid).update(avatar='/%s'%(file_path))
            # request.session['user_info']['avatar']='/%s'%(file_path)

            return redirect('/')
        else:
            return render(request, "upload.html", locals())

    form = UploadFileForm()
    return render(request, "upload.html",{'form': form})

模板中:
 <form method="POST" action="/upload/" enctype="multipart/form-data">
                 {% csrf_token %}
                {% for field in form %}
                    <div class="form-group">
                        <label for="{{ field.auto_id }}">{{ field.label }}</label>
                        {{ field }} <span class="pull-right error">{{ field.errors.0 }}</span>
                    </div>
                {% endfor %}

                 <input type="submit" class="btn btn-default" value="提交"/>
</form>
"""

浏览器的同源策略

  • 跨域是因为浏览器的同源策略导致的,也就是说浏览器会阻止非同源的请求
  • 域名不同或者端口不同都属于非同源的
  • 浏览器只阻止表单以及ajax请求,并不会阻止src请求,所以cnd,图片等src请求都可以发

解决跨域

方式一:CORS跨域请求

  • CORS即Cross Origin Resource Sharing 跨域资源共享
  • 随着技术的发展,现在的浏览器可以支持主动设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。
  • 跨域请求还分为两种,一种叫简单请求,一种是复杂请求

1、简单请求

  • HTTP方法是下列方法之一 : HEAD, GET,POST
  • HTTP头信息不超出以下几种字段 : Accept, Accept-Language, Content-Language, Last-Event-ID , Content-Type
  • 其中Content-Type只能是下列类型中的一个 : application/x-www-from-urlencoded , multipart/form-data , text/plain
  • 简单请求:一次请求
  • 简单请求:服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'

2、复杂请求

  • 任何一个不满足上述要求的请求,即会被认为是复杂请求
  • 复杂请求:两次请求,在发送数据之前会先发一次请求用做“预检”,OPTIONS请求,只有“预检”通过后才再发送一次请求用于数据传输。

3、关于“预检”

  • 请求方式:OPTIONS
  • “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息

4、如何“预检”

  • 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过 Access-Control-Request-Method
  • 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过 Access-Control-Request-Headers

5、ContentType

  • 请求头ContentType指的是请求体的编码类型,常见的类型共有3种:
  • application/x-www-form-urlencoded 这应该是最常见的 POST 提交数据的方式了。浏览器的原生表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。
  • multipart/form-data 这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让表单的 enctype 等于 multipart/form-data。
  • application/json 用来告诉服务端消息主体是序列化后的 JSON 字符串。

方式二:Jsonp

  • Jsonp的实现原理是根据浏览器不阻止src请求来实现的,通过script标签的跨域特性来绕过同源策略。
  • JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。
  • JsonP解决跨域只能发送get请求,并且实现起来需要前后端交互比较多。
  • 如果报错ALLOWED_HOSTS 需要在settings.py 中配置需要访问的域名 ALLOWED_HOSTS = ['http://www.s4.com']
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<input type="button" οnclick="AjaxRequest()" value="跨域Ajax" />


<div id="container"></div>

<script src="jquery-1.8.2.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        function AjaxRequest() {
            $.ajax({
                url: 'http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403',
                type: 'GET',
                dataType: 'jsonp',
                jsonp: 'callback',
                jsonpCallback: 'list',
                success: function (data) {
                    $.each(data.data,function(i){
                        var item = data.data[i];
                        var str = "<p>"+ item.week +"</p>";
                        $('#container').append(str);
                        $.each(item.list,function(j){
                            var temp = "<a href='" + item.list[j].link +"'>" + item.list[j].name +" </a><br/>";
                            $('#container').append(temp);
                        });
                        $('#container').append("<hr/>");
                    })

                }
            });
        }
</script>
</body>
</html>
实例:Ajax跨域
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>

</head>
<body>
    <input type="button" value="获取用户列表" οnclick="getUsers();" />
    <ul id="user_list">

    </ul>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        /*
        function getUsers(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    var content = xhr.responseText;
                    console.log(content);
                }
            };
            xhr.open('GET','http://www.s4.com:8001/users/');
            xhr.send();
        }
        */
        //a = ['alex','eric','egon']

        /*
         function getUsers(){
             var tag = document.createElement('script');
            tag.src = "http://www.s4.com:8001/users/?callback=bbb?sdd";
            document.head.appendChild(tag);
         }

        function bbb(arg){
            console.log(arg);
        }
        */
        function getUsers(){
            // XMLHttpRequest
            /*
            $.ajax({
                url: 'http://www.s4.com:8001/users/?callback=bbb',
                type: 'GET',
                success:function(arg){
                    console.log(arg);
                }
            })
            */
            // JSONP
            $.ajax({
                url: 'http://www.s4.com:8001/users/',
                type: 'GET',
                dataType: 'JSONP',
                jsonp: 'callback',
                jsonpCallback: 'bbb'
            })
        }

        function bbb(arg){
            console.log(arg);
        }


    </script>
</body>
</html>
jsonp.html
import json
from django.shortcuts import render,HttpResponse
from django.core.handlers.wsgi import WSGIRequest

from django.views import View

def users(request):
    v = request.GET.get('callback')
    print('请求来了...')
    user_list = [
        'alex','eric','egon'
    ]
    user_list_str = json.dumps(user_list)
    temp = "%s(%s)" %(v,user_list_str,)
    print(temp)
    return HttpResponse(temp)

def new_users(request):
    print(request.method)
    if request.method == "OPTIONS":
        obj = HttpResponse()
        obj['Access-Control-Allow-Origin'] = "*"
        obj['Access-Control-Allow-Methods'] = "DELETE"
        return obj

    obj = HttpResponse('asdfasdf')
    obj['Access-Control-Allow-Origin'] = "*"
    return obj
    # user_list = [
    #     'alex','eric','egon'
    # ]
    # user_list_str = json.dumps(user_list)
    # obj = HttpResponse(user_list_str)
    #
    # obj['Access-Control-Allow-Origin'] = "*"
    # return obj
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <input type="button" value="获取用户列表" οnclick="getUsers();" />
    <ul id="user_list">

    </ul>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        function getUsers(){
            $.ajax({
                url: 'http://www.s4.com:8001/new_users/',
                type:"DELETE",
                success:function(arg){
                    console.log(arg);
                }
            })
        }
    </script>
</body>
</html>
cors.html
<button id="btn_one">点击我向JsonP1发送请求</button>
<script>
    // 测试发送请求失败 跨域不能得到数据
    $('#btn_one').click(function () {
        $.ajax({
            url: "http://127.0.0.1:8000/jsonp1",
            type: "get",
            success: function (response) {
                console.log(response)
            }
        })
    });

    function handlerResponse(response) {
        alert(response)
    };

    window.onload = function () {
        $("#btn_one").click(function () {
            let script_ele = document.createElement("script");
            script_ele.src = "http://127.0.0.1:8000/jsonp1?callback=handlerResponse";
            document.body.insertBefore(script_ele, document.body.firstChild);
        })
    }


</script>
JsonP测试前端代码
class Test(APIView):

    def get(self, request):
        callback = request.query_params.get("callback", "")
        ret = callback + "(" + "'success'" + ")"
        return HttpResponse(ret)
JsonP实现的后端代码

添加响应头

from django.middleware.security import SecurityMiddleware
from django.utils.deprecation import MiddlewareMixin


class MyCors(MiddlewareMixin):

    def process_response(self, request, response):
        response["Access-Control-Allow-Origin"] = "*"
        if request.method == "OPTIONS":
            response["Access-Control-Allow-Methods"] = "PUT, DELETE"
            response["Access-Control-Allow-Headers"] = "content-type"
        return response
middlewares.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'middlewares.MyCors',
]
settings.py
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script>

</head>
<body>
<div id="app">

</div>
<script>
    const app = new Vue({
        el: "#app",
        mounted(){
            axios.request({
                url: "http://127.0.0.1:8000/demo/",
                method: "POST",
                data: {
                    "name": "Alex"
                }
            }).then(function (data) {
                console.log(data)
            })
        }
    })
</script>

</body>
</html>
demo.html

基于cors实现AJAX请求

简单请求 OR 非简单请求
条件:
    1、请求方式:HEAD、GET、POST
    2、请求头信息:
        Accept
        Accept-Language
        Content-Language
        Last-Event-ID
        Content-Type 对应的值是以下三个中的任意一个
                                application/x-www-form-urlencoded
                                multipart/form-data
                                text/plain

注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求


简单请求和非简单请求的区别?
简单请求:一次请求
非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。


关于“预检”
- 请求方式:OPTIONS
- “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
- 如何“预检”
     => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
        Access-Control-Request-Method
     => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
        Access-Control-Request-Headers
cors说明

a、支持跨域,简单请求

服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'

复制代码
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="submit" οnclick="XmlSendRequest();" />
    </p>

    <p>
        <input type="submit" οnclick="JqSendRequest();" />
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                }
            };
            xhr.open('GET', "http://c2.com:8000/test/", true);
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'GET',
                dataType: 'text',
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }


    </script>
</body>
</html>
复制代码
HTML
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        self.write('{"status": true, "data": "seven"}')
Torando

b、支持跨域,复杂请求

由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。

  • “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
  • “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
  • “预检”缓存时间,服务器设置响应头:Access-Control-Max-Age
复制代码
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="submit" οnclick="XmlSendRequest();" />
    </p>

    <p>
        <input type="submit" οnclick="JqSendRequest();" />
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                }
            };
            xhr.open('PUT', "http://c2.com:8000/test/", true);
            xhr.setRequestHeader('k1', 'v1');
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'PUT',
                dataType: 'text',
                headers: {'k1': 'v1'},
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }


    </script>
</body>
</html>
复制代码
HTML
复制代码
class MainHandler(tornado.web.RequestHandler):

    def put(self):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        self.write('{"status": true, "data": "seven"}')

    def options(self, *args, **kwargs):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        self.set_header('Access-Control-Allow-Headers', "k1,k2")
        self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
        self.set_header('Access-Control-Max-Age', 10)
复制代码
Tornado

c、跨域获取响应头

默认获取到的所有响应头只有基本信息,如果想要获取自定义的响应头,则需要再服务器端设置Access-Control-Expose-Headers。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="submit" οnclick="XmlSendRequest();" />
    </p>

    <p>
        <input type="submit" οnclick="JqSendRequest();" />
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                    // 获取响应头
                    console.log(xhr.getAllResponseHeaders());
                }
            };
            xhr.open('PUT', "http://c2.com:8000/test/", true);
            xhr.setRequestHeader('k1', 'v1');
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'PUT',
                dataType: 'text',
                headers: {'k1': 'v1'},
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                    // 获取响应头
                    console.log(xmlHttpRequest.getAllResponseHeaders());
                }
            })
        }


    </script>
</body>
</html>
HTML
class MainHandler(tornado.web.RequestHandler):

    def put(self):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")

        self.set_header('xxoo', "seven")
        self.set_header('bili', "daobidao")

        self.set_header('Access-Control-Expose-Headers', "xxoo,bili")


        self.write('{"status": true, "data": "seven"}')

    def options(self, *args, **kwargs):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        self.set_header('Access-Control-Allow-Headers', "k1,k2")
        self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
        self.set_header('Access-Control-Max-Age', 10)
Tornado

d、跨域传输cookie

在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送。

如果想要发送:

  • 浏览器端:XMLHttpRequest的withCredentials为true
  • 服务器端:Access-Control-Allow-Credentials为true
  • 注意:服务器端响应的 Access-Control-Allow-Origin 不能是通配符 *
复制代码
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="submit" οnclick="XmlSendRequest();" />
    </p>

    <p>
        <input type="submit" οnclick="JqSendRequest();" />
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                }
            };

            xhr.withCredentials = true;

            xhr.open('PUT', "http://c2.com:8000/test/", true);
            xhr.setRequestHeader('k1', 'v1');
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'PUT',
                dataType: 'text',
                headers: {'k1': 'v1'},
                xhrFields:{withCredentials: true},
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }


    </script>
</body>
</html>
复制代码
HTML
复制代码
class MainHandler(tornado.web.RequestHandler):

    def put(self):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        self.set_header('Access-Control-Allow-Credentials', "true")

        self.set_header('xxoo', "seven")
        self.set_header('bili', "daobidao")
        self.set_header('Access-Control-Expose-Headers', "xxoo,bili")

        self.set_cookie('kkkkk', 'vvvvv');

        self.write('{"status": true, "data": "seven"}')

    def options(self, *args, **kwargs):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        self.set_header('Access-Control-Allow-Headers', "k1,k2")
        self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
        self.set_header('Access-Control-Max-Age', 10)
复制代码
Tornado

转载于:https://www.cnblogs.com/bubu99/p/10258454.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值