Cors跨域(四):解决方案对决JSONP vs CORS(上)

简介: Cors跨域(四):解决方案对决JSONP vs CORS(上)

✍前言


你好,我是方同学(YourBatman)


A哥 -> 方同学。是的,中文昵称改了。自知道行不深无以用“哥”字称呼,虽已毕业多年,同学二字寄寓心态一直积极、热情、年轻


挖掘机技术哪家强,山东技校找蓝翔;跨域问题怎么解,CORS还是JSONP?


关于浏览器跨域问题的解决方案,坊间一直“传闻”着两种解决方案:JSONP和CORS。由于文章的历史背景不同,作者偏好不一样,搞得好些同学迷惑得很,去谷歌里百度搜寻答案时经常就是这种赶脚。


作为一家负责任的“技校”(负责人的技术专栏),今天通过此文彻底给你解释清楚并给出确定的答案,助你快速选择正确的道路解决问题。


所属专栏


点拨-Cors跨域


本文提纲

image.png


版本约定

  • JDK:8
  • Servlet:4.x
  • tomcat:9.x


✍正文


同源策略是浏览器最核心也最基本的安全功能。当被浏览器半信半疑的脚本运行在沙箱时,它们应该只被允许访问来自同一站点的资源,而不是那些来自其它站点可能怀有恶意的资源。但是呢,在现在的互联网场景中,跨域访问是一种必须,所以才有了解决跨域问题的方案。


两大方案:JSONP和CORS


对于跨域共享资源,一共有两大解决方案


  • JSONP:老一代浏览器解决方案
  • CORS:全新一套标准的解决方案


JSONP方案


image.png


和iPhone 7和iPhone 7P不一样,JSONP 不等于 JSON Plus,全称是JSON with Padding。JSON是一种基于文本的数据交换格式,而JSONP是一种使用模式,可以让网页从别的域访问资源,从而完成跨域资源共享。


本系列第一篇文章就说到:<script>标签的src是没有跨域这么一说的,可以基于这一点实现Get请求的跨域。


JSONP的实现跨域的基本原理是:利用script标签的src没有跨域限制 + 回调的方式来完成跨域访问。


代码实现示例


前端页面:托管在63342端口


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JSONP跨域请求</title>
    <!--导入Jquery-->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>
<script>
    // 请求完成后会回调此函数
    function jsonpCallback(result) {
        console.log("这是JSONP请求的响应结果:" + result);
    }
</script>
<!--注:这个script必须放在上面function的下面-->
<script type="text/javascript" src="http://localhost:8080/jsonp?callback=jsonpCallback"></script>
</body>
</html>


说明:利用script的src发送http请求到服务端,因此此script标签务必放在function的下面(因为浏览器是从上至下渲染)


服务端代码:托管在8080端口


/**
 * 在此处添加备注信息
 *
 * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a>
 * @site https://yourbatman.cn
 * @date 2021/6/9 10:36
 * @since 0.0.1
 */
@Slf4j
@WebServlet(urlPatterns = "/jsonp")
public class JSONPServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String callback = req.getParameter("callback");
        resp.getWriter().write(callback + "('hello jsonp...')");
    }
}

说明:可以看到服务端的代码非常的清爽,不涉及到任何请求头/响应头


打开页面,发送JSONP请求,结果如下:

image.png

请求的响应体:


image.png


浏览器控制台输出:


image.png


完美。通过JSONP我们实现了访问不同域的资源,实现了跨域。


用jQuery的ajax发送异步JSONP请求

上例是使用<script>标签的src属性发送同步跨域请求,在实际开发中(特别是前后端分离)大多数情况下发送的均为Ajax异步请求,下面来试试。


说明:异步请求用原生XMLHttpRequest还是Ajax或者Promis方式发出,底层原理都归一是相同的


使用jQuery发送异步JSONP请求非常的简单,连<script>和函数都不用写:


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JSONP跨域请求</title>
    <!--导入Jquery-->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>
<!--<script>-->
<!--    // 请求完成后会回调此函数-->
<!--    function jsonpCallback(result) {-->
<!--        console.log("这是JSONP请求的响应结果:" + result);-->
<!--    }-->
<!--</script>-->
<!--&lt;!&ndash;注:这个script必须放在上面function的下面&ndash;&gt;-->
<!--<script type="text/javascript" src="http://localhost:8080/jsonp?callback=jsonpCallback"></script>-->
<script>
    $.ajax({
        // type: "get", // 不用写方法,因为JSONP只支持GET请求
        url: "http://localhost:8080/jsonp", // 使用jQuery的Ajax后面是没有参数
        dataType: 'jsonp',
        success: function (data) {
            console.log("这是JSONP请求的响应结果(jQuery Ajax):" + data);
        },
    });
</script>
</body>
</html>


通过jQuery大大改善了js代码的书写方式,使得结构更加优雅、直观。这就是jQuery最厉害的语法糖能力~


说明:JsonP only works with type: GET。也就说type即使你写成post,jQuery也会给你转成get


服务端不变,发送异步请求,结果如下:


image.png


image.png


关注点:


  1. Ajax的callback回调函数名是动态生成的,并且确保了唯一性
  2. 由于服务端并不关心回调的函数名名称,因此回调函数名的长短没有关系(浏览器自己能识别就成)


影响体如下:


image.png


浏览器控制台打印:


image.png


完美。对于有技术敏感性的你来讲,应该能发现底层原理依旧还是script的src,只是写法不一样,仅此而已。


优缺点


JSONP跨域方案作为一种“古老”方式,有如下优缺点:

优点:


  • 对老浏览器(如IE8、7等)有非常好的兼容性
  • 书写起来比较简单,容易理解(毕竟没有那么多的请求头、响应头需要考虑嘛)

缺点:


  • 只能发送get请求,不支持POST、PUT等请求方式,这是硬伤
  • 安全度不高。因为JSONP是利用函数回调来由浏览器执行目标函数,这样宿主web其实是比较容易受到各类攻击的


总的来讲,随着Cors规范在2014年的正式确定,现代的浏览器100%支持Cors规范。由于浏览器的更新换代,JSONP的最大优势(兼容老浏览器)也就不复存在了,所以在实际开发中的使用建议是:不要使用JSONP,而应拥抱CORS。


CORS方案


image.png



由于JSONP方案存在一些不足(比如只支持Get请求就是硬伤),并不能很好的满足对跨域资源共享的需求,因此就出现了当下主流的跨域规范:CORS(Cross-origin resource sharing)


不同于JSONP的方案,CORS方案更强大实用,但稍微复杂那么一丢丢。其背后的基本思想是:使用自定义的HTTP头部和浏览器“沟通”,让浏览器和服务器相互“了解”对方,从而决定请求或响应成功与否。


说明:CORS 并不是为了解决服务端安全问题而出现,而是为了解决如何跨域调用资源。至于如何设计出安全的、开放的API,这就是安全范畴了(如可加上token验证、请求有效期、ip来源验证等手段)


CORS的WD(工作草案)从2009-03-17开始,2014-01-16进入REC(推荐标准)阶段,可谓正式毕业。起初CORS的推广的主要障碍是当时市面上的老浏览器并不支持它(比如当时市场占有率极大的IE 6、7、8这种老家伙),毕竟这个规范是新的只有升级的新浏览器才会支持到。


但历史的巨轮永远是滚滚向前,现在已经2021年了,现今市面上的浏览器对CORS规范的支持情况如下图所示(数据来源于:http://caniuse.com):


image.png


看到这张图,应该可以毫不客气的说:所有的浏览器(包括手机、PAD等浏览器)均已支持CORS规范

版本上拿Chrome浏览器举例:我现在使用的版本是91.0.xxxx.xxx,完美支持:


image.png


当下阶段,已完全无需考虑浏览器兼容问题,所以JSONP的优势也就不复存在,可以放心的、积极的拥抱CORS。既然要用CORS,作为程序员不能只停留在概念上层面,接下来就来聊点干的,看看从实操层面有哪些具体做法落地CORS呢?


CORS的核心要义是和服务端和浏览器进行沟通,服务端架构一般是分层的,理论上可以在任意层次完成沟通。从负责完成沟通的层次上来讲,一般分为这两大类:


  1. 代理服务器/网关负责
  2. Web应用自行负责


相关文章
|
9天前
|
开发框架 中间件 Java
如何处理跨域资源共享(CORS)的 OPTIONS 请求?
处理 CORS 的 OPTIONS 请求的关键是正确设置响应头,以告知浏览器是否允许跨域请求以及允许的具体条件。根据所使用的服务器端技术和框架,可以选择相应的方法来实现对 OPTIONS 请求的处理,从而确保跨域资源共享的正常进行。
|
9天前
|
JavaScript 前端开发 API
跨域资源共享(CORS)的工作原理是什么?
跨域资源共享(CORS)通过浏览器和服务器之间的这种交互机制,在保证安全性的前提下,实现了跨域资源的访问,使得不同源的网页能够合法地获取和共享服务器端的资源,为现代Web应用的开发提供了更大的灵活性和扩展性。
|
23天前
|
JSON 前端开发 安全
CORS 是什么?它是如何解决跨域问题的?
【10月更文挑战第20天】CORS 是一种通过服务器端配置和浏览器端协商来解决跨域问题的机制。它为跨域资源共享提供了一种规范和有效的方法,使得前端开发人员能够更加方便地进行跨域数据交互。
|
1月前
|
缓存 前端开发 应用服务中间件
CORS跨域+Nginx配置、Apache配置
CORS跨域+Nginx配置、Apache配置
134 7
|
2月前
|
JSON 安全 前端开发
浅析CORS跨域漏洞与JSONP劫持
浅析CORS跨域漏洞与JSONP劫持
82 3
|
5月前
|
前端开发 安全 JavaScript
Spring Boot2 系列教程(十四)CORS 解决跨域问题
Spring Boot2 系列教程(十四)CORS 解决跨域问题
|
2月前
|
安全
CORS 跨域资源共享的实现原理
CORS 跨域资源共享的实现原理
|
3月前
|
Web App开发 JSON 数据格式
【Azure Developer】浏览器查看本地数据文件时遇见跨域问题(CORS)
【Azure Developer】浏览器查看本地数据文件时遇见跨域问题(CORS)
【Azure Developer】浏览器查看本地数据文件时遇见跨域问题(CORS)
|
3月前
|
API
【Azure Function】Function本地调试时遇见跨域问题(blocked by CORS policy)
【Azure Function】Function本地调试时遇见跨域问题(blocked by CORS policy)
【Azure Function】Function本地调试时遇见跨域问题(blocked by CORS policy)
|
3月前
|
安全 前端开发 Java
Web端系统开发解决跨域问题——以Java SpringBoot框架配置Cors为例
在Web安全上下文中,源(Origin)是指一个URL的协议、域名和端口号的组合。这三个部分共同定义了资源的来源,浏览器会根据这些信息来判断两个资源是否属于同一源。例如,https://www.example.com:443和http://www.example.com虽然域名相同,但由于协议和端口号不同,它们被视为不同的源。同源(Same-Origin)是指两个URL的协议、域名和端口号完全相同。只有当这些条件都满足时,浏览器才认为这两个资源来自同一源,从而允许它们之间的交互操作。
Web端系统开发解决跨域问题——以Java SpringBoot框架配置Cors为例