HTTP访问控制CORS详解

手机wap前端开发标准
前端手机开发手指按下抬起事件
手机前端开发

一丶概述

最近小组做的项目中,前后端需要跨域通信,本打算直接使用jsonp来实现。但是这对前后端代码改动有点大,而且jsonp仅支持get请求。最后决定使用CORS的方式来实现,过程中各种的坑啊。这里为大家介绍下CORS及各种遇到的问题解决方案。

二丶什么是CORS

CORS是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制。使用CORS,可以通过普通的XMLHttpRequest发起请求和获得数据,并且支持各种类型请求。说白了就是利用XMLHttpRequest来实现跨站通信,而不是仅仅遵循同源策略,再也不用为了ajax能跨域写苦逼的jsonp了。  CORS技术现在已经被广泛的支持了。    

三丶CORS使用方法及场景举例

所谓的跨域请求,从本质上来说并不是浏览器对其他域名的请求不能发送,而是请求可以正常发起,但是浏览器在收到服务器信息后就屏蔽掉了,并向前端报错(跨域)。如图所示,跨域请求结果被屏蔽。  

解决方案,服务器在响应HTTP头部加入 **Access-Control-Allow-Origin:***即可,这样就表示服务端同意任意域名的请求。一般我们会指定可响应的域名如:Access-Control-Allow-Origin: http://b.com, http://c.com 等。这样浏览器在检测到服务端HTTP头部的时候就可以不再拦截响应。 请求头部: 响应头部: 就在我们以为轻松搞定的时候,我们又遇到了问题。前端要给后端传json格式的数据于是在http头部加入了 content-type: application/json, access_token等信息。请求再次失败,通过观察控制台信息我们发现,多了一个请求options: 原来在CORS中的请求分为两种:简单请求和复杂请求
 ####简单请求:  
 1. 只使用**GET**,**HEAD**或者**POST**。如果使用POST来发送数据到服务器,那么使用HTTP POST请求发送到服务器的数据的Content-Type为以下几种之一:**application/x-www-form-urlencoded**,**multipart/form-data**以及**text/plain**。  
 2. 不使用HTTP请求发送定制请求头(例如X-Modified等)
 在简单请求下,我们只需要像上面所说设置Access-Control-Allow-Origin头部即可。

 ####复杂请求  
 1. 使用了除**GET**,**HEAD**和**POST**以外的方法。如果使用POST方法发送请求数据时的Content-Type不是application/x-www-form-urlencoded,multipart/form-data或者text/plaint。例如,如果POST请求向服务器使用application/xml或者text/xml向服务器发送请求,那么这个请求就是preflighted的。
 2. 设置了定制请求头的请求(例如,请求使用了例如X-PINGOTHER这样的请求头)  
这类请求在发送正式请求之前会发送一个**Preflighted(预请求)**,**Preflighted**请求首先通过HTTP **OPTIONS**方法请求其他域上的资源,以确定发送实际的请求是否安全。这样做,是因为跨站请求可能会对目的站点的数据造成破坏。我们第二次发的请求是一个复杂请求,服务端没有响应options的方法,导致预请求失败,之后的请求也就终止了。我们看一下复杂请求下的HTTP报文。
Prelignted请求头部:  

可以看到报文头部信息为OPTIONS请求 预请求服务端响应报文

预请求响应只要返回一个2xx表示成功的响应信息即可说明服务端同意了跨域请求,这里我们选择204的状态码作为响应状态。因为204表示响应成功,并且没有结果返回的状态。这样节省了传输信息的事件,加快了预请求的处理。
预处理结束后,事情并没有就此解决。错误信息再次传来。

原来我们自定义了头部信息,还要在响应报文中加入Access-Control-Allow-Headers来指出服务端允许的复杂请求需要的自定义头部信息。注意这里不能用*来表示所有,只能一个个添加。例如:“Access-Control-Allow-Methods” : “PUT,POST,GET,DELETE,OPTIONS”。这样就齐活了,总算是数据可以流通了。这里我建议在服务端响应部分也加入 “Access-Control-Allow-Methods” : “PUT,POST,GET,DELETE,OPTIONS”来指出可接受的请求类型。
最后我们的服务端响应头部信息:

别急我们还没有结束

####附带凭证信息的请求
我手贱的在xhr中加入了  **xhr.withCredentials = true**  因为跨源请求默认请求头部中不提供凭据(cookie、HTTP认证及客户端SSL证明等)。为了能把这些信息带上,我们设置了withCredentials为true。浏览器再次报错,通过检查我们发现,如果你设置了withCredentials为true那么 **Access-Control-Allow-Origin**就不能用** *** ,必须使用明确的域名。而且还要为你的响应头加上**"Access-Control-Allow-Credentials":"true"**信息。  

 最后我列出CORS中可能使用的头部信息供大家参考:
** HTTP响应头**:**Access-Control-Allow-Origin**,**Access-Control-Expose-Headers**,**Access-Control-Max-Age**,**Access-Control-Allow-Credentials**,**Access-Control-Allow-Methods**,**Access-Control-Allow-Headers**  
**HTTP请求头**:**Origin**,**Access-Control-Request-Method**,**Access-Control-Request-Headers** 

附上用node.js跨域请求服务端的简单配置  
**javascript 代码**
const express = require(‘express’),
    app = express()
//统一拦截请求设置头部信息,响应预请求
app.all(‘*’, function(req, res, next) {
    res.set({
        ‘Access-Control-Allow-Origin’: ‘*’,
        ‘Access-Control-Allow-Headers’: ‘Content-Type,access_token,user_id’,
        ‘Access-Control-Allow-Methods’: ‘PUT,POST,GET,DELETE,OPTIONS’,
    })
    if (req.method == ‘OPTIONS’) {
        res.send(204)
    } else {
        next()
    }
})
app.post(‘/data’, function(req, res) {
    res.json({
        status: ‘success’,
        text: ‘返回数据’,
    })
})
app.listen(3000, ‘127.0.0.1’, function() {
    console.log(‘服务器启动了’)
})

四丶跨域请求的其他方案

这里列举一下其他常用的跨域方案,仅供参考。  
  1.** jsonp**:利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。  
  2. **postMessage**:postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。  
  3. **websocket**:WebSocket实现了全双工通信,使web上的真正的实时通信成为可能。浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。  
  4. **SSE**:Server-Sent Events(SSE)功能,允许服务端推送数据到客户端(通常叫数据推送)。已经在浏览器上普遍支持,然而IE和Edge全系列不支持。
  5. **ServiceWorker**:一个 service worker 是一段运行在浏览器后台进程里的脚本,它独立于当前页面,提供了那些不需要与web页面交互的功能在网页背后悄悄执行的能力。在将来,基于它可以实现消息推送,静默更新以及地理围栏等服务,但是目前它首先要具备的功能是拦截和处理网络请求,包括可编程的响应缓存管理。简而言之,这是让浏览器具有服务器功能的API,有了他还跨域个球球。不过这只是实验中API目前只有chrome和firfox高版本浏览器支持。   
前端开发监听手机调试
手机站前端开发
前端开发 手机适配
赞(0)
前端开发者 » HTTP访问控制CORS详解
64K

评论 抢沙发

评论前必须登录!