浏览器跨域-CORS
来源:互联网 发布:西瓜影音播放网络文件 编辑:程序博客网 时间:2024/06/04 19:45
- CORS原理分析
- 实战解析
CORS原理分析
一、简介
CORS全称为”跨域资源共享”(Cross-origin resource sharing)
它允许浏览器跨服务器发起XMLHttpRequest
请求,从而解决Ajax只能同源使用的限制。CORS需要浏览器和服务器同时支持。目前大部分浏览器都支持该功能,但IE浏览器不能低于IE10。
只要浏览器支持CORS,主要重任就落到了服务端,需要服务端根据需求配置CORS响应头信息
整个CORS通信过程,都由浏览器自动完成,不需要用户参与。浏览器一旦发现Ajax请求跨域,就会自动添加一些附加的请求头信息(比如origin:xxx等),但用户不会察觉。
Accept:*/*Accept-Encoding:gzip, deflateAccept-Language:zh-CN,zh;q=0.8Connection:keep-aliveContent-Length:0Host:172.0.2.218:3000 //Ajax请求端口3000Origin:http://172.0.2.218:4000 //源前端口4000Referer:http://172.0.2.218:4000/User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
跨域请求开始后,服务端收到请求后,如果同意跨域访问,必须进行配置。比如必要字段Access-Control-Allow-Origin。服务端配置响应头信息:
//服务端配置res.setHeader("Access-Control-Allow-Origin", "*"); //`*`表示接受任意域名的请求//配置后的请求响应头信息Access-Control-Allow-Origin:*Connection:keep-aliveContent-Length:274Content-Type:application/json; charset=utf-8Date:Tue, 07 Nov 2017 06:15:56 GMTETag:W/"112-bBbMBo5MbTrlOpNo1daLKcUeKqs"X-Powered-By:Express
后,浏览器解析到服务端响应头信息Access-Control-Allow-Origin 字段满足要求,就继续正常请求;如果不满足,浏览器则抛出错误
Failed to load http://172.0.2.218:3000/client/api/000003: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://172.0.2.218:4000' is therefore not allowed access.
二、简单请求和非简单请求
对于简单请求和非简单请求浏览器没有等同视之,而有不同的处理规则。
对于简单请求:浏览器直接发出CORS请求。只不过在请求的头信息中增加了一个
origin
字段(表示源服务器)。服务端只需要根据业务需求在响应头信息中配置Access-Control-Allow-Origin字段即可。对于非简单请求:浏览器首先发送预检请求 去询问服务器的跨域策略,如果配置符合,浏览器再继续发送CORS请求。如果不符合,浏览器报错误:禁止跨域访问
Request URL:http://172.0.2.218:3000/client/api/000003Request Method:OPTIONS //预检请求方法Status Code:200 OKRemote Address:172.0.2.218:3000Referrer Policy:no-referrer-when-downgrade
此时服务器就需要在预检请求 中去配置响应头信息
什么是预检请求:预检请求 就是一个请求方式为OPTIONS 的请求。只需要再服务端增加 预检请求路由 即可。
一旦预检请求通过,以后的每次CORS请求,就类似于简单请求,只需要服务器每次响应一个头信息即可。
三、什么是简单请求和非简单请求?
只要满足以下两个条件,就属于简单请求:
- 请求方法是以下三种方法之一
- HEAD
- GET
- POST
- HTTP的头信息不超出以下几种字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Conent-Type: 仅限于 application/x-www-form-urlencoded、multipart/form-data、text/plain。
- 请求方法是以下三种方法之一
只要不满足以上两则条件都是非简单请求
四、服务器配置字段
必要字段Access-Control-Allow-Origin
该字段的值可以是指定的域名或者指定的一组域名或者是*
。浏览器根据该字段的值进行判断是否可以跨域。如果是*
表示服务端接受任意域名请求;如果是一个域名:表示服务器只接受指定的唯一域名;如果是一组域名:表示服务器接受指定的部分域名。可选字段Access-Control-Allow-Credentials
该值是一个布尔值,表示是否允许发送cookie。可选字段Access-Control-Allow-Headers
该字段表示服务器支持的所有头信息字段,如果跨域请求头中得请求字段不在此服务器支持范围,则浏览器禁止同源访问。可选字段Access-Control-Max-Age
用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。
实战解析
一、服务器环境node、利用同一ip不同端口来模拟跨域请求(源端口为:4000,资源端口为:3000)。非简单请求利用Ajax发送常见的Content-Type=application/json 实现
二、 源服务器文件:start.js 代码如下:
"use strict"var http = require("http")var fs = require("fs")var path = require("path")var root = path.resolve(process.argv[2] || ".")var server = http.createServer(function(req, res) { var filePath = path.join(root, "cors.html") fs.stat(filePath, function(err, stats) { if(!err && stats.isFile()) { res.writeHead(200, {"Content-Type": "text/html"}); fs.createReadStream(filePath).pipe(res) }else { console.log(err) } })})server.listen(4000)console.log("server is running at http://172.0.2.218:4000/")
三、源服务器html文件cors.html(包含Ajax请求脚本)。代码如下:
<!DOCTYPE><html> <head> <meta charset="UTF-8"> <title>跨域资源共享</title> </head> <body> <button onclick="simpleRequest()">Ajax简单请求</button> <button onclick="noSimpleRequest()">Ajax非简单请求</button> <h5>请求结果为:</h5> <p></p> </body> <script> function simpleRequest() {//Ajax简单请求 var pDoc = document.getElementsByTagName("p")[0] pDoc.innerHTML = "" var xmlHttp if(window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest() }else { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP") } xmlHttp.onreadystatechange = function() { if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { pDoc.innerHTML = xmlHttp.responseText } } xmlHttp.open("POST", "http://172.0.2.218:3000/client/api/000003", true) xmlHttp.send() }//172.0.2.218外网地址改为localhost function noSimpleRequest() {//Ajax非简单请求 var pDoc = document.getElementsByTagName("p")[0] pDoc.innerHTML = "" var xmlHttp if(window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest() }else { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP") } xmlHttp.onreadystatechange = function() { if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { pDoc.innerHTML = xmlHttp.responseText } } xmlHttp.open("POST", "http://172.0.2.218:3000/client/api/000003", true) xmlHttp.setRequestHeader("Content-Type","application/json") xmlHttp.send() } </script></html>
四、目的服务器文件名:app.js 部分代码如下:
/** * 临时接口 * 处理cors跨域 *///配置预检请求方式1/*app.all("*", function(req, res, next) { res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Access-Control-Allow-Headers", "Content-Type"); res.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"); next();})app.post("/client/api/000003", function(req, res) { var jsonData = { code: "0000", msg: "success", result: [ { notice_id: "18", notice_title: "清算问题", publish_date: "2017-10-30", publish_time: "10:34:42", type: "2" }, { notice_id: "12", notice_title: "A股交易规则", publish_date: "2017-10-19", publish_time: "09:33:22", type: "2" } ] } res.json(jsonData);})*///配置预检请求方式2: //预检请求方法OPTIONSapp.options("/client/api/000003", function(req, res, next) { res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Access-Control-Allow-Headers", "Content-Type"); res.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"); next();})app.post("/client/api/000003", function(req, res) { var jsonData = { code: "0000", msg: "success", result: [ { notice_id: "18", notice_title: "清算问题", publish_date: "2017-10-30", publish_time: "10:34:42", type: "2" }, { notice_id: "12", notice_title: "A股交易规则", publish_date: "2017-10-19", publish_time: "09:33:22", type: "2" } ] } res.setHeader("Access-Control-Allow-Origin", "*");//单独配置跨域响应头信息 res.json(jsonData);})/** * 方式2和方式1的不同 * 方式1: 每次请求发起的时候都必须经过`all("*")`所以每次请求头都配置了跨域信息 * 方式2; option仅仅是接受预检请求,只是表示浏览器前期询问跨域同意。而其他请求的时候还需要单独配置跨域响应头信息 *///监听端口var port = process.env.PORT || 3000app.listen(port)console.log(`app is running at ${port}`)
五、打开命令行,进入到origin_server目录,启动源服务器
$ node start.js
六、新开命令行界面,进入到resource_server目录,启动目的服务器
$ node app.js
七、浏览器中输入4000端口,效果如下:
八、点击简单请求和非简单请求:
demo链接:https://github.com/MayerFan/CORS_Demo
参考链接:http://www.ruanyifeng.com/blog/2016/04/cors.html
- 浏览器跨域-CORS
- 跨浏览器的CORS
- 浏览器和服务器实现跨域(CORS)判定的原理
- 浏览器和服务器实现跨域(CORS)
- 什么是跨域,Cors协议,spring cors
- 跨域资源共享(CORS)
- cors 跨域详解
- 跨域资源共享CORS
- CORS 跨域资源共享
- 跨域资源共享 CORS
- 跨域资源共享cors
- CORS 跨域访问
- CORS跨域原理
- 跨域之CORS
- CORS跨域资源共享
- 跨域资源共享 CORS
- 跨域请求CORS
- CORS跨域说明
- 【Luogu1414】又是毕业季II(数论)
- 关于sql和MySQL的语句执行顺序
- ES之 基本概念
- 1009. 说反话 (20)——C语言
- 记可视化项目学习之旅--1.RequestHandler;python-self;mongodb
- 浏览器跨域-CORS
- Tour HDU
- MySQL逻辑并行复制的实现
- 成都小孩买互助金
- IT行业三大定律
- SrcollView嵌套Recycler所遇到的Bug
- 简单工厂模式
- opencv(c++)图像处理(imgproc模块)[2]
- WebService(1)——使用JDK开发WebService