从浏览器到服务器的4种跨域请求解决方案

Author Avatar
tangdaohai 6月 14, 2017
  • 在其它设备中阅读本文章

现如今前端一日一变化, 各种招式犹如万花齐放, 蜂拥而至。对于前后端分离更是人们热衷追求的, 或者多个服务API等架构, 随之而来的就是因浏览器同源策略而导致的跨域问题。那我们要摆好正确姿势去搞定她咯。

1. 利用img.src

如果只是想发送请求到服务器, 并不关心response。那这种方式再适合不过了。

比如发送log到服务器:

1
new Image().src = 'http://myweb.com/log?content=test'

当img标签src属性的一改变, 浏览器将立即发出请求, 方便至极。

所有带有src属性的html元素都可以实现这种模式, 如: script、link 表签。 但他们需要添加到dom树上才会发出请求, 没有img来得方便。

这种方法服务器端无须做任何改动。
缺点就是只能发送GET请求, 对传输大小有限制。

2. JSONP

原理便是利用script标签, 在js文件请求完毕之后, 浏览器会立即编译并执行其中的js代码。因为在发出请求之前, 我们已经提前在浏览器端声明回调函数, 当js请求完毕, 便执行了回调函数, 将想要得内容传递给了回调函数。实际上服务器端只是将返回的内容组装成了一段js代码。

浏览器端:

1
2
3
4
5
//先声明一个函数
function myCallback(data){
console.log(data);
//do something...
}

服务器端:

1
2
3
4
//服务器端需要将返回内容包裹一下

//下面是response body的内容(node koa 框架举例)
ctx.body = 'myCallback(' + '要传递的数据' + ')'; //这里的myCallback是从参数 callback 获取的, 当然也可以提前声明好

发起请求:

1
2
3
var scriptTag = document.createElement('script');
scriptTag.src = 'http://localhost/a=参数1&callback=myCallback' //这里的callback的参数便是提前声明好的回调函数名称
document.body.appendChild(scriptTag)

完成这三步之后, 当请求返回后, scriptTag中的代码便是服务器返回的'myCallback(' + '要传递的数据' + ')' 浏览器解析运行之后, myCallback函数便被执行了, 我们想要的参数也就获取到了。

缺点同样是只能发送GET请求, 对传输大小有限制。需要服务器端配置callback。

注意! JSONP跟ajax半毛钱关系都没有。JSONP发出的请求是不可以被abort掉的, 一旦发出只能等待结果回来。

3. WebSocket 跨域

webscoket的连接方式不受浏览器同源策略的影响, 所以可以直接在浏览器与服务器保持长连, 达到跨域请求数据的目的。

连接并通信:

1
2
3
4
5
6
7
8
9
10
11
12
// 创建连接
var socket = new WebSocket('ws://localhost:8080'); // 这里的域名不受同源策略限制

// 发送
socket.addEventListener('open', function (event) {
socket.send('Hello Server!');
});

// 接收
socket.addEventListener('message', function (event) {
console.log('Message from server', event.data);
});

如果服务器端使用了socket.io, 那直接在浏览器端引入socket.io js,进行与服务器的连接即可. 代码示例此处不再贴出.具体可看socket.io官网实例

个人比较喜欢webSocket, 尤其是与SPA页面一起使用, 一个长连搞定所有请求, 效率可观。
但WebSocket 还处于试验阶段, 所以在浏览器兼容上可能需要注意一下。
不过无需质疑, WebSocket必将成为趋势!

4. CORS

目前最标准的跨域姿势, 已被列入W3C标准。

使用CORS需要浏览器与服务器共同配置一下, 不过大部分浏览器都已支持了此标准(IE10以下除外), 在发起请求时浏览器会在header中加入origin字段, 自动设置为当前的域名。服务器需要手动配置一下, 需要在response header中加入Access-Control-Allow-Origin, 其值可设置为* 或者运行的域名,也就是只可以允许一个或者全部!

使用CORS之后, 请求method也就不只局限于GET了, 请求内容过大的时候改为POST也无须担心请求串被截断了。

关于CORS的具体内容可详见MDN文档:

HTTP访问控制(CORS)

5. 其他

以上4种方式是比较常用、规范的方式, 当然也有一些奇巧淫技, 比如利用iframe与postMessage配合使用, 但局限性很大, 使用起来也不顺手, 性价比不高。

本文简单的对几种跨域方式做了一个简单的概述, 没有打算对每种方式进行长篇大论的细细描述, 如果不足, 欢迎补充。

以上, 致那颗骚动的心……