Lumen 跨域问题解决

跨域

什么是跨域?为何会出现跨域问题?

首先了解一下什么叫做域?简单的定义就是 协议、域名、端口都相同叫做域,缺一不可,还有这里的域并不是单指域名。出于安全考虑,浏览器规定了一种同源策略。这里的源可以理解为域。
同源策略 的产生是处于安全考虑的。我们都知道,以 Http 协议为例,Http 协议是无状态的,所以我们为了保留某些用户的信息采用了 Cookie 方法,现在的 H5 还有 LocalStorage 。设想一下如果你登录了我的博客,必然会在头部信息中带有登录 Cookie 信息,如果没有同源策略的话,你访问其他其他网站的时候就会带上 cookie 信息,访问对方是恶意网站的话,该恶意网站可以通过访问我博客的接口完全获取你的 个人信息或者修改你的信息。

现实中还是需要突破这个策略需求的,所以 W3C 制定了 CORS 标准,全称是”跨域资源共享”(Cross-origin resource sharing)。

跨域请求共享

目前主流浏览器都是支持 CORS 标准的,所以当你进行跨域请求的时候,浏览器会自动完成整个过程。但是服务器端并不会,所以需要的解决的就是服务器端的问题。这里还有一点注意的就是浏览器会多发出一次 OPTIONS 请求,这个称作预检,用以判断实际发送的请求是否安全,服务端是不需要理会的。

两种请求

简单请求
1
2
3
4
5
6
7
8
9
10
1. 请求方法是以下三种方法之一:
1. get
2. post
3. head
2. HTTP 的头信息不超出以下几种字段:
1. Accept
2. Accept-Language
3. Content-Language
4. Last-Event-ID
5. Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

满足以上两种条件的都称之为简单请求,其他的则是非简单请求。浏览器对于这种请求的处理方式也是不一样的。

简单请求响应

对于简单请求,浏览器发出跨域请求的时候,只会简单的在头部加上 Origin 字段,在 Origin 指定的域名服务器响应中,当然是允许跨域的服务器,会多出几个响应字段,都是以 Access-Control- 开头的字段。

Access-Control-Allow-Origin

该字段是必须的。它的值要么是请求时 Origin 字段的值,要么是一个 *,表示接受任意域名的请求。

Access-Control-Allow-Credentials

该字段可选。它的值是一个布尔值,表示是否允许发送 Cookie 。默认情况下,Cookie 不包括在 CORS 请求之中。设为 true,即表示服务器明确许可,Cookie 可以包含在请求中,一起发给服务器。这个值也只能设为 true,如果服务器不要浏览器发送 Cookie,删除该字段即可。

Access-Control-Expose-Headers

该字段可选CORS 请求时,XMLHttpRequest 对象的 getResponseHeader() 方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在 Access-Control-Expose-Headers 里面指定。

非简单请求

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是 PUTDELETE,或者 Content-Type 字段的类型是application/json
除了简单请求的 Origin 字段外,还有两个特殊的头信息字段:

Access-Control-Request-Method

该字段是必须的,用来列出浏览器的 CORS 请求会用到哪些 HTTP 方法,上例是 PUT

Access-Control-Request-Headers

该字段是一个逗号分隔的字符串,指定浏览器 CORS 请求会额外发送的头信息字段。

非简单请求响应

当服务器发出非简单请求的时候,服务段会响应一下几个头信息:

Access-Control-Allow-Methods

该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次”预检”请求。

Access-Control-Allow-Headers

如果浏览器请求包括 Access-Control-Request-Headers 字段,则 Access-Control-Allow-Headers 字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在”预检”中请求的字段。

Access-Control-Allow-Credentials

该字段与简单请求时的含义相同。

Access-Control-Max-Age

该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。

Lumen 处理跨域请求

回到标题的问题,如果来解决 Lumen 的跨域请求问题。了解 CORS 标准之后,如果你使用 Lumen 框架是基于 restful api 的话,就避免不了 PUTDELETE 请求。
需要建立一下几个响应字段

Access-Control-Allow-Origin: '*' // 允许的域名
Access-Control-Allow-Methods: '*' // 允许的方法
Access-Control-Allow-Headers: 'Content-Type, Authorization, X-Requested-With'
Access-Control-Max-Age: '' // 如果你不需要每次都要预请求的话可以添加该字段
1
2

建立一个 `CORS` 中间件文件:
namespace App\Http\Middleware; use Closure; class CorsMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $response = $next($request); $response->header('Access-Control-Allow-Origin', '*'); $response->header('Access-Control-Allow-Methods', '*'); $response->header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With'); return $response; } }
1
2

在 `boostrap\app.php` 文件加入中间件
$app->middleware([ App\Http\Middleware\CorsMiddleware::class, ]); ``` 这样就可以解决跨域问题了