Ajax
1. Ajax简介
AJAX,Asynchronous JavaScript and XML (异步的JavaScript和XML),即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)。
-
异步的JavaScript:
使用 【JavaScript语言】 以及 相关【浏览器提供类库】 的功能向服务端发送请求,当服务端处理完请求之后,【自动执行某个JavaScript的回调函数】。
PS:以上请求和响应的整个过程是【偷偷】进行的,页面上无任何感知(浏览器页面局部刷新)。 -
XML:
XML是一种标记语言,是Ajax在和后台交互时传输数据的格式之一
特点:
- Ajax使用JavaScript技术向服务器发送异步请求
- Ajax无须刷新整个页面
利用AJAX可以做:
1. 注册时,输入用户名自动检测用户是否已经存在。
2. 登陆时,提示用户名密码错误
3. 删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行也删除。(博客园)
2. '伪Ajax'
iframe 标签具有局部加载内容的特性
- <!--filename: fake_ajax.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>
- </head>
- <body>
- <form id="f1" action="/fake_ajax/" method="post" target="ifr">
- <!--target 表示使用 iframe的上传方式 不使用form的上传方式-->
- <iframe id="ifr" name="ifr" style="display: none"></iframe>
- <input type="text" name="username">
- <a onclick="submitForm()">提交</a>
- </form>
- <script>
- function submitForm() {
- // loadFrame 函数在 iframe有返回值并加载完后执行
- document.getElementById('ifr').onload = loadFrame;
- document.getElementById('f1').submit();
- }
- function loadFrame() {
- // 获取iframe中内容
- var content = document.getElementById('ifr').contentWindow.document.body.innerText;
- alert(content)
- }
- </script>
- </body>
- </html>
3. 原生Ajax
3.1 XMLHTTPRequest对象介绍
-
XmlHttpRequest对象的主要方法:
- 1. void open(String method,String url,Boolen async)
- 用于创建请求
- 参数:
- method: 请求方式(字符串类型),如:POST、GET、DELETE...
- url: 要请求的地址(字符串类型)
- async: 是否异步(布尔类型)
- 2. void send(String body)
- 用于发送请求
- 参数:
- body: 要发送的数据(字符串类型)
- 3. void setRequestHeader(String header,String value)
- 用于设置请求头
- 参数:
- header: 请求头的key(字符串类型)
- vlaue: 请求头的value(字符串类型)
- 4. String getAllResponseHeaders()
- 获取所有响应头
- 返回值:
- 响应头数据(字符串类型)
- 5. String getResponseHeader(String header)
- 获取响应头中指定header的值
- 参数:
- header: 响应头的key(字符串类型)
- 返回值:
- 响应头中指定的header对应的值
- 6. void abort()
- 终止请求
-
XmlHttpRequest对象的主要属性:
- 1. Number readyState
- 状态值(整数)
- 详细:
- 0-未初始化,尚未调用open()方法;
- 1-启动,调用了open()方法,未调用send()方法;
- 2-发送,已经调用了send()方法,未接收到响应;
- 3-接收,已经接收到部分响应数据;
- 4-完成,已经接收到全部响应数据;
- 2. Function onreadystatechange
- 当readyState的值改变时自动触发执行其对应的函数(回调函数)
- 3. String responseText
- 服务器返回的数据(字符串类型)
- 4. XmlDocument responseXML
- 服务器返回的数据(Xml对象)
- 5. Number states
- 状态码(整数),如:200、404...
- 6. String statesText
- 状态文本(字符串),如:OK、NotFound...
3.2 XMLHTTPRequest使用示例代码
- <html>
- <head lang="en">
- <meta charset="UTF-8">
- <title></title>
- </head>
- <body>
- <h1>XMLHttpRequest - Ajax请求</h1>
- <input type="button" onclick="XmlGetRequest();" value="Get发送请求" />
- <input type="button" onclick="XmlPostRequest();" value="Post发送请求" />
- <script src="/statics/jquery-1.12.4.js"></script>
- <script type="text/javascript">
- function GetXHR(){
- var xhr = null;
- if(XMLHttpRequest){
- xhr = new XMLHttpRequest();
- }else{
- xhr = new ActiveXObject("Microsoft.XMLHTTP");
- }
- return xhr;
- }
- function XhrPostRequest(){
- var xhr = GetXHR();
- // 定义回调函数
- xhr.onreadystatechange = function(){
- if(xhr.readyState == 4){
- // 已经接收到全部响应数据,执行以下操作
- var data = xhr.responseText;
- console.log(data);
- }
- };
- // 指定连接方式和地址----文件方式
- xhr.open('POST', "/test/", true);
- // 设置请求头
- // 注意: 如果不设置请求头, request.body中会有数据, 但是Django不会解析, 所以request.post 中没有数据
- xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
- // 发送请求
- xhr.send('n1=1;n2=2;');
- }
- function XhrGetRequest(){
- var xhr = GetXHR();
- // 定义回调函数
- xhr.onreadystatechange = function(){
- if(xhr.readyState == 4){
- // 已经接收到全部响应数据,执行以下操作
- var data = xhr.responseText;
- console.log(data);
- }
- };
- // 指定连接方式和地址----文件方式
- xhr.open('get', "/test/", true);
- // 发送请求
- xhr.send();
- }
- </script>
- </body>
- </html>
- 基于原生AJAX - Demo
4. jQuery Ajax
- jQuery其实就是一个JavaScript的类库,其将复杂的功能做了上层封装,使得开发者可以在其基础上写更少的代码实现更多的功能
- jQuery Ajax本质 XMLHttpRequest 或 ActiveXObject
4.1 jQuery Ajax方法列表
- 1. jQuery.get(...)
- 所有参数:
- url: 待载入页面的URL地址
- data: 待发送 Key/value 参数。
- success: 载入成功时回调函数。
- dataType: 返回内容格式,xml, json, script, text, html
- 2. jQuery.post(...)
- 所有参数:
- url: 待载入页面的URL地址
- data: 待发送 Key/value 参数
- success: 载入成功时回调函数
- dataType: 返回内容格式,xml, json, script, text, html
- 3. jQuery.getJSON(...)
- 所有参数:
- url: 待载入页面的URL地址
- data: 待发送 Key/value 参数。
- success: 载入成功时回调函数。
- 4. jQuery.getScript(...)
- 所有参数:
- url: 待载入页面的URL地址
- data: 待发送 Key/value 参数。
- success: 载入成功时回调函数。
- 5. jQuery.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 格式
- # 使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数
- # 如果不指定,jQuery 将自动根据HTTP包MIME信息返回相应类型(an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string
- converters: 转换器,将服务器端的内容根据指定的dataType转换类型,并传值给success回调函数
- $.ajax({
- accepts: {
- mycustomtype: 'application/x-some-custom-type'
- },
- // Expect a `mycustomtype` back from server
- dataType: 'mycustomtype'
- // Instructions for how to deserialize a `mycustomtype`
- converters: {
- 'text mycustomtype': function(result) {
- // Do Stuff
- return newresult;
- }
- },
- });
4.2 jQuery Ajax使用示例代码
- <html>
- <head lang="en">
- <meta charset="UTF-8">
- <title></title>
- </head>
- <body>
- <p>
- <input type="button" onclick="JqSendRequest();" value='Ajax请求' />
- </p>
- <script type="text/javascript" src="jquery-1.12.4.js"></script>
- <script>
- function JqSendRequest(){
- $.ajax({
- url: "http://c2.com:8000/test/",
- type: 'GET',
- dataType: 'text',
- success: function(data, statusText, xmlHttpRequest){
- console.log(data);
- }
- })
- }
- </script>
- </body>
- </html>
- 基于jQueryAjax - Demo
5. 跨域Ajax
同源策略:
- 存在于浏览器,阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。
- 同源策略是浏览器的限制,所以请求的发送和响应是可以进行,只不过浏览器不接受
- 浏览器同源策略并不是对所有的请求均制约:
- 制约: XmlHttpRequest
- 允许: img、iframe、script等具有src属性的标签
- 跨域:跨域名访问,如:http://www.c1.com 域名向 http://www.c2.com 域名发送请求。
5.1 JSONP
JSONP(JSONP - JSON with Padding是JSON的一种“使用模式”),利用script标签的src属性(浏览器允许script标签跨域)
- 实现机制
- script标签会将src后的路径内容导入到本地内存中
- 若导入函数则会执行
- 示例代码
-
后台代码
- def users(request):
- # callback 为回调函数名
- data = request.GET.get('callback')
- user_list = [
- 'alex', 'egon', 'lex',
- ]
- user_list_str = json.dumps(user_list)
- temp = '%s(%s)' % (data, user_list_str)
- return HttpResponse(temp)
-
自定义 动态创建script标签
- <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="/static/common.js"></script>
- </head>
- <body>
- <input type="button" value="获取用户列表" onclick="getUser()">
- <script src="/static/jquery-3.3.1.js"></script>
- <script>
- function getUser() {
- var tag = document.createElement('script');
- tag.src = 'http://www.ly80.com:8001/users/?callback=bbb';
- // 动态生成 删除
- document.head.appendChild(tag);
- document.head.removeChild(tag);
- }
- // 回调函数
- function bbb(args) {
- console.log(args)
- }
- </script>
- </body>
- </html>
-
通过jQuery实现
- <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="/static/common.js"></script>
- </head>
- <body>
- <input type="button" value="获取用户列表" onclick="getUser()">
- <ul id="u1">
- </ul>
- <script src="/static/jquery-3.3.1.js"></script>
- <script>
- function getUser(){
- $.ajax({
- url: 'http://www.ly80.com:8001/users/',
- type: 'GET',
- // 如果不定义datatype 默认通过xmlhttpresponse发送数据
- dataType: 'JSONP',
- jsonp: 'callback',
- jsonpCallback: 'bbb',
- })
- }
- // 回调函数
- function bbb(args) {
- console.log(args)
- }
- </script>
- </body>
- </html>
-
- 注意:
- jsonp只能发送get请求
- 需要客户端与服务端进行约定
5.2 CORS
浏览器支持主动设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。
- 简单请求&复杂请求
- 相关定义
- 条件:
- 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
- 注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求
- 区别
- 1. 简单请求:一次请求
- 2. 非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。
- 关于'预检'
- - 请求方式:OPTIONS
- - “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
- - 如何“预检”
- - 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
- Access-Control-Request-Method
- - 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
- Access-Control-Request-Headers
- 相关定义
- 基于cors实现Ajax请求
-
跨域简单请求
服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'- 服务器
- def new_users(request):
- obj = HttpResponse('返回内容')
- obj['Access-Control-Allow-Origin'] = "*"
- return obj
- 客户端HTML
Ajax或XMLHTTPRequest正常访问
- 服务器
-
跨域复杂请求
由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。- “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
- “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
- “预检”缓存时间,服务器设置响应头:Access-Control-Max-Age
- def new_users(request):
- # options为预检请求,不会发送请求数据
- # 将返回值进行校验,如果正确将发送真正数据
- 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
-
注意: cors适用于任何请求
-