跨域

193 阅读2分钟

1.同源

如果两个url的协议、域名、端口号完全一致,那么这两个url就是同源的。

举例说明:

https://a.com
https://b.com
域名不同,两者不同源
https://a.com
http://a.com
协议不同,两者不同源
https://a.com
https://a.com:8848
端口号不同,两者不同源
https://a.com/index.html
https://a.com/detail.html
协议相同,域名相同,端口号相同(默认80),路径不同,两者同源

2.同源策略

浏览器规定,如果js运行在源A里,那么就只能获取源A的数据,不能获取源B的数据,既 不允许跨域。

同源策略的目的是为了保护用户的隐私。

3.跨域

突破浏览器同源策略的限制,让不同的源之间可以相互访问数据,就是跨域。

4.CORS 跨域

允许浏览器向跨源服务器发出XMLHttpRequest请求,克服了AJAX只能同源使用的限制。

  • CORS需要浏览器和服务器同时支持
  • 实现CORS通信的关键是服务器实现了CORS接口

简单请求:

(1)请求方法是以下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

过程:

  • 浏览器直接发出CORS请求,在头信息中增加一个Origin字段
Origin: http://api.bob.com
  • 如果Origin指定的源在服务器许可范围内,则增加响应头信息,实现跨域
response.setHeader('Access-Control-Allow-Origin','http://frank.com:9990')
  • 否则跨域失败

5.JSONP 跨域

当浏览器不支持CORS 跨域时,使用JSONP进行跨域。
举例说明:a.com要访问b.com中friends.json数据。

//b中文件: 
window["{{xxx}}"]({{data}})  //friends.js
[{ "name": "jack" }, { "name": "frank" }]  //friends.json
/////////////////////////////////////////////////////////////
//b后台程序
//server.js
else if (path === "/friends.js") {
    if (request.headers["referer"].indexOf("http://a.com:9999") === 0) {
      response.statusCode = 200;
      response.setHeader("Content-Type", "text/javascript;charset=utf-8");
      const string = fs.readFileSync("./public/friends.js").toString();
      const data = fs.readFileSync("./public/friends.json").toString();
      const string2 = string
        .replace("{{data}}", data)
        .replace("{{xxx}}", query.callback);
      response.write(string2);
      response.end();
//////////////////////////////////////////////////////////////////
//a中文件
//a.js
function jsonp(url){
    return new Promise((resolve,reject)=>{
        const random='frankcallbackname'+Math.random()
        window[random]=(data)=>{
            resolve(data)
        }
        const script=document.createElement('script')
        script.src=`${url}?callback=${random}`
        script.onload=()=>{
            script.remove()
        }
        script.onerror=()=>{
            reject()
        }
        console.log(script)
        document.body.appendChild(script)
    })
}

过程:

  • a.js定义回调函数,函数名为一随机数,并定义script标签引用friends.js
  • b后台程序处理请求,将随机数替换为函数名,friends.json数据替换data
  • friends.js执行回调函数'window["{{xxx}}"]{{data}}'
  • 请求成功,调用then方法,执行成功函数,得到数据

JSONP 跨域缺点

  • 不支持post只支持get
  • 调用失败的时不返回HTTP状态码和Header

JSONP 跨域优点

  • 兼容IE
  • 可以实现跨域