jsonp跨域资源引起CORB

一、jsonp的使用

jsonp是实现跨域请求数据的一种方式,解决了由于浏览器同源策略带来的安全限制;虽然浏览器有同源策略的限制,但对于一些特殊的dom元素却可引用非同源资源,例如<img src=""/> <script src=""/>等,下面结合例子说明:

  • jquery直接发起ajax调用

服务端代码

@RequestMapping(value = "/load/data")
public void loadData2(@RequestParam("callback") String callback,
                     HttpServletResponse response) throws IOException {
    Map<String, String> data = new HashMap<>();
    data.put("name", "xudj");
    data.put("age", "18");
    // 转json
    String jsonData = JSON.toJSONString(data);

    //用回调函数名称包裹返回数据
    String result = callback + "(" + jsonData + ")";
    response.getWriter().write(result);
}

客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>跨域测试</title>
    <script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
    <script>
        $(document).ready(function () {
            $("#btn").click(function () {
                $.ajax({
                    url: 'http://localhost:8080/load/data',
                    type: 'GET',
                    success: function (data) {
                        $(text).val(data);
                    }
                });
            });
        });
    </script>
</head>
<body>
<input id="btn" type="button" value="跨域请求数据" />
<textarea id="text" style="width: 200px; height: 100px;"></textarea>
</body>
</html>

调用结果
cors跨域
如上,当在localhost:9090站点访问localhost:8080的接口资源时,出现跨域错误。

如错误提示,可在服务器端代码中设置响应头“Access-Control-Allow-Origin”实现允许跨域
  • script解决跨域问题

服务端代码
如上不变

客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>script解决跨域</title>
    <script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
    <script>
        //回调函数
        function showData (result) {
            //json对象转成字符串
            var data = JSON.stringify(result);
            $("#text").val(data);
        }
        $(document).ready(function () {
            $("#btn").click(function () {
                // 向头部输入一个脚本,该脚本发起一个跨域请求
                $("head").append("<script src='http://localhost:8080/load/data?callback=showData'><\/script>");
            });
        });
    </script>
</head>
<body>
<input id="btn" type="button" value="跨域请求数据" />
<textarea id="text" style="width: 200px; height: 100px;"></textarea>
</body>
</html>

调用结果
script解决cprs

  • jsonp解决跨域

服务端代码
如上不变

客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp解决跨域</title>
    <script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
    <script>
        // 回掉函数,默认callback=jQuery30004159376653216822_1550582355513
        function showData(data) {
            console.info("Get Into showData");
            // json对象转成字符串
            var result = JSON.stringify(data);
            $("#text").val(result);
        }
        // 调用
        $(document).ready(function () {
            $("#btn").click(function () {
                $.ajax({
                    url: "http://localhost:8080/load/data",
                    type: "GET",
                    dataType: "jsonp", //指定服务器返回的数据类型
                    jsonpCallback: "showData",  // 指定回调函数名称或直接使用回掉函数success
                    jsonp: "callback",   // 默认callback
                    success: function (data) {
                        console.info("Get Into success");
                        // json对象转成字符串
                        // var result = JSON.stringify(data);
                        // $("#text").val(result);
                    }
                });
            });
        });
    </script>
</head>
<body>
<input id="btn" type="button" value="跨域请求数据"/>
<textarea id="text" style="width: 200px; height: 100px;"></textarea>
</body>
</html>

调用结果
jsonp解决跨域

通过指定ajax的dataType为“jsonp”,jsonp指定服务端返回jsonp格式数据;请求会自动带上参数callback=?

二、CORB问题的由来

当服务端代码中添加安全响应头时:
服务端代码

@RequestMapping(value = "/load/data")
    public void loadData2(@RequestParam("callback") String callback,
                         HttpServletResponse response) throws IOException {
        // 安全响应头
        response.addHeader("X-Content-Type-Options", "nosniff");
        response.setContentType("text/html;charset=UTF-8");

        Map<String, String> data = new HashMap<>();
        data.put("name", "xudj");
        data.put("age", "18");
        // 转json
        String jsonData = JSON.toJSONString(data);

        //用回调函数名称包裹返回数据
        String result = callback + "(" + jsonData + ")";
        response.getWriter().write(result);
    }
如上所示,代码中多出
// 安全响应头
response.addHeader("X-Content-Type-Options", "nosniff");
response.setContentType("text/html;charset=UTF-8");

导致使用jsonp解决跨域的请求出现如下错误:
jsonp出现CORB

如上,如果服务端代码没有指定ContentType时,则出现如下错误:

jsonp拒绝执行script
以上均是由response.addHeader("X-Content-Type-Options", "nosniff");导致的浏览器执行script时通过对MIME类型检测过滤掉不安全的文件或请求。

三、原因分析

CORB(Cross-Origin Read Blocking):浏览器在加载可以跨域资源时,在将资源载入页面时对其进行识别与拦截等一系列处理。
X-Content-Type-Options(:nosniff):相当于一个提示标志,被服务器用来提示客户端须遵循在Content-Type首部中对MIME类型的设定,不能对其进行修改。
从而禁用了客户端(浏览器)的MIME类型嗅探行为(即把不可执行的MIME类型转变为可执行的MIME类型)。指定值为nosniff时,会拒绝以下两种请求:
  • 请求类型:style,MIME类型不是“text/css”
  • 请求类型:script,MIME类型不是“Javascript类型”,Javascript类型有text/javascript、application/javascript、application/x-javascript等

所以,当服务端出现response.addHeader("X-Content-Type-Options", "nosniff");安全相应头,且未指定Content-Type为Javascript类型类型时,jsonp请求跨域资源时变出现如上CORB或拒绝解析的问题。

四、解决办法

根据第三步问题原因的分析中可知,修改方法有如下两种:

  1. 去除服务端response.addHeader("X-Content-Type-Options", "nosniff");的配置,但可能造成一些安全上的问题,笔者这里不做扩展,有兴趣的同学可以留言讨论
  2. 服务指定Content-Type为Javascript类型的一种即可
  3. 启用jsonp,将跨域的数据请求转到本站服务器,由本站服务器去做跨域请求,即跳过浏览器同源策略的限制

记忆阁楼
天道酬勤
10 声望
0 粉丝
0 条评论
推荐阅读
并发编程之happens-before
前言Jdk5开始,Java使用新的JSP-133内存模型,JSR-133使用happens-before的概念来阐述操作直接的内存可见性。在JMM中,如果一个操作执行结果需对另一个操作课件,那么这两个操作之间必须要存在happen-before关系。

luck阅读 1.2k

Java 编译器 javac 及 Lombok 实现原理解析
javac 是 Java 代码的编译器12,初学 Java 的时候就应该接触过。本文整理一些 javac 相关的高级用法。Lombok 库,大家平常一直在使用,但可能并不知道实现原理解析,其实 Lombok 实现上依赖的是 Java 编译器的注...

nullwy10阅读 5.9k

与RabbitMQ有关的一些知识
工作中用过一段时间的Kafka,不过主要还是RabbitMQ用的多一些。今天主要来讲讲与RabbitMQ相关的一些知识。一些基本概念,以及实际使用场景及一些注意事项。

lpe2348阅读 1.8k

封面图
Git操作不规范,战友提刀来相见!
年终奖都没了,还要扣我绩效,门都没有,哈哈。这波骚Git操作我也是第一次用,担心闪了腰,所以不仅做了备份,也做了笔记,分享给大家。问题描述小A和我在同时开发一个功能模块,他在优化之前的代码逻辑,我在开...

王中阳Go5阅读 1.8k评论 2

封面图
Redis 发布订阅模式:原理拆解并实现一个消息队列
“65 哥,如果你交了个漂亮小姐姐做女朋友,你会通过什么方式将这个消息广而告之给你的微信好友?““那不得拍点女朋友的美照 + 亲密照弄一个九宫格图文消息在朋友圈发布大肆宣传,暴击单身狗。”像这种 65 哥通过朋...

码哥字节5阅读 1.1k

封面图
NB的Github项目,看到最后一个我惊呆了!
最近看到不少好玩的、实用的 Github 项目,就来给大家推荐一把。中国制霸生成器最近在朋友圈非常火的一个小网站,可以在线标记 居住、短居、游玩、出差、路过 标记后可生成图片进行社区分享,标记过的信息会记录...

艾小仙5阅读 1.5k评论 1

好好的系统,为什么要分库分表?
今天是《分库分表 ShardingSphere 原理与实战》系列的开篇文章,之前写过几篇关于分库分表的文章反响都还不错,到现在公众号:程序员小富后台不断的有人留言、咨询分库分表的问题,我也没想到大家对于分库分表的话...

程序员小富3阅读 1.5k

10 声望
0 粉丝
宣传栏