跨域请求 JSONP & CORS
页面ajax跨域请求会受到浏览器同源策略的限制,不同协议、端口、主机(域名)等情况都会被限制。而在实际项目当中,跨域请求也经常会用到,常用的跨域请求有JSONP、CORS。
JSONP
浏览器对跨域ajax请求作限制,但是允许加载不同域静态文件,如css、js、img等。
如a.com加载b.com静态文件。
<script src="http://b.com/test.js"></script>
<img src="http://b.com/logo.png" alt="" title="" />
<link href="http://b.com/style.css" />
JSONP是利用浏览器的这一特性,将 script的src指向跨域的接口,并传递回调函数,接口返回的数据包含在回调函数的参数(JSON)里。script加载完成后会执行回调函数。
JSONP是JSON width padding 的简写,由回调函数和数据两部分组成。
// 前端代码
<script>
// 定义回调函数
function logInfo (data) {
console.log(data);
}
</script>
<script src="http://b.com/getUserInfo?callBack=logInfo"></script>
// 后端代码
router.get('/getUserInfo', function(req, res, next) {
// 回调函数
let callBack = req.query.callBack;
// JSON数据
let data = {
userName: '张三',
age: 25
};
res.send(callBack + '(' + JSON.stringify(data) + ')');
});
代码简单实现
/**
* JSONP跨域请求
* @param {String} url 请求地址
* @param {Object} params 请求参数
* @param {String} callBack 回调函数名
*/
function crossDomain (url, params, callBack) {
let script;
let query = '';
for(k in params){
query += k + '=' + params[k] + '&';
};
script = document.createElement('script');
script.src = url + '?' + query + '&callBack=' + callBack;
script.onload = function () {
// do something
};
document.head.appendChild(script);
};
crossDomain('http://b.com/getUserInfo', {id: 1}, 'logInfo');
动态加载script后,浏览器会立即执行返回的js。
logInfo({"userName":"张三","age":25})
CORS
CORS(Cross-Origin Resource Sharing,跨域资源共享),通过自定义HTTP头部让浏览器与服务器进行沟通,判断request或response成功与否。
CORS 需要客户端与服务端同时支持,现在大部分浏览器都支持,早期IE8、IE9需要通过XDomainRequest实现。
客户端请求头设置
HTTP首部字段无须手动设置,在发起请求时自动设置。
跨域请求头部
Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
Connection:keep-alive
Content-Type:application/x-www-form-urlencoded
Host:www.b.com
Origin:http://www.a.com
Referer:http://www.a.com/
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
同域请求头部
Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
Connection:keep-alive
Content-Type:application/x-www-form-urlencoded
Host:www.b.com
If-None-Match:W/"1d-ObzyCxC5+mC0i89GegH96w"
Referer:http://www.b.com/
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
X-Requested-With:XMLHttpRequest
跨域请求头部会被设置参数Origin:http://www.a.com
,用于服务端判断是否允许跨域。
服务端响应头设置
服务端通过设置响应参数决定是否允许请求。
- Access-Control-Allow-Origin 允许跨域请求源,如果是公共资源或不需要限制请求源可设置
*
- Access-Control-Allow-Methods 允许请求的方法,多个方法已逗号隔开
- Access-Control-Allow-Headers 允许请求的头部,多个头部已逗号隔开
- Access-Control-Max-Age 请求缓存多长时间
以Access-Control-Allow-Origin为例的跨域过程。如果感兴趣,可以查看下COR的实现方式。
JSONP 与 CORS 区别
JSONP与跨域资源共享(CORS)同样可实现跨域请求,CORS通过设置相应头(请求头无须手动设置),从而避开浏览器的同源策略。
- JSONP只支持GET请求,而 CORS 支持其他HTTP请求(如POST)
- JSONP是利用浏览器加载跨域静态文件实现,而CORS是通过XMLHttpRequest(IE8、9通过XDomainRequest)请求实现