AJAX全套 & jsonp跨域AJAX

1.1 AJAX介绍

  1、AJAX作用

      1. AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

      2. AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。

      3. AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

  2、AJAX与传统开发模式区别

      ajax开发模式:页面将用户的操作通过ajax引擎与服务器进行通信,将返回的结果给ajax引擎,然后ajax将数据插入指定位置。

      传统的开发模式:用户的每一次操作都触发一次返回服务器的HTTP请求,服务器做出处理后,返回一个html页面给用户。

  3、AJAX请求的三种方法

      1. jQuery Ajax:本质 XMLHttpRequest 或 ActiveXObject

      2. 原生Ajax:主要就是使用 【XmlHttpRequest】对象来完成请求的操作,该对象在主流浏览器中均存在

      3. “伪”AJAX:由于HTML标签的iframe标签具有局部加载内容的特性,所以可以使用其来伪造Ajax请求

1.2 jQuery AJAX(第一种)

  1、JQuery AJAX说明

                  1、jQuery其实就是一个JavaScript的类库,其将复杂的功能做了上层封装,使得开发者可以在其基础上写更少的代码实现更多的功能

                  2、jQuery Ajax本质 XMLHttpRequest 或 ActiveXObject

  2、使用JQuery AJAX发送数据

from django.shortcuts import render,HttpResponse
import json

def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    elif request.method == 'POST':
        print(request.POST)                    #{'name': ['root'], 'pwd': ['123']}
        ret = {'code':True,'data':None}
        return HttpResponse(json.dumps(ret))
views.py视图函数
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="add_form">
        <input type="text" name="user" placeholder="用户名">
        <input type="text" name="pwd" placeholder="密码">
        <span id="jquery_ajax">JQuery Ajax提交</span>
    </form>
    <script src="/static/jquery-1.12.4.js"></script>
    
    <script>
        $('#jquery_ajax').click(function(){
            $.ajax({
                
                url: '/login/',
                // data: {'user': 123,'host_list': [1,2,3,4]},   // 也可以这样穿数据给后台
                data: $('#add_form').serialize(),                //拿到form表单提交的所有内容
                type: "POST",
                dataType: 'JSON',                                // 让JQuery将data先JSON后再发送到后台
                traditional: true,                               //如果发送的是列表告诉JQuery也发送到后台
                
                success: function(data, statusText, xmlHttpRequest){
                    if(data.code == true){
                        console.log('返回登录后的页面');
                    }else {
                        console.log('在页面上添加错误提示信息');
                    }
                },
                
                error: function () {
                    //只有当发送数据,后台没有捕捉到的未知错误才执行error函数
                }
            })
        });
    </script>
</body>
</html>
login.html

    3、JQuery ajax借助FormData上传文件(借助FormData低版本ie不支持)

from django.shortcuts import render,HttpResponse
import json

def upload(request):
    return render(request,'upload.html')

def upload_file(request):
    username = request.POST.get('username')
    fafafa = request.FILES.get('fafafa')
    print(username,fafafa)

    with open(fafafa.name,'wb') as f:
        for item in fafafa.chunks():
            f.write(item)
    ret = {'code':True,'data':request.POST.get('username')}
    return HttpResponse(json.dumps(ret))
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .upload{
            display: inline-block;
            padding: 10px;
            background-color: brown;
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            z-index: 90;
        }
        .file{
            width: 60px;
            height: 30px;
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            z-index: 100;
            opacity: 0;
        }
    </style>
</head>
<body>
    {# 为了让我们的上传图标好看,可以用我们的a标签显示到上传标签的外面 #}
    <div style="position: relative; 60px;height: 40px">
        <input class="file" type="file" id="fafafa" name="afafaf">
        <a class="upload">上传</a>
    </div>
    <input type="button" value="提交jQuery" onclick="fqSubmit();">

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        function fqSubmit(){
            var file_obj = document.getElementById('fafafa').files[0];

            var fd = new FormData();            // FormData对象可以传字符串,也可以传文件对象
            fd.append('username','root');
            fd.append('fafafa',file_obj);
            var xhr = new XMLHttpRequest();

            $.ajax({
                url:'/upload_file/',
                type:'POST',
                data:fd,

                //jquery Ajax上传文件必须执定processData,contentType参数
                processData:false,              //告诉JQuery不要特殊处理这个数据
                contentType:false,              //告诉JQuery不要设置内容格式
                success:function(arg,a1,a2){
                    console.log(111,arg);       //后台返回的数据
                    console.log(222,a1);        //执行状态:sucess(fail)
                    console.log(333,a2);        //对象
                }
            })
        }
    </script>
</body>
</html>
upload.html

  4、当框架加载完成发送ajax发送请求获取数据

        // 当框架加载完成后执行此函数
        window.onload = function(){
            var deptid = $('[name="approvetype"]').val();
           $.ajax({
                url: '{% url "workordermanager:parse_deptid" %}',
                data: {'deptid': deptid},   // 也可以这样穿数据给后台
                type: "get",
                dataType: 'JSON',                                // 让JQuery将data先JSON后再发送到后台
                traditional: true,                               //如果发送的是列表告诉JQuery也发送到后台
                success: function(data, statusText, xmlHttpRequest){
                    if(data.code == true){
                        $('[name="approvetype"]').val(data.data);
                    }else {
                        console.log('在页面上添加错误提示信息');
                    }
                },
                error: function () {
                    //只有当发送数据,后台没有捕捉到的未知错误才执行error函数
                }
            })
        }
当框架加载完成发送ajax获取数据填充页面

1.3 原生ajax(第二种)

  1、原生AJAX说明

      1. 原生Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操作

      2. 该对象在主流浏览器中均存在(除早起的IE),Ajax首次出现IE5.5中存在(ActiveX控件)

  2、XmlHttpRequest对象方法和属性

// 1、void open(String method,String url,Boolen async)
    1)作用:用于创建请求
    2)参数:
        method: 请求方式(字符串类型),如:POST、GET、DELETE...
        url:    要请求的地址(字符串类型)
        async:  是否异步(布尔类型)
        
// 2、void send(String body)
    1)作用:用于发送请求
    2)参数:
            body: 要发送的数据(字符串类型)
            
// 3、void setRequestHeader(String header,String value)
    1)作用:用于设置请求头
    2)参数:
        header: 请求头的key(字符串类型)
        vlaue:  请求头的value(字符串类型)
        
// 4、String getAllResponseHeaders()
    1)作用:获取所有响应头
    2)返回值:
        响应头数据(字符串类型)
        
// 5、String getResponseHeader(String header)
    1)作用:获取响应头中指定header的值
    2)参数:
        header: 响应头的key(字符串类型)
    3)返回值:  响应头中指定的header对应的值
    
// 6、oid abort()
    1)作用:
        终止请求
XmlHttpRequest对象的主要方法
//a. Number readyState
   状态值(整数)
 
   详细:
      0-未初始化,尚未调用open()方法;
      1-启动,调用了open()方法,未调用send()方法;
      2-发送,已经调用了send()方法,未接收到响应;
      3-接收,已经接收到部分响应数据;
      4-完成,已经接收到全部响应数据;
 
//b. Function onreadystatechange
   当readyState的值改变时自动触发执行其对应的函数(回调函数)
 
//c. String responseText
   服务器返回的数据(字符串类型)
 
//d. XmlDocument responseXML
   服务器返回的数据(Xml对象)
 
//e. Number states
   状态码(整数),如:200、404...
 
//f. String statesText
   状态文本(字符串),如:OK、NotFound...
XmlHttpRequest对象的主要属性

   3、使用原生AJAX发送数据(send方法发送)

from django.shortcuts import render,HttpResponse
import json

def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    elif request.method == 'POST':
        print(request.POST)                    #{'name': ['root'], 'pwd': ['123']}
        ret = {'code':True,'data':None}
        return HttpResponse(json.dumps(ret))
views.py视图函数
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <input type="button" value="ajax1" onclick="Ajax1()">

    <script>
        // 使用原生ajax发送数据
        function Ajax1(){
            // var xhr = GetXHR();                              //(浏览器兼容性可以这样创建xhr对象)

            //1 new关键字创建JavaScript的XMLHttpRequest对象xhr
            var xhr = new XMLHttpRequest();                     //创建xhr对象(浏览器兼容性)

            //2 以get方式发数据给ajax_json,true表示支持异步
            xhr.open('POST','/login/',true);                    //open就是xhr对象的方法

            //3 onreadystatechange是:回调函数,当readyState的值改变时自动触发执行其对应的匿名函数
            xhr.onreadystatechange = function(){
              if(xhr.readyState == '4'){                         // 只有状态为4时才执行 表示已经接收完毕
                  var obj = JSON.parse(xhr.responseText);       // xhr.responseText就是服务器端的返回值
                  console.log(obj);                              //获取返回值:{code: true, data: null}
              }
            };

            //4 发送请求头 CSRF中用的就是这个
            xhr.setRequestHeader('k1','v1');

            //5 后台要想获得xhr.send数据,必须在这里设置请求头
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');

            //6 发送的字符串内容
            xhr.send("name=root;pwd=123");
        }


        // 原生ajax兼容ie低版本才使用这个方法创建XMLHttpRequest对象
        function GetXHR(){
            var xhr = null;                   //先设置xhr对象为null
            if(XMLHttpRequest){
                xhr = new XMLHttpRequest();   //如果有XMLHttpRequest就设置
            }else{
                xhr = new ActiveXObject("Microsoft.XMLHTTP"); //没有就设置成微软的
            }
            return xhr;
        }
    </script>
</body>
</html>
login.html

   4、原生ajax借助FormData上传文件(借助FormData低版本ie不支持)

from django.shortcuts import render,HttpResponse
import json

def upload(request):
    return render(request,'upload.html')

def upload_file(request):
    username = request.POST.get('username')
    fafafa = request.FILES.get('fafafa')
    print(username,fafafa)

    with open(fafafa.name,'wb') as f:
        for item in fafafa.chunks():
            f.write(item)
    ret = {'code':True,'data':request.POST.get('username')}
    return HttpResponse(json.dumps(ret))
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .upload{
            display: inline-block;
            padding: 10px;
            background-color: brown;
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            z-index: 90;
        }
        .file{
            width: 60px;
            height: 30px;
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            z-index: 100;
            opacity: 0;
        }
    </style>
</head>
<body>
    {# 为了让我们的上传图标好看,可以用我们的a标签显示到上传标签的外面  #}
    <div style="position: relative; 60px;height: 40px">
        <input class="file" type="file" id="fafafa" name="afafaf">
        <a class="upload">上传</a>
    </div>

    <input type="button" value="提交XHR" onclick="xhrSubmit();">

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        // 原生ajax上传文件
        function xhrSubmit(){
            var file_obj = document.getElementById('fafafa').files[0];
            var fd = new FormData();                    // FormData对象可以传字符串,也可以传文件对象
            fd.append('username','root');
            fd.append('fafafa',file_obj);

            var xhr = new XMLHttpRequest();
            xhr.open('POST','/upload_file/',true);     //open就是xhr对象的方法
            xhr.onreadystatechange = function(){
              if(xhr.readyState == '4'){
                  var obj = JSON.parse(xhr.responseText);
                  console.log(obj);
              }
            };
            xhr.send(fd);
        }
    </script>
</body>
</html>
upload.html

1.4 iframe“伪”AJAX(第三种)

   1、说明 

      1. 由于HTML标签的iframe标签具有局部加载内容的特性,所以可以使用其来伪造Ajax请求。

   2、使用伪AJAX发送数据

from django.shortcuts import render,HttpResponse
import json

def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    elif request.method == 'POST':
        print(request.POST)                    #{'name': ['root'], 'pwd': ['123']}
        ret = {'code':True,'data':None}
        return HttpResponse(json.dumps(ret))
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{#1 target="ifm1 就让form和iframe建立关系,表单就会通过iframe提交数据到后台   #}
{#2 可以给submit绑定一个事件,当点击时才绑定iframeLoad事件 #}
    <form action="/login/" method="POST" target="ifm1">
        <iframe name="ifm1" id="ifm1" style="display: none"></iframe>

        <input type="text" name="username">
        <input type="text" name="email">
        <input type="submit" value="Form提交" onclick="submitForm();">
    </form>

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        //1 使用iframe提交数据,后台返回数据放到iframe中了,需要拿到数据
        //2 只有当点击提"Form提交"才会触发绑定iframe 的load事件
        //3 只有当后台返回数据后,才会自动触发iframe的load事件

        function submitForm(){
            $('#ifm1').load(function(){

                var text = $('#ifm1').contents().find('body').text();  // contents()中就可以获取到后台返回给iframe的内容了
                var obj = JSON.parse(text);                             //将字符串转换成json数据
                console.log(obj)
            })
        }
    </script>
</body>
</html>
login.html

   3、iframe伪ajax上传图片及预览(可以兼容所有浏览器)

from django.shortcuts import render,HttpResponse
import json
import os

def upload_file(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        fafafa = request.FILES.get('fafafa')
        img_path = os.path.join('staticimage',fafafa.name)
        print(img_path)
        with open(img_path,'wb') as f:
            for item in fafafa.chunks():
                f.write(item)
        ret = {'code':True,'data':img_path}
        return HttpResponse(json.dumps(ret))
    return render(request,'upload_file.html')
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/upload_file/" method="POST" target="ifm1" enctype="multipart/form-data">
        <iframe name="ifm1" id="ifm1" style="display: none"></iframe>
        <input type="file" name="fafafa">
        <input type="submit" value="iframe提交" onclick="iframeForm();">
    </form>
    <div id="preview"></div>

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        function iframeForm(){
            $('#ifm1').load(function(){
                var text = $('#ifm1').contents().find('body').text();
                var obj = JSON.parse(text);                      //将字符串转换成json数据
                var imgTag = document.createElement('img');     //创建image标签
                $('#preview').empty();
                imgTag.src='/'+obj.data;                        //上传后图片路径

                $('#preview').append(imgTag);
            })
        }
    </script>
</body>
</html>
法1:upload.html不定义上传按钮样式
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="fm" action="/upload_file/" method="POST" target="ifm1" enctype="multipart/form-data">
        <iframe name="ifm1" id="ifm1" style="display: none"></iframe>
        <input type="file" name="fafafa" onchange="iframeForm();" id="publish_file" style="display: none">
        <a onclick="document.getElementById('publish_file').click();">上传图片</a>
    </form>
    <div id="preview"></div>

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        function iframeForm(){
            $('#ifm1').load(function(){
                var text = $('#ifm1').contents().find('body').text();
                var obj = JSON.parse(text);                      //将字符串转换成json数据
                var imgTag = document.createElement('img');     //创建image标签
                $('#preview').empty();
                imgTag.src='/'+obj.data;                        //上传后图片路径

                $('#preview').append(imgTag);
            });
            
            document.getElementById('fm').submit();
        }
    </script>
</body>
</html>
法2:upload.html自定义上传按钮样式 

1.5 jsonp跨域请求

   1、jsonp跨域请求原理

      1. 由于浏览器存在同源策略机制,同源策略阻止通过js通过浏览器设置另一个源加载的文档的属性。

      2. 比如现在访问 http://127.0.01/index 页面,在index页面中通过js发送请求获取 http://tom.com/login/ 页面的数据会被浏览器阻止

      3. 由于同源策略是浏览器的限制,所以请求的发送和响应是可以进行,只不过浏览器不接受返回来的数据罢了

      4. 浏览器同源策略仅制约XmlHttpRequest,不会制约 img、iframe、script等具有src属性的标签

      5. JSONP(JSON with Padding是JSON的一种“使用模式”),利用script标签的src属性实现jsonp跨域请求

      6. JSONP实质就是通过scrip的src属性向其他域请求数据,这样就可以在网页中获取到远端路径的数据了

  2、实现jsonp跨域请求测试分为以下几步

      1. 首先需要建立第两个Django项目MyNewDay25  和 anotherDomainProject

      2.从MyNewDay25 的Django项目通过AJAX,向  anotherDomainProject项目请求数据

      3.  这里因为在同一台计算机中测试,所以将anotherDomainProject 监听端口改为8001

      4.  为了实现不同域名的效果,修改计算机hosts记录:

        路径: C:WindowsSystem32driversetchosts

        添加: 127.0.0.1       tom.com

        目的:通过 http://tom.com:8001/another_domain_project/?callback=list'  访问anotherDomainProject

   2、MyNewDay25  项目中发送请求给anotherDomainProject获取数据

    1. MyNewDay25代码

        说明:当我们访问MyNewDay25项目的: http://127.0.0.1:8000/get_data/    时就会使用ajax到

                 http://tom.com:8001/another_domain_project/ 获取数据,然后通过console.log打印出来

from django.shortcuts import render,HttpResponse

def get_data(request):
    return render(request,'get_data.html')
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <input type="button" value="获取数据" onclick="getContent();" />

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        function getContent(){
            // 1. 使用原生js的src属性跨域请求数据
            var tag = document.createElement('script');
            tag.src = 'http://tom.com:8001/another_domain_project/?callback=list';
            // tag.src = 'http://www.jxntv.cn/data/jmd-jxtv2.html?calback=list&_=1454376870403';
            document.head.appendChild(tag);
            document.head.removeChild(tag);

            // 2. 使用ajax实现jsonp跨域请求
            $.ajax({
                url: 'http://tom.com:8001/another_domain_project/',
                type: 'POST',
                dataType: 'jsonp',
                // 下面的两句就相当于上面再URL中写:?callback=list
                jsonp: 'callback',
                jsonpCallback: 'list'
            })
        }

        // 3.这个函数就是当数据返回后使用list函数处理:arg就是跨域请求来的数据
        function list(arg){
            console.log(arg);
        }
    </script>
</body>
</html>
get_data.html

    2. anotherDomainProject代码

ALLOWED_HOSTS = ['tom.com','127.0.0.1',]
settings.py
from django.shortcuts import render,HttpResponse

def another_domain_project(request):       # 请求端发送AJAX请求路径:http://tom.com:8001/another_domain_project/?callback=list
    func = request.GET.get('callback')    # 获取请求端回调函数名(这里名字是:list,字符串格式)
    content = '%s(1000000)'%(func)        # 返回给请求端内容:list(1000000), 在请求端就会调用js中的list()函数了
    return HttpResponse(content)
views.py

1.6 在tornado中使用jsonp解决跨域请求

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_header('Access-Control-Allow-Origin', "")
        self.render('get_data.html')

settings = {
    'template_path': 'template',
    'static_path': 'static',
    'static_url_prefix': '/static/',
}

application = tornado.web.Application([
    (r"/get_date", MainHandler),
], **settings)

if __name__ == "__main__":
    application.listen(8000)
    print('http://127.0.0.1:8000/get_date')
    tornado.ioloop.IOLoop.instance().start()
app.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<input type="button" onclick="AjaxRequest()" value="跨域Ajax" />

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

<script src="/static/jquery-1.12.4.js" type="text/javascript"></script>
    <script type="text/javascript">
        function AjaxRequest() {
            $.ajax({      // 下面这个路径是江西卫视界面菜单的json数据
                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>
get_data.html
原文地址:https://www.cnblogs.com/jiaxinzhu/p/12667251.html