Ajax简介
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
- 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
- AJAX局部刷新
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
|
<script>
//.shadow{position: fixed;left: 0;top: 0;right: 0;bottom: 0;background-color: black;opacity: 0.4;z-index: 999;}
$(
"#m_add_ok"
).click(
function
(){
$.ajax({
url:
'/m_user_add/'
,
// 要提交的地址
type:
'POST'
,
// GET或POST,提交方式
//dataType:'JSON',
data: {
// 提交的数据
'name'
: $(
"#m_add_box input[name='name']"
).val(),
'gender'
:$(
"#m_add_box input[name='gender']:checked"
).val(),
'email'
:$(
"#m_add_box input[name='email']"
).val(),
'depart_id'
:$(
"#m_add_box select[name='depart_id']"
).val()
},
success:
function
(data){
// 当服务端处理完成后,返回数据时,该函数自动调用
// data=服务端返回的值 默认是字符串
// console.log(data);
// JSON.parse(字符串) => 对象
// JSON.stringify(对象) => 字符串
var
data=JSON.parse(data)
//如果上面写了dataType:'JSON' 就相当于把success函数的参数data字符串转化成json对象,这就不需要写了json.parse(data)
if
(data.status){
location.reload();
// location.href='/user_list/';
}
else
{
$(
'#titlemsg'
).text(data.titlemsg);
}
}
})
});
</script>
|
一、jQuery.ajax()
1、请求参数
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
|
######################------------data---------################
data: 当前ajax请求要携带的数据,是一个json的
object
对象,ajax方法就会默认地把它编码成某种格式
(urlencoded:?a
=
1
&b
=
2
)发送给服务端;此外,ajax默认以get方式发送请求。
function testData() {
$.ajax(
"/test"
,{
/
/
此时的data是一个json形式的对象
data:{
a:
1
,
b:
2
}
});
/
/
?a
=
1
&b
=
2
######################------------processData---------################
processData:声明当前的data数据是否进行转码或预处理,默认为true,即预处理;
if
为false,
那么对data:{a:
1
,b:
2
}会调用json对象的toString()方法,即{a:
1
,b:
2
}.toString()
,最后得到一个[
object
,
Object
]形式的结果。
######################------------contentType---------################
contentType:默认值:
"application/x-www-form-urlencoded"
。发送信息至服务器时内容编码类型。
用来指明当前请求的数据编码格式;urlencoded:?a
=
1
&b
=
2
;如果想以其他方式提交数据,
比如contentType:
"application/json"
,即向服务器发送一个json字符串:
$.ajax(
"/ajax_get"
,{
data:JSON.stringify({
a:
22
,
b:
33
}),
contentType:
"application/json"
,
type
:
"POST"
,
});
/
/
{a:
22
, b:
33
}
注意:contentType:
"application/json"
一旦设定,data必须是json字符串,不能是json对象
views.py: json.loads(request.body.decode(
"utf8"
))
######################------------traditional---------################
traditional:一般是我们的data数据有数组时会用到 :data:{a:
22
,b:
33
,c:[
"x"
,
"y"
]},
traditional为false会对数据进行深层次迭代;
|
2、响应参数
1
2
3
4
5
6
7
8
9
10
11
12
|
/*
dataType: 预期服务器返回的数据类型,服务器端返回的数据会根据这个值解析后,传递给回调函数。
默认不需要显性指定这个属性,ajax会根据服务器返回的content Type来进行转换;
比如我们的服务器响应的content Type为json格式,这时ajax方法就会对响应的内容
进行一个json格式的转换,if转换成功,我们在success的回调函数里就会得到一个json格式
的对象;转换失败就会触发error这个回调函数。如果我们明确地指定目标类型,就可以使用
data Type。
dataType的可用值:html|xml|json|text|script
见下dataType实例
*/
|
二、jQuery.serialize()
该函数主要根据用于提交的有效表单控件的name和value,将它们拼接为一个可直接用于表单提交的文本字符串,该字符串已经过标准的URL编码处理(字符集编码为UTF-8)。
- jQuery 1.0 新增该函数。语法:jQueryObject.serialize()
- 返回值:serialize()函数的返回值为String类型,返回将表单元素编码后的可用于表单提交的文本字符串。
- 不在标签内的、没有name属性的、带有disabled属性的、没有被选中的表单控件不会被提交。
- serialize()函数通常用于将表单内容序列化,以便通过AJAX方式提交。
- serialize()函数用于序列化所有表单元素。$("form").serialize()
- serialize()函数用于序列化部分表单元素。$(":text, select, :checkbox").serialize()
def ajax_login(request):
if request.method == 'GET':
return render(request, 'login.html')
else:
import json
ret = {'status': True,'msg': None}
obj = LoginForm(request.POST)
if obj.is_valid():
print(obj.cleaned_data)
else:
# print(obj.errors) # obj.errors对象
ret['status'] = False
ret['msg'] = obj.errors
v = json.dumps(ret)
return HttpResponse(v)
<body>
<h1>用户登录</h1>
<form id="f1" >
{% csrf_token %}
<p>
<input type="text" name="user" />
</p>
<p>
<input type="password" name="pwd" />
</p>
<a οnclick="submitForm();">提交</a>
</form>
<script src="/static/jquery-1.12.4.js"></script>
<script>
function submitForm(){
$('.c1').remove();
$.ajax({
url: '/ajax_login/',
type: 'POST',
data: $('#f1').serialize(),// user=alex&pwd=456&csrftoen=dfdf\
dataType:"JSON",
success:function(arg){
console.log(arg);
if(arg.status){
}else{
$.each(arg.msg,function(index,value){
console.log(index,value);
var tag = document.createElement('span');
tag.innerHTML = value[0];
tag.className = 'c1';
$('#f1').find('input[name="'+ index +'"]').after(tag);
})
}
}
})
}
</script>
</body>
csrf跨站请求伪造
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
|
<body>
<!--
{% csrf_token %} 生成input框
{{ csrf_token }} 生成随机字符串
-->
<form method=
"POST"
action=
"/csrf1.html"
>
{% csrf_token %}
<input id=
"user"
type=
"text"
name=
"user"
/>
<input type=
"submit"
value=
"提交"
/>
<a id=
"a_sub"
>Ajax提交</a>
</form>
<script src=
"/static/jquery-1.12.4.js"
></script>
<script>
$(
"#a_sub"
).click(
function
(){
var
user = $(
'#user'
).val();
$.ajax({
url:
'/csrf1.html'
,
type:
'POST'
,
//方式1:
data: {
"user"
:user,
'csrfmiddlewaretoken'
: $(
"[name='csrfmiddlewaretoken']"
).val()},
//方式2:
// data: { "user":user,'csrfmiddlewaretoken': '{{ csrf_token }}'},
success:
function
(arg){
console.log(arg);
}
})
});
</script>
<script src=
"/static/jquery.cookie.js"
></script>
<script>
$(
"#a_sub"
).click(
function
(){
var
user = $(
'#user'
).val();
$.ajax({
url:
'/csrf1.html'
,
//方式3:放在请求头中
headers:{
'X-CSRFToken'
: $.cookie(
'csrftoken'
)},
type:
'POST'
,
data: {
"user"
:user},
success:
function
(arg){
console.log(arg);
}
})
});
</script>
</body>
|
stringify与parse方法
1
2
3
4
5
6
7
8
|
JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象
eg:
console.log(JSON.parse(
'{"name":"tom"}'
));
console.log(JSON.parse(
'{name:"tom"}'
)) ;
// 错误
console.log(JSON.parse(
'[12,undefined]'
)) ;
// 错误
JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串。
eg: console.log(JSON.stringify({
'name'
:
"tom"
}));
|
上传文件
一、Ajax(FormData)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
.avatar_con {
height: 100px;
width: 100px;
position: relative;
}
.avatar_con iframe {
display: none
}
.avatar_con img {
height: 100%;
width: 100%;
border: 0;
overflow: hidden;
max-height: 100px;
}
.avatar_con #previewImg {
border-radius: 50%;
border: 1px solid #dddddd;
padding: 3px;
height: 96px;
width: 96px;
}
.avatar_con #avatarImg {
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
position: absolute;
z-index: 102;
}
.avatar-avatar_con .text {
position: absolute;
left: 0;
bottom: 0;
text-align: center;
}
</style>
<body>
<h1>jQuery Ajax上传文件</h1>
<div class="avatar_con">
<label for="avatar">
<img id="previewImg" src="/media/avatar/default.png">
<div class="text">点击图片更换</div>
</label>
<input id="avatarImg" name="avatar" type="file"/>
</div>
<script src="http://code.jquery.com/jquery-1.12.3.min.js"></script>
<script type="text/javascript">
$(function () {
bindChangeAvatar();
});
// ajax上传文件
function bindChangeAvatar() {
$('#avatarImg').change(function () {
/*
// 头像预览 方法1:
// 获取用户选中的文件对象
var file_obj = $(this)[0].files[0];
// 获取文件对象的路径
var reader = new FileReader();
reader.readAsDataURL(file_obj);
// 修改img的src属性 ,src=文件对象的路径
reader.onload = function () {
$("#previewImg").attr("src", reader.result)
};
*/
/* 本地上传预览 方法2:
var obj = $(this)[0].files[0];
// Ajax发送后台,并获取路径
// img.src = 获取路径
var v = window.URL.createObjectURL(obj);
$('#previewImg').attr('src',v);
$('#previewImg').load(function(){
window.URL.revokeObjectURL(v);
});
*/
/*
本地上传预览 方法3: Ajax上传
*/
var formdata=new FormData();
formdata.append("avatar",$("#avatarImg")[0].files[0]);
formdata.append("csrfmiddlewaretoken","{{ csrf_token }}"); //csrf
$.ajax({
url:"", //不填写就是当前 /upload/
type:"post",
contentType:false, // 用formdata的时候需要设置
processData:false, // 用formdata的时候需要设置
data:formdata,
success:function(arg){
arg = JSON.parse(arg);
if (arg.status) {
console.log(arg.data);
// 头像预览 方法3:
$('#previewImg').attr('src', '/' + arg.data);
}
}
})
})
}
</script>
</body>
</html>
二、伪Ajax上传文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
.avatar_con {
height: 100px;
width: 100px;
position: relative;
}
.avatar_con iframe {
display: none
}
.avatar_con img {
height: 100%;
width: 100%;
border: 0;
overflow: hidden;
max-height: 100px;
}
.avatar_con #previewImg {
border-radius: 50%;
border: 1px solid #dddddd;
padding: 3px;
height: 96px;
width: 96px;
}
.avatar_con #avatarImg {
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
position: absolute;
z-index: 102;
}
.avatar-avatar_con .text {
position: absolute;
left: 0;
bottom: 0;
text-align: center;
}
</style>
<body>
<h1>伪 Ajax上传文件</h1>
<div class="avatar_con">
<iframe id="upload_iframe" name="upload_iframe"></iframe>
<form method="POST" action="/upload/" enctype="multipart/form-data" target="upload_iframe">
<!--target和iframe的name 进行关联-->
<!--别忘了 编码格式 enctype="multipart/form-data"-->
{% csrf_token %}
<img id="previewImg" src="/media/avatar/default.png">
<div class="text">点击图片更换</div>
<input id="avatarImg" name="avatar" type="file"/>
</form>
</div>
<script src="http://code.jquery.com/jquery-1.12.3.min.js"></script>
<script type="text/javascript">
$(function () {
bindChangeAvatar();
});
function bindChangeAvatar() {
$('#avatarImg').change(function () {
$(this).parent().submit();
$('#upload_iframe').load(function () {
var con = this.contentWindow.document.body.innerText;
con = JSON.parse(con);
if (con.status) {
console.log(con.data);
$('#previewImg').attr('src', '/' + con.data);
}
})
})
}
</script>
</body>
</html>
三、原生Ajax上传文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
.avatar_con {
height: 100px;
width: 100px;
position: relative;
}
.avatar_con iframe {
display: none
}
.avatar_con img {
height: 100%;
width: 100%;
border: 0;
overflow: hidden;
max-height: 100px;
}
.avatar_con #previewImg {
border-radius: 50%;
border: 1px solid #dddddd;
padding: 3px;
height: 96px;
width: 96px;
}
.avatar_con #avatarImg {
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
position: absolute;
z-index: 102;
}
.avatar-avatar_con .text {
position: absolute;
left: 0;
bottom: 0;
text-align: center;
}
</style>
<body>
<h1>原生Ajax上传文件</h1>
<div class="avatar_con">
<label for="avatar">
<img id="previewImg" src="/media/avatar/default.png">
<div class="text">点击图片更换</div>
</label>
<input οnchange="bindChangeAvatar()" id="avatarImg" name="avatar" type="file"/>
</div>
<script>
function bindChangeAvatar(){
var formdata = new FormData();
formdata.append("avatar",document.getElementById('avatarImg').files[0]);
formdata.append("csrfmiddlewaretoken","{{ csrf_token }}"); //csrf
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
var arg = JSON.parse(xhr.responseText);
document.getElementById('previewImg').src='/' + arg.data
}
};
xhr.open('POST','/upload/');
/*xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
发post请求必须设置Content-Type,request.POST才有数据,并且已转换成字典,
不然就要去request.body中取值还是字节 b'a=1&b=2'
如果发送的是formdata 则不需要设置
*/
xhr.send(formdata);
}
</script>
</body>
</html>
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>首页</h1> <input type="text" id="i1" /> + <input type="text" id="i2" /> = <input type="text" id="i3" /> <input type="button" id="btn1" value="jQuery Ajax" onclick="add1();" /> <input type="button" id="btn2" value="原生Ajax" onclick="add2();" /> <script src="/static/jquery-1.12.4.js"></script> <script> function add1(){ $.ajax({ url: '/add1/', type: 'POST', data: {'i1': $('#i1').val(),'i2': $('#i2').val()}, success:function(arg){ $('#i3').val(arg); } }) } function add2(){ /* var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ alert(xhr.responseText); } }; xhr.open('GET','/add2/?i1=12&i2=19'); xhr.send(); */ var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ alert(xhr.responseText); } }; xhr.open('POST','/add2/'); xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); /*发post请求必须设置Content-Type,request.POST才有数据,并且已转换成字典,不然就要去request.body中取值还是字节 b'a=1&b=2' * 如果发送的是formdata 则不需要设置 * */ xhr.send("i1=12&i2=19"); } </script> </body> </html>
四、服务端处理上传文件
# 配置文件:
# 与用户上传相关的配置
MEDIA_ROOT= os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
# 路由中:
from django.urls import path, re_path
from django.views.static import serve
from django.conf import settings
from app01 import views
urlpatterns = [
# media配置:
re_path(r"media/(?P<path>.*)$", serve, {"document_root": settings.MEDIA_ROOT}),
# 文本编辑器上传图片url
path('upload/', views.upload),
]
# 视图中:
import os
import time
def upload(request):
ret = {'status': False, 'data': None, }
if request.method == 'POST':
# print(request.body) # 请求报文中的请求体 b'a=1&b=2'
# print(request.POST) # if contentType==urlencoded ,request.POST才有数据
# print(request.FILES) #文件都在这下面
file_obj = request.FILES.get('avatar') #文件对象
file_obj.name = "%s%s" % (time.time(), file_obj.name)
file_dir = 'media%savatar' % (os.sep)
if not os.path.exists(file_dir):
os.makedirs(file_dir)
file_path = os.path.join("media", "avatar", file_obj.name)
with open(file_path, 'wb') as f:
for line in file_obj:
f.write(line)
ret['status'] = True
ret['data'] = file_path
# cur_nid = request.session['user_info'].get('nid')
# row = models.UserInfo.objects.filter(nid=cur_nid).update(avatar='/%s'%(file_path))
# request.session['user_info']['avatar']='/%s'%(file_path)
return HttpResponse(json.dumps(ret))
return render(request, "upload.html")
五、models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
from
django.db
import
models
from
django.contrib.auth.models
import
AbstractUser
class
UserInfo(AbstractUser):
"""
用户信息
"""
nid
=
models.AutoField(primary_key
=
True
)
telephone
=
models.CharField(max_length
=
11
, null
=
True
, unique
=
True
)
avatar
=
models.FileField(upload_to
=
'avatars/'
, default
=
"avatars/default.png"
)
create_time
=
models.DateTimeField(verbose_name
=
'创建时间'
, auto_now_add
=
True
)
blog
=
models.OneToOneField(to
=
'Blog'
, to_field
=
'nid'
, null
=
True
, on_delete
=
models.CASCADE)
def
__str__(
self
):
return
self
.username
class
Meta:
verbose_name
=
'用户信息'
verbose_name_plural
=
'用户信息'
|
六、带form验证
"""
Myforms.py中:
from django import forms
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=32)
avatar = forms.FileField()
视图中:
import os
import time
from .Myforms import UploadFileForm
def upload(request):
if request.method == 'POST':
# form = UploadFileForm(data = request.POST, files = request.FILES) # 注意获取数据的方式
form = UploadFileForm(request.POST, request.FILES) # 注意获取数据的方式
if form.is_valid():
file_obj = request.FILES.get('avatar')
file_obj.name = "%s%s" % (time.time(), file_obj.name)
file_dir = 'media%savatar' % (os.sep)
if not os.path.exists(file_dir):
os.makedirs(file_dir)
file_path = os.path.join("media", "avatar", file_obj.name)
with open(file_path, 'wb') as f:
for line in file_obj:
f.write(line)
# cur_nid = request.session['user_info'].get('nid')
# row = models.UserInfo.objects.filter(nid=cur_nid).update(avatar='/%s'%(file_path))
# request.session['user_info']['avatar']='/%s'%(file_path)
return redirect('/')
else:
return render(request, "upload.html", locals())
form = UploadFileForm()
return render(request, "upload.html",{'form': form})
模板中:
<form method="POST" action="/upload/" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="{{ field.auto_id }}">{{ field.label }}</label>
{{ field }} <span class="pull-right error">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<input type="submit" class="btn btn-default" value="提交"/>
</form>
"""
浏览器的同源策略
- 跨域是因为浏览器的同源策略导致的,也就是说浏览器会阻止非同源的请求
- 域名不同或者端口不同都属于非同源的
- 浏览器只阻止表单以及ajax请求,并不会阻止src请求,所以cnd,图片等src请求都可以发
解决跨域
方式一:CORS跨域请求
- CORS即Cross Origin Resource Sharing 跨域资源共享
- 随着技术的发展,现在的浏览器可以支持主动设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。
- 跨域请求还分为两种,一种叫简单请求,一种是复杂请求
1、简单请求
- HTTP方法是下列方法之一 : HEAD, GET,POST
- HTTP头信息不超出以下几种字段 : Accept, Accept-Language, Content-Language, Last-Event-ID , Content-Type
- 其中Content-Type只能是下列类型中的一个 : application/x-www-from-urlencoded , multipart/form-data , text/plain
- 简单请求:一次请求
- 简单请求:服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'
2、复杂请求
- 任何一个不满足上述要求的请求,即会被认为是复杂请求
- 复杂请求:两次请求,在发送数据之前会先发一次请求用做“预检”,OPTIONS请求,只有“预检”通过后才再发送一次请求用于数据传输。
3、关于“预检”
- 请求方式:OPTIONS
- “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
4、如何“预检”
- 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过 Access-Control-Request-Method
- 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过 Access-Control-Request-Headers
5、ContentType
- 请求头ContentType指的是请求体的编码类型,常见的类型共有3种:
- application/x-www-form-urlencoded 这应该是最常见的 POST 提交数据的方式了。浏览器的原生表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。
- multipart/form-data 这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让表单的 enctype 等于 multipart/form-data。
- application/json 用来告诉服务端消息主体是序列化后的 JSON 字符串。
方式二:Jsonp
- Jsonp的实现原理是根据浏览器不阻止src请求来实现的,通过script标签的跨域特性来绕过同源策略。
- JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。
- JsonP解决跨域只能发送get请求,并且实现起来需要前后端交互比较多。
- 如果报错ALLOWED_HOSTS 需要在settings.py 中配置需要访问的域名 ALLOWED_HOSTS = ['http://www.s4.com']
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <input type="button" οnclick="AjaxRequest()" value="跨域Ajax" /> <div id="container"></div> <script src="jquery-1.8.2.min.js" type="text/javascript"></script> <script type="text/javascript"> function AjaxRequest() { $.ajax({ 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>
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <input type="button" value="获取用户列表" οnclick="getUsers();" /> <ul id="user_list"> </ul> <script src="/static/jquery-1.12.4.js"></script> <script> /* function getUsers(){ var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ var content = xhr.responseText; console.log(content); } }; xhr.open('GET','http://www.s4.com:8001/users/'); xhr.send(); } */ //a = ['alex','eric','egon'] /* function getUsers(){ var tag = document.createElement('script'); tag.src = "http://www.s4.com:8001/users/?callback=bbb?sdd"; document.head.appendChild(tag); } function bbb(arg){ console.log(arg); } */ function getUsers(){ // XMLHttpRequest /* $.ajax({ url: 'http://www.s4.com:8001/users/?callback=bbb', type: 'GET', success:function(arg){ console.log(arg); } }) */ // JSONP $.ajax({ url: 'http://www.s4.com:8001/users/', type: 'GET', dataType: 'JSONP', jsonp: 'callback', jsonpCallback: 'bbb' }) } function bbb(arg){ console.log(arg); } </script> </body> </html>
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
import json from django.shortcuts import render,HttpResponse from django.core.handlers.wsgi import WSGIRequest from django.views import View def users(request): v = request.GET.get('callback') print('请求来了...') user_list = [ 'alex','eric','egon' ] user_list_str = json.dumps(user_list) temp = "%s(%s)" %(v,user_list_str,) print(temp) return HttpResponse(temp) def new_users(request): print(request.method) 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 # user_list = [ # 'alex','eric','egon' # ] # user_list_str = json.dumps(user_list) # obj = HttpResponse(user_list_str) # # obj['Access-Control-Allow-Origin'] = "*" # return obj
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <input type="button" value="获取用户列表" οnclick="getUsers();" /> <ul id="user_list"> </ul> <script src="/static/jquery-1.12.4.js"></script> <script> function getUsers(){ $.ajax({ url: 'http://www.s4.com:8001/new_users/', type:"DELETE", success:function(arg){ console.log(arg); } }) } </script> </body> </html>
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<button id="btn_one">点击我向JsonP1发送请求</button> <script> // 测试发送请求失败 跨域不能得到数据 $('#btn_one').click(function () { $.ajax({ url: "http://127.0.0.1:8000/jsonp1", type: "get", success: function (response) { console.log(response) } }) }); function handlerResponse(response) { alert(response) }; window.onload = function () { $("#btn_one").click(function () { let script_ele = document.createElement("script"); script_ele.src = "http://127.0.0.1:8000/jsonp1?callback=handlerResponse"; document.body.insertBefore(script_ele, document.body.firstChild); }) } </script>
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Test(APIView): def get(self, request): callback = request.query_params.get("callback", "") ret = callback + "(" + "'success'" + ")" return HttpResponse(ret)
添加响应头
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
from django.middleware.security import SecurityMiddleware from django.utils.deprecation import MiddlewareMixin class MyCors(MiddlewareMixin): def process_response(self, request, response): response["Access-Control-Allow-Origin"] = "*" if request.method == "OPTIONS": response["Access-Control-Allow-Methods"] = "PUT, DELETE" response["Access-Control-Allow-Headers"] = "content-type" return response
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'middlewares.MyCors', ]
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE 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> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script> </head> <body> <div id="app"> </div> <script> const app = new Vue({ el: "#app", mounted(){ axios.request({ url: "http://127.0.0.1:8000/demo/", method: "POST", data: { "name": "Alex" } }).then(function (data) { console.log(data) }) } }) </script> </body> </html>
基于cors实现AJAX请求
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
简单请求 OR 非简单请求 条件: 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 注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求 简单请求和非简单请求的区别? 简单请求:一次请求 非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。 关于“预检” - 请求方式:OPTIONS - “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息 - 如何“预检” => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过 Access-Control-Request-Method => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过 Access-Control-Request-Headers
a、支持跨域,简单请求
服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="submit" οnclick="XmlSendRequest();" /> </p> <p> <input type="submit" οnclick="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>
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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"}')
b、支持跨域,复杂请求
由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。
- “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
- “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
- “预检”缓存时间,服务器设置响应头:Access-Control-Max-Age
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="submit" οnclick="XmlSendRequest();" /> </p> <p> <input type="submit" οnclick="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>
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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)
c、跨域获取响应头
默认获取到的所有响应头只有基本信息,如果想要获取自定义的响应头,则需要再服务器端设置Access-Control-Expose-Headers。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="submit" οnclick="XmlSendRequest();" /> </p> <p> <input type="submit" οnclick="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>
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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)
d、跨域传输cookie
在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送。
如果想要发送:
- 浏览器端:XMLHttpRequest的withCredentials为true
- 服务器端:Access-Control-Allow-Credentials为true
- 注意:服务器端响应的 Access-Control-Allow-Origin 不能是通配符 *
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="submit" οnclick="XmlSendRequest();" /> </p> <p> <input type="submit" οnclick="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>
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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)