前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >谷歌浏览器获取本地json文件跨域问题及JSONP的应用

谷歌浏览器获取本地json文件跨域问题及JSONP的应用

作者头像
celineWong7
发布2020-11-05 19:03:45
4K0
发布2020-11-05 19:03:45
举报
文章被收录于专栏:web前端踩坑web前端踩坑

最近需要读取本地json文件,找到了原生js方式和ajax方式,都会报跨域的问题。于是研究了下什么是跨域,为什么会跨域,以及JSONP解决方案的运用。

一、我是怎么遇到跨域问题的?

因为要读取本地json文件(test.json),分别使用了原生js方式和ajax方式(代码如下)。

代码语言:javascript
复制
// 原生方式  -   google会报跨域
window.onload = function () {
    var url = "./test.json";
    var request = new XMLHttpRequest();
    request.open("get", url); // 设置请求方法与路径
    request.send(null);// 读取本地,就不发送数据到服务器
    request.onload = function () { // XHR对象获取到返回信息后执行
        if (request.status == 200) { // 返回状态为200,即为数据获取成功
            var json = JSON.parse(request.responseText);
            console.log(json);
        }
    }
}
代码语言:javascript
复制
    // ajax请求json文件  -   google会报跨域
    // 要引入jq库文件
    $.ajax({
        url: "./test.json",// json文件位置
        type: "GET",
        dataType: "json",
        success: function(data) {
           console.log(name);
        }
    })

用谷歌浏览器和IE浏览器打开,都获取不到json数据,控制台报错:

谷歌浏览器访问本地文件的跨域报错提示

二、什么是跨域?

1. 首先,什么是域?

协议、域名、端口这三者相同,视为同一个域。 所以,只要协议,域名,端口有一个不同,就是跨域。

2. 为什么浏览器会报跨域的错?

这是因为浏览器有一个安全机制,叫做 同源策略(CROS),不同域的客户端脚本在无明确授权的情况下,是不能读取对方资源的。它保证了一个域的脚本只能读写本域内的资源,而无法访问其他域的资源。 所以,可以说跨域就是不同源。

但需要注意,并不是所有浏览器都用同源策略,比如火狐浏览器,就允许跨域。而且,即使是谷歌浏览器,也可以通过浏览器设置项改成允许跨域。

3. 本地html页面读取本地json文件是跨域?

按照上面我们分析的跨域场景是:协议,域名,端口有一个不同。 但看起来本地页面html的地址,和本地json文件的地址是在同一个域的感觉:

代码语言:javascript
复制
file:///Z:/celine/test/jsonp/demo.html
file:///Z:/celine/test/jsonp/test.json

而实际上,让我们仔细看看谷歌浏览器的报错内容,就可以发现,跨源请求仅支持协议方案。 :http, data, chrome, chrome-extension, https.,不支持file协议。 (谷歌报错内容:Access to XMLHttpRequest at 'file:///Z:/celine/test/jsonp/test.json' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.

三、怎么解决跨域问题?

解决跨域目前有以下几种:

    1. 纯前端方式:采用JSONP;
    1. 后端配合方式:使用nginx反向代理;
    1. 小白选手方式:修改谷歌浏览器的配置;
    1. 本地调试方式:本地搭建一个服务。

针对这一次案例:本地脚本读取本地json文件。其实只要案例项目放到服务器中,避免掉使用file:///协议访问页面,就不是跨域了。

如果一定要在本地打开,要么是方案4-本地起一个服务;要么就是方案1-jsonp

此处我们着重看下怎么使用jsonp解决跨域。

四、JSONP方式解决跨域问题

1. 什么是jsonp?

JSONP是一种非正式传输协议,目的就是便于客户端使用数据。它的具体概念和优点,请查看参考文章3. 要注意区分jsonjsonp两个概念:

  • json : 是一种数据格式。
  • jsonp: 是一种数据调用方式。

JSONP方式具有一定的局限性:

  • 仅适用于GET请求;
  • 读取本地json文件的话,json文件里的数据要包含在一个函数名里(这个往后看就知道是什么意思了)。
1. 实现原理

我们知道,<script> 标签是不受同源策略的限制的,它可以载入任意地方的 JavaScript 文件,而并不要求同源(回忆下,我们可以通过<script> 载入官方服务器(或者cdn)上的一些库文件,比如jq库文件或者boostrap库文件)。 所以,我们可以利用<script> 标签的这个特点,用它来载入json文件。

载入json文件后,我们还需要获取到文件里面的json数据,这时候我们可以借用函数调用方式,把json数据作为函数实参,从而在js代码中取到数据。

2. 实现步骤

step1: 定义一个函数getJson(),这个函数将会在.json文件里被调用,得到json数据。可以在函数内部对json数据处理。

step2: 通过<script>标签引入test.json文件。

step3: test.json文件中,要把json数据作为实参放在函数getJson()中,即调用函数。

代码语言:javascript
复制
<!-- demo.html -->

<script type="text/javascript">
// 1. 定义接收数据的函数
    function getJson(data){
                // data 就是要取的json数据
        console.log(data);
        alert(data.name);
                
              // 可以在函数内部对json数据进行处理
    }
</script>

<!-- 2. 引入json文件 -->
<script type="text/javascript" src="test.json"></script>
代码语言:javascript
复制
// test.json

// 3. 真正json数据需要放在函数getJson()里,相当于作为调用函数getJson的实参。
getJson({
    "name": "celine",
    "nickName": "bling",
    "likes": [
        {
            "name": "Alex",
            "age": "18"
        },
        {
            "name": "Didi",
            "age": "9"
        }
    ]
})

网络上有些提到在引入json文件时候,需要在链接后面加上回调函数,如下:

代码语言:javascript
复制
<script type="text/javascript" src="test.json?callback=getJson">

这种一般是向服务器请求json文件时,允许客户端传递一个callback参数(此处就是getJson)给服务端,然后服务端返回数据时会将这个callback参数(即getJson)作为函数名来包裹住JSON数据,这样客户端就可以随意定义自己的函数来处理返回数据了。——这也是JSONP协议的要点。 也就是说,json文件不需要手动去给它包裹上一个函数名了(即不需要上面的step3,这个步骤由后端返回数据时完成)。

五、结语

以上就是一个jsonp方式解决跨域问题的方案。 但这种需要去修改json文件里面的原始数据结构,其实也不是很好。 希望有更好方案,小伙伴可以积极提供。

思考:vue-cli项目中,因为有一个本地服务器概念,如果使用axios去请求json文件,不知道是不是就没有跨域问题了。有待尝试! 甚至有可能直接用import或者require就可以获取到呢?

参考文章:

  1. 谷歌通过ajax获取本地JSON文件,为什么会提示跨域? 杂糅了一大堆的资料,后面的例子反而不是和清晰了。
  2. 解决ajax不能访问本地文件(利用js跨域原理) 通过截图,很清晰说明了jsonp应用过程。
  3. jsonp 读取本地文件 这篇的主要贡献是:介绍了jsonp的概念、提出jsonp的有点,与ajax的区别。很建议一读!
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、我是怎么遇到跨域问题的?
  • 二、什么是跨域?
    • 1. 首先,什么是域?
      • 2. 为什么浏览器会报跨域的错?
        • 3. 本地html页面读取本地json文件是跨域?
        • 三、怎么解决跨域问题?
        • 四、JSONP方式解决跨域问题
          • 1. 什么是jsonp?
            • 1. 实现原理
              • 2. 实现步骤
              • 五、结语
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档