Ajax使用

摘要

本文部分内容来源于网络,个人收集整理,请勿传播

https://www.cnblogs.com/wupeiqi/articles/5703697.html

jQuery Ajax

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

  • jQuery不是生产者,而是大自然搬运工。
  • jQuery Ajax本质XMLHttpRequestActiveXObject

注:2.+版本不再支持IE9以下的浏览器

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
jQuery.get(...)
所有参数:
url: 待载入页面的URL地址
data: 待发送 Key/value 参数。
success: 载入成功时回调函数。
dataType: 返回内容格式,xml, json, script, text, html


jQuery.post(...)
所有参数:
url: 待载入页面的URL地址
data: 待发送 Key/value 参数
success: 载入成功时回调函数
dataType: 返回内容格式,xml, json, script, text, html


jQuery.getJSON(...)
所有参数:
url: 待载入页面的URL地址
data: 待发送 Key/value 参数。
success: 载入成功时回调函数。


jQuery.getScript(...)
所有参数:
url: 待载入页面的URL地址
data: 待发送 Key/value 参数。
success: 载入成功时回调函数。


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;
}
},
});

基于jQueryAjax - Demo

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
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>

<p>
<input type="button" onclick="XmlSendRequest();" 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>

iframe伪造ajax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<iframe id="ifm0" src="http://www.baidu.com" frameborder="0"></iframe>
<input type="text" id="url">
<input type="button" value="iframe" onclick="iframeRequest()">
<script>
function iframeRequest() {
var url = $('#url').val();
$('#ifm0').attr('src',url);
}
</script>
########
<form action="/index/" method="POST" target="ifm">
<iframe name="ifm" frameborder="0" onload=""></iframe>
<input type="text" name="username">
<input type="submit" onclick="submitForm()" value="form提交">
</form>
<script>
function submitForm() {
$('#ifm').load(function (){
var data = $('#ifm').contents().find('body').text();
});
}
</script>

跨域AJAX

由于浏览器存在同源策略机制,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。

特别的:由于同源策略是浏览器的限制,所以请求的发送和响应是可以进行,只不过浏览器不接受罢了。

浏览器同源策略并不是对所有的请求均制约:

  • 制约:XmlHttpRequest
  • 允许:img、iframe、script等具有src属性的标签

跨域,跨域名访问,如:http://www.c1.com域名向http://www.c2.com域名发送请求。

JSONP实现跨域请求

浏览器默认是不允许ajax的跨域请求的,但是允许script标签的src属性进行跨域请求。

而利用script标签的src属性来达到跨域请求的模式就叫做JSONPJSONP - JSON with Padding是JSON的一种”使用模式”)

  • 创建script标签
  • src添加远程地址
  • 返回的数据必须是js格式
  • 只能发get请求
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
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<p>
<input type="button" onclick="Jsonp1();" value='提交'/>
</p>
<p>
<input type="button" onclick="Jsonp2();" value='提交'/>
</p>
<script type="text/javascript" src="jquery-1.12.4.js"></script>
<script>
function Jsonp1(){
var tag = document.createElement('script');
tag.src = "http://c2.com:8000/test/?callback=cb";
document.head.appendChild(tag);
document.head.removeChild(tag);

}

function cb(arg) {
// 需要后端view返回js代码
alert(arg);
}

function Jsonp2(){
$.ajax({
url: "http://c2.com:8000/test/",
type: 'GET',
dataType: 'JSONP',
jsonp: 'callback',
jsonpCallback: 'list',
success: function(data, statusText, xmlHttpRequest){
console.log(data);
}
})
}
</script>
</body>
</html>

CORS

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

简单请求 OR 非简单请求

  • 条件
    • 请求方式:HEAD、GET、POST
    • 请求头信息
      • 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实现AJAX请求

支持跨域,简单请求

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

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
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>

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

<p>
<input type="submit" onclick="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>
1
2
3
4
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"}')

支持跨域,复杂请求

  • 由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。
    • “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
    • “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
    • “预检”缓存时间,服务器设置响应头:Access-Control-Max-Age
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
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>

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

<p>
<input type="submit" onclick="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>

Tornado

1
2
3
4
5
6
7
8
9
10
11
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)

跨域获取响应头

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

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
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>

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

<p>
<input type="submit" onclick="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>

Tornado

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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)

跨域传输cookie

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

  • 如果想要发送:
    • 浏览器端:XMLHttpRequestwithCredentialstrue`
    • 服务器端:Access-Control-Allow-Credentialstrue
    • 注意:服务器端响应的Access-Control-Allow-Origin不能是通配符 *
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
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>

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

<p>
<input type="submit" onclick="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>

Tornado

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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)

文件上传

选择的使用的时机

  • 如果发送的普通数据 -> jquery、XMLHttpRequest、iframe
  • 文件