一、准备知识
什么是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示例:
ajax_demo.html
<!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>urls.py
url(r"^ajax_demo/$", views.ajax_demo), url(r"^ajax_add/$", views.ajax_add),
三、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"