什么是跨域?
跨域:指的是浏览器不能执行其它网站的脚本,它是由浏览器的同源策略造成的,是浏览器的安全限制!
同源策略
同源策略:域名、协议、端口均相同。
浏览器执行JavaScript脚本时,会检查这个脚本属于那个页面,如果不是同源页面,就不会被执行。
JSONP跨域
只支持GET请求,不支持POST等其它请求,也不支持复杂请求,只支持简单请求。
CORS跨域
支持所有的请求,包含GET、POST、OPTOIN、PUT、DELETE等。既支持复杂请求,也支持简单请求。
JSONP和CORS跨域理解
使用目的: JSONP与CORS的使用目的相同,并且都需要服务端和客户端同时支持,但CORS的功能更加强大。
JSONP(json with padding 填充式json):利用了使用src引用静态资源时不受跨域限制的机制。主要在客户端搞一个回调做一些参数接收与操作的处理,并把这个回调函数告知服务器,而服务器端需要做的是按照JavaScript的语法把数据放到约定好的回调函数之中即可,jQuery很早之前就已经把JSONP语法糖化了,使用起来会更加方便。
CORS(Cross-origin resource sharing 跨域资源共享):依附于AJAX,通过添加HTTP Header部分字段请求与获取有权限访问的资源。CORS对开发者是透明的,因为浏览器会自动根据请求的情况(简单和复杂)做出不同的处理。CORS的关键是服务器端的配置支持,由于CORS是W3C中一项较“新”的方案,以至于各大网页解析引擎还没有对齐进行严格规格的实现,所以不同引擎下可能会有一些不一致。
JSONP和CORS的优缺点
1. JSONP的主要优势在于对浏览器的支持较好;虽然目前主流浏览器都支持CORS,但IE9及以下不支持CORS。
2. JSONP只能用于获取资源(即只读,类似于GET请求);CORS支持所有类型的HTTP请求,功能完善。(这点JSONP被玩虐,但大部分情况下GET已经能满足需求了)
JSONP的错误处理机制并不完善,我们没办法进行错误处理;而CORS可以通过onerror事件监听错误,并且浏览器控制台会看到报错信息,利于排查。
3. JSONP只会发一次请求;而对于复杂请求,CORS会发两次请求。
4. 始终觉得安全性这个东西是相对的,没有绝对的安全,也做不到绝对的安全。毕竟JSONP并不是跨域规范,它存在很明显的安全问题:callback参数注入和资源访问授权设置。CORS好歹也算是个跨域规范,在资源访问授权方面进行了限制(Access-Control-Allow-Origin),而且标准浏览器都做了安全限制,比如拒绝手动设置origin字段,相对来说是安全了一点。但是回过头来看一下,就算是不安全的JSONP,我们依然可以在服务端端进行一些权限的限制,服务端和客户端也都依然可以做一些注入的安全处理,哪怕被攻克,它也只能读一些东西。就算是比较安全的CORS,同样可以在服务端设置出现漏洞或者不在浏览器的跨域限制环境下进行攻击,而且它不仅可以读,还可以写。
应用场景
如果需要兼容IE低版本浏览器,无疑,JSONP。
如果需要对服务端资源进行操作,无疑,CORS。
其他情况的话,根据自己的对需求的分析来决定和使用。
Ajax跨域调用Restful接口 JSONP和CORS两种解决方案详解
最近工作中遇到了一个需求,需要Ajax跨域调取Restful接口获取数据。因为本次需求仅用到GET请求,经过几番波折,最终采用JSONP方式(仅支持GET方式请求)实现。但是本篇文章将顺带介绍另一种更为通用的跨域解决方案CORS,因为CORS支持更多的请求方式(GET,POST,PUT,DELETE等)。
一. JSONP方式
前端代码:
var patientInfoURL = 'http://10.1.8.82:8332/soap/GetPatInfo?
citycardno=0000997144446894&id=32010600000002012';
$.ajax({
type:'get',
url: patientInfoURL ,
dataType:'jsonp',
//jsonp:'callback',//默认就是callback,可以不写
//jsonpCallback:"successCallback",//此处定义请求url中callback参数后的值,不写则jQuery会自动生成一个字符串
success:function(data){
console.log(data);
},
error:function(XMLHttpRequest, textStatus, errorThrown){
alert(XMLHttpRequest.status);
alert(XMLHttpRequest.readyState);
alert(textStatus);
}
});
以上代码说明:
Ajax跨域请求,浏览器会在请求的url后面自动加上两个param,一个key=callback,另一个key=_。其中第一个key的值callback可以通过jsonp:’callback’来改变,默认是callback。第二个key用途不清楚,不影响使用,有兴趣的朋友可以去研究,笔者在此不做介绍。具体可以看以下浏览器HTTP请求截图。
自定义jsonp的callback名字(即带有jsonpCallback:”successCallback”)
未自定义jsonp的callback名字(即不带有jsonpCallback:”successCallback”)
笔者遇到的问题:
刚开始用的jQuery版本是jquery-1.2.3.js,比较老的版本,结果是就算加了自定义的jsonpCallback,url参数中的callback值依然是jQuery随机生成的字符串。具体原因不得而知。后来换用了最新版的jQuery,jquery-3.3.1.js,问题随即得到了解决。
dataType:’jsonp’
如果Ajax涉及到跨域,则dataType一定要写‘jsonp’。
Jsonp服务器返回的数据格式:回调函数名+(+json+)
例如:回调函数名字是successCallback,json为{“name”:”hello”},
则Jsonp返回的数据格式successCallback({“name”:”hello”}); 所以后台返回数据的数据格式也要相应改变。
其中,回调函数名就是以上两幅截图中,callback对应的值(即 successCallback 或者 jQuery32108683094116218273_1536130976427),jQuery随机生成的字符串每次请求都不一样。
拓展:
关于Ajax中dataType的一些说明
1.释义:
预期服务器返回的数据类型。如果不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,比如XML MIME类型就被识别为XML。
在1.4中,JSON就会生成一个JavaScript对象,而script则会执行这个脚本。随后服务器端返回的数据会根据这个值解析后,传递给回调函数。
2.可用值:
“xml”: 返回 XML 文档,可用 jQuery 处理。
“html”: 返回纯文本 HTML 信息;包含的script标签会在插入dom时执行。
“script”: 返回纯文本 JavaScript 代码。不会自动缓存结果。除非设置了”cache”参数。”’注意:”’在远程请求时(不在同一个域下),所有POST请求都将转为GET请求。(因为将使用DOM的script标签来加载)
“json”: 返回 JSON 数据 。
“jsonp”: JSONP 格式。使用 JSONP 形式调用函数时,如 “myurl?callback=?” jQuery 将自动替换 ? 为正确的函数名,以执行回调函数。
“text”: 返回纯文本字符串
关于jsonp和jsonpcallback的详细使用说明,读者可以点击此处查看。
后端代码:
Response.ContentType="text/html; charset=utf-8";
String callback = Request.QueryString["callback"].ToString();
Response.Write(callback + "{ "success": [{ "id": 1, "title": "title 1" }, { "id": 2, "title": "title 2" }, { "id": 3, "title": "title 3"}] }");
通过获取前端请求url中param的key为callback的值来作为回调函数名。
二. CORS方式
介绍:
CROS是现在主流解决跨域问题的方案,未来估计也是趋势。
Cross-Origin Resource Sharing (CORS) 是W3c工作草案,它定义了在跨域访问资源时浏览器和服务器之间如何通信。CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否。
前端代码:
var patientInfoURL = 'http://10.1.8.82:8332/soap/GetPatInfo?
citycardno=0000997144446894&id=32010600000002012';
$.ajax({
type:'get',
url: patientInfoURL ,
dataType:'json',
success:function(data){
console.log(data);
},
error:function(XMLHttpRequest, textStatus, errorThrown){
alert(XMLHttpRequest.status);
alert(XMLHttpRequest.readyState);
alert(textStatus);
}
});
细心的朋友可以注意到,CORS方式的Ajax跨域请求和普通的非跨域Ajax请求看上去没什么区别,事实也确实如此。这也是CORS方式的优点所在。在程序员看来,所做的工作和非跨域并无区别,主要的区别则是在后端代码。
后端代码:
// 跨域配置
response.setHeader("Access-Control-Allow-Origin","*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Max-Age", "3600"); // 保持跨域Ajax时的Cookie
response.setHeader("Access-Control-Allow-Headers", "x-auth-token, x-requested-with,Authorization,Origin, Accept, Content-Type,x-xsrf-token");