有关同源策略详细介绍,请看 这里
JSONP是服务器与客户端跨源通讯的经常使用方法。最大特色就是简单适用,老式浏览器所有支持,服务器改造很是小。
它的基本思想是,网页经过添加一个<script>
元素,向服务器请求JSON数据,这种作法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
首先,网页动态插入<script>
元素,由它向跨源网址发出请求。
例子:javascript
客服端java
function addScriptTag(src) { var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } window.onload = function () { addScriptTag('http://localhost:3000/test?callback=foo'); } function foo(data) { console.log('Your public IP address is: ' + data.ip); };
上面代码经过动态添加<script>
元素,向服务器http://localhost:3000
发出请求。注意,该请求的查询字符串有一个callback
参数,用来指定回调函数的名字,这对于JSONP是必需的。express
服务器收到这个请求之后,会将数据放在回调函数的参数位置返回。json
JavaScript服务端后端
var express = require('express'); var app = express(); app.get('/test', function (req, res) { var cbFunction = req.query.callback res.send(`${cbFunction}({"ip":"110.110.110.110"})`); //或者不用那么麻烦直接经过express提供的API /** * res.jsonp({ip:"110.110.110.110"}); */ }); var server = app.listen(3000, function () { var host = server.address().address; var port = server.address().port; console.log('Example app listening at http://%s:%s', host, port); });
上面代码经过express作的简单后台,当请求接口时,后端拿到callback
参数而后将其与要返回的数据组合成字符串的形式返回给客户端。
因为<script>
元素请求的脚本,直接做为代码运行。这时,只要浏览器定义了foo
函数,该函数就会当即调用。做为参数的JSON数据被视为JavaScript对象,而不是字符串,所以避免了使用JSON.parse
的步骤。跨域
CORS有两种请求 :简单请求(simple request)和非简单请求(not-so-simple request)只要同时知足如下两大条件,就属于简单请求。浏览器
请求方法是如下三种方法之一:服务器
HTTP的头信息不超出如下几种字段:app
application/x-www-form-urlencoded
、multipart/form-data
、text/plain
凡是不一样时知足上面两个条件,就属于非简单请求。
浏览器对这两种请求的处理,是不同的。函数
客户端
var xhr = new XMLHttpRequest() xhr.open('post','http://localhost:3000/test',true) xhr.onload = function(e){ if(e.currentTarget.status==200){ alert(e.currentTarget.responseText) } } xhr.send()
RequestHeaders请求头信息
Accept:/*/ Accept-Encoding:gzip, deflate, br Accept-Language:zh-CN,zh;q=0.8 Connection:keep-alive Content-Length:0 Host:localhost:3000 Origin:http://localhost:8020 Referer:http://localhost:8020/ User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
JavaScript服务端
app.post('/test', function (req, res) { res.set('Access-Control-Allow-Origin','http://localhost:8020') res.send({ name:'tom' }) });
ResponseHeaders
Access-Control-Allow-Origin:http://localhost:8020 Connection:keep-alive Content-Length:14 Content-Type:application/json; charset=utf-8 Date:Mon, 09 Apr 2018 02:09:05 GMT ETag:W/"e-v50e5W1R/vD6VVQyxqDA0eSWedA" X-Powered-By:Express
客户端
var xhr = new XMLHttpRequest() xhr.open('put','http://localhost:3000/test',true) xhr.setRequestHeader('X-Custom-Header', 'value'); xhr.onload = function(e){ if(e.currentTarget.status==200){ alert(e.currentTarget.responseText) } } xhr.send()
当发送上面的http请求时浏览器会先发送一个options类型的http的预检请求
RequestHeaders请求头信息
Accept:*/* Accept-Encoding:gzip, deflate, br Accept-Language:zh-CN,zh;q=0.8 Access-Control-Request-Headers:x-custom-header Access-Control-Request-Method:PUT Connection:keep-alive Host:localhost:3000 Origin:http://localhost:8020 Referer:http://localhost:8020/ User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
JavaScript服务端
//options类型用于CORS非简单请求的预检请求 app.options('/test',function(req,res){ res.set('Access-Control-Allow-Origin','http://localhost:8020') //必须设置 res.set('Access-Control-Allow-Methods','PUT') //必须设置 res.set('Access-Control-Allow-Headers','X-Custom-Header') //若是浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。 res.send({status:200,msg:'预检成功!'}) })
ResponseHeaders
Access-Control-Allow-Headers:X-Custom-Header Access-Control-Allow-Methods:PUT Access-Control-Allow-Origin:http://localhost:8020 Connection:keep-alive Content-Length:38 Content-Type:application/json; charset=utf-8 Date:Mon, 09 Apr 2018 04:08:40 GMT ETag:W/"26-+1THtR73k4ca8avMcdsJULlJZUs" X-Powered-By:Express
关于客户端和服务端字段相应说明能够在 这里查看
一旦服务器经过了"预检"请求,之后每次浏览器正常的CORS请求,就都跟简单请求同样,会有一个Origin
头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin
头信息字段。
客户端
RequestHeaders请求头信息
Accept:*/* Accept-Encoding:gzip, deflate, br Accept-Language:zh-CN,zh;q=0.8 Connection:keep-alive Content-Length:0 Host:localhost:3000 Origin:http://localhost:8020 Referer:http://localhost:8020/ User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36 X-Custom-Header:value
上面头信息的Origin
字段是浏览器自动添加的。
JavaScript服务端
app.put('/test', function (req, res) { res.set('Access-Control-Allow-Origin','http://localhost:8020') res.send({ name:'tom' }) });
ResponseHeaders
Access-Control-Allow-Origin:http://localhost:8020 Connection:keep-alive Content-Length:14 Content-Type:application/json; charset=utf-8 Date:Mon, 09 Apr 2018 04:08:40 GMT ETag:W/"e-v50e5W1R/vD6VVQyxqDA0eSWedA" X-Powered-By:Express
上面头信息中,Access-Control-Allow-Origin
字段是每次回应都一定包含的。