第二百七十四节,同源策略和跨域Ajax
同源策略和跨域Ajax
什么是同源策略
URL | 结果 | 原因 |
http://store.company.com/dir2/other.html | 是 | |
http://store.company.com/dir/inner/another.html | 是 | |
https://store.company.com/secure.html | 不是 | 协议不相同 |
http://store.company.com:81/dir/etc.html | 不是 | 端口号不相同 |
http://news.company.com/dir/other.html | 不是 | 主机名不相同 |

127.0.0.1 www.fwd.com
127.0.0.1 www.khd.com
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script>
</head>
<body>
<input type="button" value="提交" onclick="doajax();"/>
<script>
function doajax() {
$.ajax({
url: 'http://www.fwd.com:8001/fwd',
type: 'POST',
data:{'k1':'v1'},
success: function (responseText, statusText) {
},
error: function (event, errorText, errorType) { }
});
}
</script>
</body>
</html>
http://www.fwd.com:8001/fwd
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script>
<script type="text/javascript" src='{{static_url("jquery.form.js")}}' charset="UTF-8"></script>
</head>
<body>
服务端
<script> </script>
</body>
</html>
此时点击按钮发起ajax请求后,可以看到请求已被浏览器的同源策略阻止

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script>
</head>
<body>
<input type="button" value="跨域提交" onclick="doajax();"/>
<script>
//利用原生js自己创建一个跨域请求
function doajax() { //当点击提交按钮是执行函数
var tag = document.createElement('script'); //创建一个script标签
tag.src = 'http://www.fwd.com:8001/fwd'; //设置script标签的src地址,为要请求数据的地址,因为src是不受同源策略
document.head.appendChild(tag); //将script标签添加到head标签里面
document.head.removeChild(tag); //添加后会立即发送请求,所以这里可以将添加的script标签删除了
}
//响应网站返回,shuju({'k1':'v1'}); 也就相当于返回了一个带有参数的函数名称
function shuju(shj) { //自定义执行函数,和响应网站返回的名称相同,也就会执行自定义函数,而参数就是响应网站返回的数据
for(var i in shj){ //循环响应网站返回的数据
alert(i + ':' + shj[i]); //打印出数据的键和值
}
}
</script>
</body>
</html>
响应端
import tornado.ioloop
import tornado.web #导入tornado模块下的web文件 class fwdHandler(tornado.web.RequestHandler):
def get(self): #接收get请求
# self.render("fwd.html")
self.write("shuju({'k1':'v1'});") #返回数据
def post(self):
self.write("post请求成功") settings = { #html文件归类配置,设置一个字典
"template_path":"views", #键为template_path固定的,值为要存放HTML的文件夹名称
"static_path":"statics", #键为static_path固定的,值为要存放js和css的文件夹名称
} #路由映射
application = tornado.web.Application([ #创建一个变量等于tornado.web下的Application方法
(r"/fwd", fwdHandler),
],**settings) #将html文件归类配置字典,写在路由映射的第二个参数里 if __name__ == "__main__":
#内部socket运行起来
application.listen(8001) #设置端口
tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script>
</head>
<body>
<input type="button" value="跨域提交" onclick="doajax();"/>
<script>
function doajax() { //当点击提交按钮是执行函数
$.ajax({
type: 'GET',
url: 'http://www.fwd.com:8001/fwd',
dataType: 'jsonp', //JSONP,数据类型
jsonpCallBack:'shj' //接收响应页面带有参数的函数名称
});
}
//响应网站返回,shuju({'k1':'v1'}); 也就相当于返回了一个带有参数的函数名称
function shuju(shj) { //自定义执行函数,和响应网站返回的名称相同,也就会执行自定义函数,而参数就是响应网站返回的数据
for (var i in shj) { //循环响应网站返回的数据
alert(i + ':' + shj[i]); //打印出数据的键和值
}
}
</script>
</body>
响应端
#!/usr/bin/env python
#coding:utf-8 import tornado.ioloop
import tornado.web #导入tornado模块下的web文件 class fwdHandler(tornado.web.RequestHandler):
def get(self): #接收get请求
# self.render("fwd.html")
self.write("shuju({'k1':'v1'});") #返回数据
def post(self):
self.write("post请求成功") settings = { #html文件归类配置,设置一个字典
"template_path":"views", #键为template_path固定的,值为要存放HTML的文件夹名称
"static_path":"statics", #键为static_path固定的,值为要存放js和css的文件夹名称
} #路由映射
application = tornado.web.Application([ #创建一个变量等于tornado.web下的Application方法
(r"/fwd", fwdHandler),
],**settings) #将html文件归类配置字典,写在路由映射的第二个参数里 if __name__ == "__main__":
#内部socket运行起来
application.listen(8001) #设置端口
tornado.ioloop.IOLoop.instance().start()
简单请求和非简单请求的区别?
简单请求:一次请求
非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。
条件:
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
注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求
self.set_header()方法,在响应端的逻辑处理的get或者post里使用,功能:给返回数据加上响应头标识告诉浏览器允许跨域请求
使用方法:两个参数,参数1,响应头标识,参数2,允许跨域请求的域名(多个域名,号隔开),(*代表所有域名支持跨域请求)
self.set_header('Access-Control-Allow-Origin','http://www.jxiou.com/')
self.set_header('Access-Control-Allow-Origin','*')
响应端
#!/usr/bin/env python
#coding:utf-8 import tornado.ioloop
import tornado.web #导入tornado模块下的web文件 class fwdHandler(tornado.web.RequestHandler):
def get(self): #接收get请求
pass
def post(self):
self.set_header('Access-Control-Allow-Origin','*')
self.write("{'k1':'v1'}") # 返回数据 settings = { #html文件归类配置,设置一个字典
"template_path":"views", #键为template_path固定的,值为要存放HTML的文件夹名称
"static_path":"statics", #键为static_path固定的,值为要存放js和css的文件夹名称
} #路由映射
application = tornado.web.Application([ #创建一个变量等于tornado.web下的Application方法
(r"/fwd", fwdHandler),
],**settings) #将html文件归类配置字典,写在路由映射的第二个参数里 if __name__ == "__main__":
#内部socket运行起来
application.listen(8001) #设置端口
tornado.ioloop.IOLoop.instance().start()
请求页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script>
</head>
<body>
<input type="button" value="跨域提交" onclick="doajax();"/>
<script>
function doajax() { //当点击提交按钮是执行函数
$.ajax({
type: 'POST',
url: 'http://www.fwd.com:8001/fwd',
data: {"a":'b'},
success: function (response, status, xhr) {
alert(response); //打印返回数据
}
});
}
</script>
</body>
</html>
复杂请求
复杂请求:两次请求,在发送数据之前会先发一次OPTIONS请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") 预检请求或者数据请求时允许跨域,允许跨域的域名(多个逗号隔开)(*标识所有域名允许)
self.set_header('Access-Control-Allow-Headers', "k1,k2") 预检请求时允许请求页面ajax设置请求头headers属性跨域,允许跨域的headers属性请求头(多个逗号隔开)
self.set_header('Access-Control-Allow-Methods', "PUT,DELETE") 预检请求时允许请求页面的请求方式跨域,允许跨域的请求方式(多个逗号隔开)
self.set_header('Access-Control-Max-Age', 10) 预检请求时设置预检有效时间,如设置10,表示这次预检后10秒后的请求再次预检
响应端
#!/usr/bin/env python
#coding:utf-8 import tornado.ioloop
import tornado.web #导入tornado模块下的web文件 class fwdHandler(tornado.web.RequestHandler):
def get(self): #接收get请求
pass
def options(self): #接收预检的options请求
self.set_header('Access-Control-Allow-Origin', '*') #预检请求或者数据请求时允许跨域,允许跨域的域名(多个逗号隔开)(*标识所有域名允许)
self.set_header('Access-Control-Allow-Methods', 'PUT') #预检请求时允许请求页面的请求方式跨域,允许跨域的请求方式(多个逗号隔开)
self.set_header('Access-Control-Allow-Headers', "k1,k2") #预检请求时允许请求页面ajax设置请求头headers属性跨域,允许跨域的headers属性请求头(多个逗号隔开)
def put(self):
self.set_header('Access-Control-Allow-Origin','*')
self.write("{'k1':'v1'}") # 返回数据 settings = { #html文件归类配置,设置一个字典
"template_path":"views", #键为template_path固定的,值为要存放HTML的文件夹名称
"static_path":"statics", #键为static_path固定的,值为要存放js和css的文件夹名称
} #路由映射
application = tornado.web.Application([ #创建一个变量等于tornado.web下的Application方法
(r"/fwd", fwdHandler),
],**settings) #将html文件归类配置字典,写在路由映射的第二个参数里 if __name__ == "__main__":
#内部socket运行起来
application.listen(8001) #设置端口
tornado.ioloop.IOLoop.instance().start()
请求页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script>
</head>
<body>
<input type="button" value="跨域提交" onclick="doajax();"/>
<script>
function doajax() { //当点击提交按钮是执行函数
$.ajax({
type: 'PUT', //复杂请求
url: 'http://www.fwd.com:8001/fwd',
headers: {'k1': 'qqtou'}, //设置请求头
data: {"a":'b'},
success: function (response, status, xhr) {
alert(response); //打印返回数据
}
});
}
</script>
</body>
</html>
跨域传输cookie
在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送。
如果想要发送:
浏览器端ajax属性:xhrFields的withCredentials为true
服务器端的预检请求和数据请求:Access-Control-Allow-Credentials为true
注意:服务器端响应的 Access-Control-Allow-Origin 不能是通配符 *
响应端
/usr/bin/env python
#coding:utf-8 import tornado.ioloop
import tornado.web #导入tornado模块下的web文件 class fwdHandler(tornado.web.RequestHandler):
def get(self): #接收get请求
pass
def options(self): #接收预检的options请求
self.set_header('Access-Control-Allow-Credentials', "true") #传递Cookie头以及用户的SSL证书
self.set_header('Access-Control-Allow-Origin', 'http://www.khd.com:8002') #预检请求或者数据请求时允许跨域,允许跨域的域名
self.set_header('Access-Control-Allow-Methods', 'PUT') #预检请求时允许请求页面的请求方式跨域,允许跨域的请求方式(多个逗号隔开)
self.set_header('Access-Control-Allow-Headers', "k1,k2") #预检请求时允许请求页面ajax设置请求头headers属性跨域,允许跨域的headers属性请求头(多个逗号隔开)
def put(self):
self.set_header('Access-Control-Allow-Credentials', "true") # 传递Cookie头以及用户的SSL证书
self.set_header('Access-Control-Allow-Origin','http://www.khd.com:8002')
self.write("{'k1':'v1'}") # 返回数据
self.set_cookie('kkkkk', 'vvvvv') #写入cookie
print(self.get_cookie('kkkkk')) #获取cookie settings = { #html文件归类配置,设置一个字典
"template_path":"views", #键为template_path固定的,值为要存放HTML的文件夹名称
"static_path":"statics", #键为static_path固定的,值为要存放js和css的文件夹名称
} #路由映射
application = tornado.web.Application([ #创建一个变量等于tornado.web下的Application方法
(r"/fwd", fwdHandler),
],**settings) #将html文件归类配置字典,写在路由映射的第二个参数里 if __name__ == "__main__":
#内部socket运行起来
application.listen(8001) #设置端口
tornado.ioloop.IOLoop.instance().start()
请求页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script>
</head>
<body>
<input type="button" value="跨域提交" onclick="doajax();"/>
<script>
function doajax() { //当点击提交按钮是执行函数
$.ajax({
type: 'PUT', //复杂请求
url: 'http://www.fwd.com:8001/fwd',
headers: {'k1': 'qqtou'}, //设置请求头
xhrFields:{withCredentials: true}, //传递Cookie头以及用户的SSL证书
data: {"a":'b'},
success: function (response, status, xhr) {
alert(response); //打印返回数据
}
});
}
</script>
</body>
</html>
self.set_header('xxoo', "bili") 设置响应头第一个是响应头名称,第二个是响应头值
self.set_header('Access-Control-Expose-Headers', "xxoo,bili") 允许设置的响应头,请求端获取
#!/usr/bin/env python
#coding:utf-8 import tornado.ioloop
import tornado.web #导入tornado模块下的web文件 class fwdHandler(tornado.web.RequestHandler):
def get(self): #接收get请求
pass
def options(self): #接收预检的options请求
self.set_header('Access-Control-Allow-Credentials', "true") #传递Cookie头以及用户的SSL证书
self.set_header('Access-Control-Allow-Origin', 'http://www.khd.com:8002') #预检请求或者数据请求时允许跨域,允许跨域的域名
self.set_header('Access-Control-Allow-Methods', 'PUT') #预检请求时允许请求页面的请求方式跨域,允许跨域的请求方式(多个逗号隔开)
self.set_header('Access-Control-Allow-Headers', "k1,k2") #预检请求时允许请求页面ajax设置请求头headers属性跨域,允许跨域的headers属性请求头(多个逗号隔开)
def put(self):
self.set_header('Access-Control-Allow-Credentials', "true") # 传递Cookie头以及用户的SSL证书
self.set_header('Access-Control-Allow-Origin','http://www.khd.com:8002')
self.set_header('xxoo', "bili") #设置响应头第一个是响应头名称,第二个是响应头值
self.set_header('Access-Control-Expose-Headers', "xxoo,bili") #允许设置的响应头,请求端获取 self.write("{'k1':'v1'}") # 返回数据
self.set_cookie('kkkkk', 'vvvvv') #写入cookie
print(self.get_cookie('kkkkk')) #获取cookie settings = { #html文件归类配置,设置一个字典
"template_path":"views", #键为template_path固定的,值为要存放HTML的文件夹名称
"static_path":"statics", #键为static_path固定的,值为要存放js和css的文件夹名称
} #路由映射
application = tornado.web.Application([ #创建一个变量等于tornado.web下的Application方法
(r"/fwd", fwdHandler),
],**settings) #将html文件归类配置字典,写在路由映射的第二个参数里 if __name__ == "__main__":
#内部socket运行起来
application.listen(8001) #设置端口
tornado.ioloop.IOLoop.instance().start()
第二百七十四节,同源策略和跨域Ajax的更多相关文章
- 第三百七十四节,Django+Xadmin打造上线标准的在线教育平台—创建课程app,在models.py文件生成4张表,课程表、课程章节表、课程视频表、课程资源表
第三百七十四节,Django+Xadmin打造上线标准的在线教育平台—创建课程app,在models.py文件生成4张表,课程表.课程章节表.课程视频表.课程资源表 创建名称为app_courses的 ...
- 第一百七十四节,jQuery,Ajax进阶
jQuery,Ajax进阶 学习要点: 1.加载请求 2.错误处理 3.请求全局事件 4.JSON 和 JSONP 5.jqXHR 对象 在 Ajax 课程中,我们了解了最基本的异步处理方式.本章,我 ...
- 第二百七十四、五、六天 how can I 坚持
三天小长假这么快就过去了,好快啊.基本都是在济南过的. 元旦.坐车回济南.下午在万科新里程看了一下午房子,没有买啊,93的现在八千六七,有点贵啊,户型也不是自己喜欢的. 晚上一块吃了个饭,还行,晚上在 ...
- 第二百六十四节,Tornado框架-基于正则的动态路由映射分页数据获取计算
Tornado框架-基于正则的动态路由映射分页数据获取计算 分页基本显示数据 第一步.设置正则路由映射配置,(r"/index/(?P<page>\d*)", inde ...
- 第二百二十四节,jQuery EasyUI,ComboGrid(数据表格下拉框)组件
jQuery EasyUI,ComboGrid(数据表格下拉框)组件 学习要点: 1.加载方式 2.属性列表 3.方法列表 本节课重点了解 EasyUI 中 ComboGrid(数据表格下拉框)组件的 ...
- 第二百七十九节,MySQL数据库-pymysql模块操作数据库
MySQL数据库-pymysql模块操作数据库 pymysql模块是python操作数据库的一个模块 connect()创建数据库链接,参数是连接数据库需要的连接参数使用方式: 模块名称.connec ...
- 第二百七十五节,MySQL数据库安装和介绍
MySQL数据库安装 一.概述 1.什么是数据库 ? 答:数据的仓库,称其为数据库 2.什么是 MySQL.Oracle.SQLite.Access.MS SQL Server等 ? 答:他们均是一种 ...
- 第二百三十四节,Bootstrap表单和图片
Bootstrap表单和图片 学习要点: 1.表单 2.图片 本节课我们主要学习一下 Bootstrap 表单和图片功能,通过内置的 CSS 定义,显示各 种丰富的效果. 一.表单 Bootstrap ...
- 第二百七十六节,MySQL数据库,【显示、创建、选定、删除数据库】,【用户管理、对用户增删改查以及授权】
MySQL数据库,[显示.创建.选定.删除数据库],[用户管理.对用户增删改查以及授权] 1.显示数据库 SHOW DATABASES;显示数据库 SHOW DATABASES; mysql - 用户 ...
随机推荐
- Web中树形数据(层级关系数据)的实现—以行政区树为例
在Web开发中常常遇到树形数据的操作,如菜单.组织机构.行政区(省.市.县)等具有层级关系的数据. 以下以行政区为例说明树形数据(层级关系数据)的存储以及实现,效果如图所看到的. 1 数据库表结构设计 ...
- One or more files are in a conflicted state
http://blog.csdn.net/caiwenfeng_for_23/article/details/37501249 解决代码冲突 如果commit时出现“You have to updat ...
- 算法笔记_153:算法提高 判断名次(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 某场比赛过后,你想要知道A~E五个人的排名是什么,于是要求他们每个人说了一句话.(经典的开头……-_-!)得了第1名的人23,说了假话:得 ...
- 怎样获取oracle dbid
1.查询v$database获得 因为DBID在控制文件和数据文件里都存在记录,所以假设可以mount数据库就行查询v$database视图获得. SQL> alter database mo ...
- Android系统源代码——所需工具
一.概述 众所周知,Android移动操作系统是Google花费了很大的财力.物力及人力的前提下,推广到世界各个角落,以开放源代码的方式(当然也不是完全开放所有),使其在世界范围内迅速漫延开来,到目前 ...
- 真正的PHP多线程(绝非fork或者用http再开进程)
转载:http://blog.csdn.net/leinchu/article/details/8012640 我写了一个扩展打算放到pecl,但是,进过交流发现有人已经做了两个php的多线程扩展 1 ...
- JAVA中的static方法
static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念. 被static修饰的成员变量和成员方法独立于该类的任何 ...
- Linux下TCP/IP内核参数优化
/proc/sys/net目录 所有的TCP/IP参数都位于/proc/sys/net目录下(请注意,对/proc/sys/net目录下内容的修改都是临时的,任何修改在系统重启后都会丢失),例如下面这 ...
- 手动集成OWIN
1.Install-Package Microsoft.AspNet.Identity.Owin Owin的很大亮点之一就是它可以让我们的ASP.NET 网站摆脱IIS,但是毕竟大多数的ASP.NET ...
- Java模拟公司置办货物系统(二)
採用MVC风格,将数据写入文件,模拟公司置办货物系统. A类表示普通员工,B类表示部门精力,C类表示採购部,D类表示资源管理部. 订单状态 1.表示申请状态 2.表示通过审批 3.表示未通过审批 4 ...