Ajax

一、准备知识

什么是json?

JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。
它基于ECMAScript(w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

合格的json对象:

["one", "two", "three"]
{"one": 1, "two": 2, "three": 3}
{"names": ["张三", "李四"] }
[{ "name": "张三"}, {"name": "李四"}]

不合格的json对象:

{ name: "张三", 'age': 32 }  # 属性名必须使用双引号
[32, 64, 128, 0xFFF]  # 不能使用十六进制值
{ "name": "张三", "age": undefined }  # 不能使用undefined
{ "name": "张三",
  "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
  "getName":  function() {return this.name;}  # 不能使用函数和日期对象
}

stringify与parse方法

JavaScript中关于JSON对象和字符串转换的两个方法:

JSON.parse():用于将一个 JSON 字符串转换为 JavaScript 对象

JSON.parse('{"name":"pd"}');
JSON.parse('{name:"pd"}');  # 错误
JSON.parse('[18,undefined]');  # 错误

JSON.stringify():用于将 JavaScript 值转换为 JSON 字符串

JSON.stringify({"name":"pd"})

二、Ajax简介

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

AJAX除了异步的特点外,还有一个就是:浏览器页面局部刷新;(这一特点给用户的感受就是在不知不觉中完成了请求和响应过程)

优点:

  • AJAX使用Javascript技术向服务器发送异步请求
  • AJAX无须刷新整个页面
  • 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高

jQuery实现Ajax示例:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>ajax_demo</title>
    <script type="text/javascript" src="/static/jquery-3.3.1.min.js"></script>
</head>
<body>

<input type="text" id="i1">+
<input type="text" id="i2">=
<input type="text" id="i3">
<button type="button" id="btn">提交</button>

<script>
    $("#btn").click(function () {
        var i1 = $("#i1").val();
        var i2 = $("#i2").val();
        $.ajax({
            url:"/ajax_add/",
            type: "GET",
            data: {"i1": i1, "i2": i2},
            success:function (ret) {
                $("#i3").val(ret)
            }
        })
    })
</script>
</body>
</html>
ajax_demo.html
def ajax_demo(request):
    return render(request, "ajax_demo.html")


def ajax_add(request):
    i1 = request.GET.get("i1")
    i2 = request.GET.get("i2")
    ret = int(i1) + int(i2)
    return HttpResponse(ret)
views.py
url(r"^ajax_demo/$", views.ajax_demo),
url(r"^ajax_add/$", views.ajax_add),
urls.py

三、jQuery实现Ajax

<button class="send_Ajax">send_Ajax</button>

<script>
    $(".send_Ajax").click(function () {
        $.ajax({
            url: "/test/",
            type: "POST",
            data: {username: "pd", password: 123},

            // -------- success --------
            success: function (data) {
                alert(data)
            },

            // -------- error --------
            error: function (jqXHR, textStatus, err) {
                // jqXHR: jQuery增强的xhr
                // textStatus: 请求完成状态
                // err: 底层通过throw抛出的异常对象,值与错误类型有关
                console.log(arguments);
            },

            // -------- complete --------
            complete: function (jqXHR, textStatus) {
                // jqXHR: jQuery增强的xhr
                // textStatus: 请求完成状态 success | error
                console.log('statusCode: %d, statusText: %s', jqXHR.status, jqXHR.statusText);
                console.log('textStatus: %s', textStatus);
            },

            // -------- statusCode --------
            statusCode: {
                "403": function (jqXHR, textStatus, err) {
                    console.log(arguments);  // 注意:后端模拟error方式:HttpResponse.status_code=500
                },
                "400": function () {
                }
            }
        })
    })
</script>

data参数中的键值对,如果值不为字符串,则需要将其装换成字符串类型;如:"lst": JSON.stringify([1, 2, 3])

$.ajax(...)
        url:请求地址
       type:请求方式,GET、POST(1.9.0之后用 method)
    headers:请求头
       data:要发送的数据
contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
      async:是否异步
    timeout:设置请求超时时间(毫秒)

 beforeSend:发送请求前执行的函数(全局)
   complete:完成之后执行的回调函数(全局)
    success:成功之后执行的回调函数(全局)
      error:失败之后执行的回调函数(全局)
    
    accepts:通过请求头发送给服务器,告诉服务器当前客户端课接受的数据类型
   dataType:将服务器端返回的数据转换成指定类型
           "xml": 将服务器端返回的内容转换成xml格式
          "text": 将服务器端返回的内容转换成普通文本格式
          "html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
        "script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
          "json": 将服务器端返回的内容转换成相应的JavaScript对象
         "jsonp": JSONP格式
 converters: 转换器,将服务器端的内容根据指定的dataType转换类型,并传值给success回调函数

请求参数

contentType:    默认为"application/x-www-form-urlencoded";代表发送信息至服务器时内容编码类型。
                 用来指明当前请求的数据编码格式;urlencoded:?a=1&b=2;
                 如果想以其他方式提交数据,比如contentType: "application/json",即向服务器发送一个json字符串:
                    <button class="send_Ajax">send_Ajax</button>
                    <script>
                        $(".send_Ajax").click(function () {
                            $.ajax({
                                url: "/test/",
                                type: "post",
                                contentType: "application/json",
                                data: JSON.stringify({a: 11, b: 22}),
                                success:function (data) {
                                    alert(data)
                                }
                            })
                        })
                    </script>
                 注意:contentType: "application/json"一旦设定,data必须是json字符串,不能是json对象。

响应参数

dataType:  预期服务器返回的数据类型,服务器端返回的数据会根据这个值解析后,传递给回调函数。
            默认不需要显性指定这个属性,ajax会根据服务器返回的content Type来进行转换;
            比如我们的服务器响应的content Type为json格式,这时ajax方法就会对响应的内容进
               行一个json格式的转换,如果转换成功,我们在success的回调函数里就会得到一个json
               格式的对象;转换失败就会触发error这个回调函数。如果我们明确地指定目标类型,就可
               以使用dataType。

            dataType的可用值:xml、text、html、script、json、jsonp

四、Ajax请求设置csrf_token

通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。

<script>
    $("#btn").click(function () {
        var i1 = $("#i1").val();
        var i2 = $("#i2").val();
        $.ajax({
            url:"/ajax_add/",
            type: "POST",
            data: {"i1": i1, "i2": i2, "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val()},
            success:function (ret) {
                $("#i3").val(ret)
            }
        })
    })
</script>

五、Ajax上传文件

XMLHttpRequest 是一个浏览器接口,通过它,我们可以使得 Javascript 进行 HTTP(S) 通信。XMLHttpRequest 在现在浏览器中是一种常用的前后台交互数据的方式。2008年 2 月,XMLHttpRequest Level 2 草案提出来了,相对于上一代,它有一些新的特性,其中 FormData 就是 XMLHttpRequest Level 2 新增的一个对象,利用它来提交表单、模拟表单提交,当然最大的优势就是可以上传二进制文件。下面就具体介绍一下如何利用 FormData 来上传文件。

formData的基本用法:FormData对象,可以把所有表单元素的name与value组成一个queryString,提交到后台。只需要把 form 表单作为参数传入 FormData 构造函数即可:

# 上传文件示例
$("#b3").click(function () {
    var formData = new FormData();
    formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
    formData.append("f1", $("#f1")[0].files[0]);
    $.ajax({
        url: "/upload/",
        type: "POST",
        processData: false,  # 告诉jQuery不要去处理发送的数据
        contentType: false,  # 告诉jQuery不要去设置Content-Type请求头
        data: formData,
        success:function (data) {
            console.log(data)
        }
    })
})

注意:由于 FormData 是 XMLHttpRequest Level 2 新增的接口,现在 低于IE10 的IE浏览器不支持 FormData。

六、jQuery.serialize()

serialize()函数用于序列化一组表单元素,将表单内容编码为用于提交的字符串。

serialize()函数常用于将表单内容序列化,以便用于AJAX提交。

该函数不会序列化不需要提交的表单控件,这和常规的表单提交行为是一致的。例如:不在<form>标签内的表单控件不会被提交、没有name属性的表单控件不会被提交、带有disabled属性的表单控件不会被提交、没有被选中的表单控件不会被提交。

与常规表单提交不一样的是:常规表单一般会提交带有name的按钮控件,而serialize()函数不会序列化带有name的按钮控件。
<form action="" id="id_form">
    {% csrf_token %}
    <p><input type="text" name="username" id="id_username" placeholder="账号"></p>
    <p><input type="password" name="password" id="id_password" placeholder="密码"></p>
    <p><button type="button" id="id_login">登录</button></p>
</form>
<script src="/static/jquery-3.3.1.min.js"></script>
<script>
    $("#id_login").click(function () {
        $.ajax({
            url:"/ajax/",
            type: "post",
            data: $("#id_form").serialize(),
            dataType: "json",
            success:function (arg) {
                if (arg=="1"){
                    location.href="http://www.sogo.com"
                }else {
                    alert(arg)
                }
            }
        })
    })
</script>

七、JSONP

jsonp是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。

下面的示例为:jQuery对JSONP的实现

假设项目 jsonp_test1 的某个页面向项目 jsonp_test2 的某个路径请求数据。

jsonp_test1

#jsonp_test1/urls.py

from django.conf.urls import url
from appxx import views

urlpatterns = [
    url(r"^$", views.index)
]
#jsonp_test1/views.py

from django.shortcuts import render

def index(request):
    return render(request, "index.html")
#jsonp_test1/index.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>INDEX</title>
    <script type="text/javascript" src="/static/js/jquery-3.3.1.min.js"></script>
</head>
<body>
<h3>INDEX页面</h3>
<button id="id_btn">跨域ajax</button>
</body>
<script>
    $("#id_btn").click(function () {
        $.ajax({
            url: "http://127.0.0.1:8888/jsonp_ajax/",   // 请求数据的路径
            type: "get",                // 注意jsonp一定是get请求
            dataType: "jsonp",          // 必须有,告诉server,这次访问要的是一个jsonp的结果
            jsonp: "callbacks",         // jQuery帮助随机生成的:callbacks="......"
            success:function (data) {
                console.log(data)
            }
        })
    })
</script>
</html>

jsonp_test2

#jsonp_test2/urls.py

from django.conf.urls import url
from appxx import views

urlpatterns = [
    url(r"^jsonp_ajax/", views.jsonp_ajax)
]
#jsonp_test2/views.py

from django.shortcuts import HttpResponse
import json

def jsonp_ajax(request):
    func = request.GET.get("callbacks")
    data = {"title": "python", "price": 100, "author": "pd"}
    return HttpResponse("{}({})".format(func, json.dumps(data)))

jsonp实际应用示例

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>INDEX</title>
    <script type="text/javascript" src="/static/js/jquery-3.3.1.min.js"></script>
</head>
<body>

<h3>INDEX页面</h3>
<button id="id_btn">跨域ajax</button>
<div id="content"></div>

</body>
<script>
    $("#id_btn").click(function () {
        $.ajax({
            url: "http://www.jxntv.cn/data/jmd-jxtv2.html",
            type: "get",
            dataType: "jsonp",
            jsonp: "callbacks",
            jsonpCallback: 'list',
            success:function (data) {
                console.log(data.data);
                $.each(data.data, function (index1, items) {
                    var html = "";
                    html += '<h3>'+items.week+'</h3>';
                    $.each(items.list, function (index2, show) {
                        html += '<p><a href='+show.link+'>'+show.name+'</a></p>';
                    });
                    $("#content").append(html);
                })
            }
        })
    })
</script>
</html>

八、CORS

#jsonp_test1/index.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>INDEX</title>
    <script type="text/javascript" src="/static/js/jquery-3.3.1.min.js"></script>
</head>
<body>

<h3>INDEX页面</h3>
<button id="id_btn">跨域ajax</button>
<div id="content"></div>

</body>
<script>
    $("#id_btn").click(function () {
        $.ajax({
            url: "http://127.0.0.1:8888/jsonp_ajax/",
            success:function (data) {
                 console.log(JSON.parse(data))
             }
        })
    })
</script>
</html>
#jsonp_test2/views.py

from django.shortcuts import HttpResponse
import json

def jsonp_ajax(request):
    data = {"title": "python", "price": 100, "author": "pd"}
    response = HttpResponse(json.dumps(data))
    response["Access-Control-Allow-Origin"] = "http://127.0.0.1:8000"
    # response["Access-Control-Allow-Origin"] = "*"
    return response

一、简介

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

二、两种请求

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

只要同时满足以下两大条件,就属于简单请求。

(1) 请求方法是以下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出以下几种字段:
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

支持跨域,简单请求

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

# 允许你的域名来获取我的数据
response["Access-Control-Allow-Origin"] = "http://127.0.0.1:8080"

支持跨域,复杂请求

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

  • "预检"请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
# 允许你发送PUT、DELETE请求
response["Access-Control-Request-Method"] = "PUT,DELETE"
  • "预检"请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
# 允许你携带Content-Type请求头
response["Access-Control-Request-Headers"] = "Content-Type"
原文地址:https://www.cnblogs.com/believepd/p/9920537.html