跨域

150 阅读2分钟

源=协议+域名+端口(默认端口80) window.originlocation.origin可以查询源 同源策略 浏览器规定,只有同源之间才能相互访问数据,即源的三者必须完全一致。注意,与子域名间非同源。否则浏览器会拦截。IE有特例:

  • 授信范围(Trust Zones):两个相互之间高度互信的域名,如公司域名(corporate domains),则不受同源策略限制。
  • 端口:IE 未将端口号纳入到同源策略的检查。

跨域

跨域就是不同源之间的操作,而浏览器会限制数据读操作(cross-origin-read),但允许跨域写操作(Cross-origin writes),如链接;允许跨域资源嵌入(cross-origin-empedding),如script标签、img标签等

跨域方法

CORS(CrossOriginResourceSharing)是HTTP的一部分。服务端设置响应头.方法一直接方便。但是IE9以下不支持

response.setHeader('Access-Control-Allow-Origin', 'http://deibo.com:9999')

JSONP.由于浏览器允许跨域资源嵌入,所以利用script标签。流程是请求方利用script标签请求数据方,数据方拿到查询参数中的函数名(callback),而后回调该函数把序列化的数据作为参数传入。

他的优点是:兼容IE,实现了跨域.缺点是:由于是script标签的引用所以不能发POST请求,而且拿不到状态码,响应头

请求方:

function jsonp(url) {
   return new Promise((resolve, reject) => {
       const random = Math.random()//  获得一个随机数的函数名
       window[random] = (data) => {
           resolve(data)
       }
       const script = document.createElement('script')
       script.src = url + `?callback=${random}`//  查询参数中把函数名传过去,利用回调的方式获得数据,这里约定了functionName为callback
       document.body.appendChild(script)
       script.onload = () => {
           script.remove()
       }
       script.onerror = () => {
           reject()
       }
   })
}

   jsonp('http://qq.com:8888/data.js')
       .then((data) => { console.log(data); }, () => { console.log('失败了'); })

数据方:

if (path === '/data.js') {
        if (request.headers.referer.indexOf('http://deibo.com:9999/') === 0) {//  检查请求头的referer
            response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
            response.statusCode = 200
            const callback = query.callback//  找到请求路径的查询参数中的函数名
            let data = fs.readFileSync('db/friends.json').toString()
            let string = 'window["{{xxx}}"]({{data}})'
            let string2 = string.replace('{{data}}', data)//  把js文件预留占位符替换成数据
            let string3 = string2.replace('{{xxx}}', callback)//  把js文件的函数名换成请求穿过来的随机数函数名
            response.write(string3)
        } else {
            response.statusCode = 404
        }
        response.end()
    }