前后端分离之跨域请求及cookie接收发送
解决思路:
使用CORS解决不同源前后端之间数据访问,和cookies-session共享(即允许前端在发送请求的时候带上本域名下的cookie访问另一个域名下的后端服务器,后端服务器允许指定域名发送cookie和接收cookie).要想实现前后端跨域,不管是在前端还是在后端都必须进行配置
什么是CORS
CORS是一个w3c标准,全称是"跨域资源共享"(Cross-origin resource sharing),但一个请求url的协议,域名,端口三者之间任意与当前页面地址不同即为跨域.它允许阅览器向跨源服务器发送XMLHttpRequest请求,从而客服AJAX只能同源使用的限制.
浏览器默认的安全限制为同源策略,即JavaScript或Cookie只能访问同源(相同协议,相同域名,相同端口)下的内容。但由于跨域访问资源需要,出现了CORS机制,这种机制让web服务器能跨站访问控制,使跨站数据传输更安全。CORS需要阅览器和服务器同时支持,目前,主流的浏览器都支持cors。
CORS的2种请求方式
- 简单请求
(1) 请求方法是以下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
不同时满足上面两个条件,就是非简单请求,简单请求
当进行跨域请求的时候,浏览器会自动在请求中添加Origin头部(值为:请求域名),表示这个请求是一个跨域请求
2. 非简单请求
不满足简单请求的条件就是非简单请求.
非简单请求相比于简单请求,需要在请求前主动请求一次Http查询请求,又称预检请求。
浏览器先请求服务器,当前网页所在域名是否在服务器许可名单中以及可以使用那些HTTP动词和头信息字段,当客户端得到肯定答复时,浏览器才会正式发出正式请求。
预检请求用的请求方法是OPTIONS,表示这个请求是用来询问的。
当服务其收到预检请求后,检查了Origin,Access-Control-Request-Method等信息字段后,如果没有问题,则确认允许跨源请求,就可以做出了回应。
上图为预检请求后返回的头部信息,详细说明服务器允许那些域名允许跨域,浏览器接收之后解除跨域访问限制
服务器端跨域处理流程
1. 首先查看http头部有无origin字段;
2. 如果没有,或者不允许,当成普通请求;
3. 如果有且是允许的,再看是否是preflight(method=OPTIONS);
4. 如果不是preflight(简单请求),返回Allow-Origin,Allow-Credential等字段,并返回正常内容;
5. 如果是preflight(非简单请求),返回Allow-Headers,Allow-Methods等;
解决跨域的代码实现
1. 后端配置代码
这里使用的是springmvc拦截器,对所有服务端的响应添加头部信息
// 拦截器类
public class CrossdomainInterceptor implements HandlerInterceptor {
// 在执行Controller方法之后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
// 在执行Controller方法前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpServletResponse resp = (HttpServletResponse) response;
HttpServletRequest rep = (HttpServletRequest) request;
// 设置允许跨域的网站域名
resp.addHeader("Access-Control-Allow-Origin", rep.getHeader("Origin"));
// 允许跨域请求中携带cookie
resp.addHeader("Access-Control-Allow-Credentials", "true");
// 如果存在自定义的header参数,需要在此处添加,逗号分隔,允许跨域时带上的自定义头部
resp.addHeader("Access-Control-Allow-Headers", "authorization,Origin, No-Cache, X-Requested-With, "
+ "If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, " + "Content-Type, X-E4M-With");
// 允许的跨域请求方法
resp.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS,DELETE,PUT,");
// 测试拦截器是否执行
System.out.println("拦截器执行");
return true;
}
}
springmvc.xml 配置文件
<mvc:interceptors>
<!--第一个拦截器-->
<mvc:interceptor>
<!--要拦截的Controller方法-->
<!--<mvc:mapping path="/**"/>表示所有方法都拦截-->
<!--<mvc:mapping path="/users/*"/>表示只拦截users下的路径-->
<mvc:mapping path="/**"/>
<bean class="cn.luntan.ssm.interceptor.CrossdomainInterceptor"></bean>
<!--表示不拦截那个地址-->
<!-- <mvc:exclude-mapping path=""/>-->
</mvc:interceptor>
</mvc:interceptors>
2. 前端配置代码
前端使用vue脚手架
// 在main.js中添加如下代码,作用是允许请求时携带本域cookie和接收不同源服务器发送的cookie
axios.defaults.withCredentials=true;
jquery ajax解决跨域发送cookie
$.ajax({
type: 'post',
url: "http://localhost:8080/post/secondcom",
data: JSON.stringify(data),
// dataType: 'jsonp',
xhrFields: {
withCredentials: true
},
crossDomain: true,
contentType: "application/json",
success: function (data) {
if (data) {
alert("评论成功");
} else {
alert("评论失败")
}
}
})
将代码加入之后就可以前后端的资源访问了,快去试试吧