持续更新地址:http://jaylin.wang/2017/cross...html
跨域HTTP请求是指当前文档访问其余源提供的资源。两个页面具备相同的协议,域名和端口,则两个页面属于相同的源,不一样子域名之间也属于不一样的源。这是浏览器端的同源策略的约束,同源策略则是浏览器隔离潜在恶意文件的安全机制。git
目前经常使用的跨域解决方案有EmbedPing、JSONP、CORS。github
跨域限制是浏览器的一种行为ajax
当咱们在浏览器的一个页面中尝试进行一次跨域操做,好比咱们在 localhost 的一个页面经过 ajax 访问 127.0.0.1 的一个路由,127.0.0.1已经将数据返回给浏览器,浏览器禁止了获取响应数据行为。咱们能够看一张图:json
跨域请求的几种方式跨域
跨域写
浏览器始终支持经过跨域写操做。例如经过表单提交方式向其余源提交数据,点击连接重定向到其余源。浏览器
跨域嵌入
浏览器始终支持跨域资源的嵌入。例如经过 img、script、video 等元素的 src 属性嵌入跨域资源。缓存
跨域读安全
这是我本身瞎取的一个名字,大体是利用浏览器支持标签嵌入跨域属性实现的一种方案。img、script、link[rel='stylesheet']会在页面渲染过程当中请求其src/href设置的资源地址,咱们能够在访问的路由中作处理。例如使用img的src属性:服务器
<script> var img = new Image() img.src = 'http://localhost:4000/check' </script>
由于没法获取到服务端返回的数据,EmbedPing是浏览器向服务器单向请求的过程。
咱们可使用 EmbedPing 作一些不严格统计。
JSONP也利用了 script 标签的 src 属性,浏览器会执行加载成功后的js。JSONP的局限是只能发送一个GET请求。
应用示例
看一个简单示例,咱们但愿在当前域的页面上打印服务器的一个状态,咱们使用JSONP能够这样实现,前能够看一段简单代码(服务端使用koa构建的):
当前域属于 http://localhost:3000
,咱们在页面上这请求
<body> <script> var script = document.createElement('script') script.src = 'http://localhost:4000/jsonp/run' script.async = true document.body.appendChild(script) </script> </body>
在 http://localhost:4000/jsonp/run
中,咱们返回了一段打印状态的script
var valForServerB = 'a' router.get('/jsonp/run', (ctx) => { let script = ` alert('我来自服务器b,个人值是${valForServerB}') ` ctx.body = script })
这样,咱们能够在当前页面上显示 valForServerB
的值了。
几种类型
根据 JSONP 返回的代码片断不一样,混入本身的情感,我将 JSONP 分为三种类型(这种带着情感的划分,须要各位大牛的指正):
返回执行
返回代码即执行代码,直接在页面上产生效果
返回定义
返回代码是函数的定义,具体调用时机交给当前页面决定
返回调用
函数的执行过程是在页面上所定义的,JSONP的返回只是函数的调用,固然包含传给函数的参数。
为了保持当前页面的的绝对控制权,返回调用应该是应用最广的
错误处理
JSONP使用过程当中,会有两种常见错误:
请求失败或服务器返回失败
捕获此类错误,咱们是借用 script 的 onerror 处理
服务器返回内容错误
针对这类错误,咱们会在当前页面借用定时器去处理。在返回调用时,咱们能够在页面上的函数定义中埋下时间因子;在返回定义时,咱们能够设置时间点去检测指望调用的方法是否存在。固然,此方法会由于网络等因素变得不可靠。
CORS是当前页面与其余域执行的一种双方约束,须要浏览器应用和服务器程序之间的协调。
咱们在服务器端能够经过设置CORS响应头部:
Access-Control-Allow-Origin: <origin> | *
容许访问的源
Access-Control-Allow-Methods
容许访问的方法
Access-Control-Allow-Headers
运行添加的请求头部
Access-Control-Expose-Headers
容许客户端能够访问的头部
Access-Control-Max-Age
预请求的缓存周期
Access-Control-Allow-Credentials
是否运行请求加入用户凭证信息
相应的,在请求头部中,咱们能够加入:
Origin
告知服务器请求的源
Access-Control-Request-Method
告知服务器使用请求的的方法
Access-Control-Request-Headers
告知服务器,请求中携带的头部
跨域请求好,安全第一位。在咱们跨域请求时,咱们要确保咱们请求的服务器返回的数据是可信任的。