React:快速上手(8)——前后端分离的跨域访问与会话保持
React:快速上手(8)——前后端分离的跨域访问与会话保持
跨域访问
跨域是指从一个域名的网页去请求另一个域名的资源。比如从http://www.baidu.com/ 页面去请求http://www.google.com 的资源。跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不同,就被当作是跨域。
如下,域名相同的情况下,3000端口的应用无法直接访问8080端口的服务。
跨域资源共享CORS
它允许浏览器向跨源服务器,发出XMLHttpRequest
请求,从而克服了AJAX只能同源使用的限制。CORS需要浏览器与服务器的双向支持。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
在简单的跨域Ajax请求中,会在头部信息中添加Origin参数用于表面这个请求来自哪里,如下
如果Origin
指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin
字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest
的onerror
回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。
如果Origin
指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段,如下:
其中,几个重要的头信息如下:
- Access-Control-Allow-Origin:该字段是必须的。它的值要么是请求时
Origin
字段的值,要么是一个*
,表示接受任意域名的请求。 - Access-Control-Allow-Credentials:该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为
true
,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true
,如果服务器不要浏览器发送Cookie,删除该字段即可。
服务器端的处理
如上所述,CORS请求的关键是在后端,即将Origin添加到服务器的许可范围内。在SpringBoot应用中,我们可以编写一个拦截器,来实现:
@Component
public class CorsInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, If-Modified-Since");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
这里直接允许了所有源,在实际开发中,必须指定可信范围的源。
客户端处理
对于使用creat-react-app构建的项目,可以直接在package.json下配置,具体如下
{ "name": "recommender", "version": "0.1.0", "private": true, "proxy": "http://代理地址", "dependencies": { "antd": "^3.23.3", ... }, }
会话保持
CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials为true
。另一方面,开发者必须在AJAX请求中打开withCredentials
属性。
在Axios中,可以简单设置如下:
import axios from 'axios'
//方法1
axios.defaults.withCredentials =true;
//方法2
let config = {headers: {'Content-Type': 'multipart-/form-data'},withCredentials: true};
axios.post("http://127.0.0.1:8080/get.do", null, config).then((response) => {alert(response.data)})
服务端的处理,我们已经在上述代码中实现了,即
response.addHeader("Access-Control-Allow-Credentials", "true");
至此,前后端分离项目即可完成跨域访问与会话保持!