跨域(Cross-Origin)初窥

同源策略

  1. 什么是同源?

    • 使用window.origin或者location.origin可以获得当前
    • 源:协议+域名+端口号
    • 如果协议、域名、端口号完全一致,那么就可以说这两个url是同源的。
  2. 同源策略

    • 浏览器规定如果JS运行在源A中,那么只能获取源A得数据,不能获取源B的数据,即不允许跨域
    • 这是浏览器故意设计的功能,目的是为了保护用户隐私

跨域

但是大多数时间,我们往往都需要进行跨域访问。

  1. CORS跨域

    跨源资源共享(CORS)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它源,使得浏览器允许这些源访问加载自己的资源。[1]

    整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。 因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。[2]

    我们在手动设置CORS时只需在服务器端添加:response.setHeader('Access-Control-Allow-Origin','*')。一般来说我们在设置源字段的时候都会填写一个域名,* 则代表可以接受所有域名的加载资源请求。

  2. JSONP跨域

    当我们无法使用CORS进行跨域时,可以考虑使用JSONP来进行跨域。

    JSONP的原理纯属套娃,其本质就是使用回调函数来进行一个的套。

    因为在HTML中,script的src属性本身是一个不会产生跨域的GET请求,我们可以通过定义一个全局回调函数,同时引用服务器端的js文件(文件中含有经过服务器端处理过的包含我们所需数据的同名函数),js在执行后,就是变相执行了我们一早就定义好的全局回调函数(因为他们是同名的),从而解决了我们的需求。这么说来可能有些拗口,可以参考以下过程:

    本地:

    1
    2
    3
    4
    
    //定义全局回调函数
    window.dataSource(data) =>{
        console.log(data)
    }
    

    服务器端:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    //将我们需要的数据装进一个js内,由其他人调用
    if (path === '/data.js'){
        response.statusCode = 200
        response.setHeader('Content-Type','text/javascript;charset=utf-8')
        //写所引用js内容,并字符串化
        const string = fs.readFileSync('./public/data.js').toString()
        //写所需数据内容,并字符串化
        const data = fs.readFileSync('./public/data.json').toString()
        //将所需数据替换占位符
        const dataSource = string.replace('{{data}}',data)
        //将数据写入data.js作为res
        response.write(dataSource)
        }
    
    1
    2
    3
    
    //data.js中
    //dataSource为同名函数
    window.dataSource({{data}})
    

    本地:

    1
    2
    3
    4
    
    //动态引入data.js
    const script = document.createElement('script')
    script.src = '.../data.js'
    document.body.appendChild(script)
    

    我们在本地引用data.js后,服务器端首先发现我们的请求,并将我们所需的内容写入data.js作为回应发送给我们。我们引用的是什么?如果弄清了上述流程,应该发现我们引用的是一句非常简单的window.dataSource(data)。而window.dataSource正是我们一开始定义在本地的一个函数!我们从移花接木地从服务器端拿来了我们需要的数据并执行,也就可以如愿以偿的console.log出我们需要的东西。

    可以说是顶级套娃🪆。