前后端分离实现,后端基于SpringBoot开发,前端使用Jquery实现Ajax请求,测试中请求可以正常到达,但是在拦截器或者过滤器中总获取不到自定义请求头。解决方法如下,直接上代码。
网上文章总感觉缺点意思。。
前端代码
<script>
$.ajax({
// 地址根据本地定义
url:"",
type:"post",
dataType:"json",
headers:{
"token":"token check"
},
success:function (data){
console.log(data.message + "===")
},
error:function (xhr) {
console.log(xhr)
}
})
</script>
后端代码
过滤器,用于处理第一次的options请求,设置响应头
@WebFilter(filterName = "CodeFilter", urlPatterns = "/*")
public class CodeFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("filter");
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
response.setHeader("Access-control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type,token");
// 暴露token,这里一定要写,如果你的写法与我的相同,检查此行代码是否也添加了
response.setHeader("Access-Control-Expose-Headers", "token");
response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
if ("OPTIONS".equals(request.getMethod())) {
// 进行我们定义的请求前,浏览器自动发起的options请求
System.out.println("options");
// 服务器正常接收,返回状态码,不响应其他内容
response.setStatus(HttpStatus.ACCEPTED.value());
return;
} else {
// 非options请求,放行
chain.doFilter(request, response);
}
}
public void init(FilterConfig config) throws ServletException {
}
}
拦截器用于处理权限验证,并获取请求头
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取所有请求头,并遍历,此处代码可以去掉--开始
Enumeration<String> enumeration = request.getHeaderNames();
while (enumeration.hasMoreElements()){
System.out.println(enumeration.nextElement());
}
--- 结束
// 获取token------
String token = request.getHeader("token");
System.out.println(token + "======");
// 仅用于验证逻辑,都省掉
HttpSession session = request.getSession();
Object object = session.getAttribute("user");
if (null != object) {
return true;
} else {
// 响应数据测试
response.getOutputStream().print("{\"message\":\"abcdefg\"}");
return false;
}
}
}
提示:如果不想写过滤器,可以将过滤器的代码统一贴在拦截器中实现一样的
配置主程序
@SpringBootApplication
@ServletComponentScan(basePackages = {"com.cx.filter"})
public class MvBootApplication {
public static void main(String[] args) {
SpringApplication.run(MvBootApplication.class, args);
}
}
以上代码没看懂,继续看下去,看完后在回头看代码
IE chrome 等浏览器对于跨域请求设置自定义Headers参数的时候会进行 "预请求" ,该请求需要两步完成!
第一步:发送预请求 OPTIONS 请求。此时 服务器端需要对于OPTIONS请求作出响应,一般使用202响应即可,不用返回任何内容信息,如上面Filter中
response.setStatus(HttpStatus.ACCEPTED.value());
这便是可能遇到的问题请求成功了但是没有任何信息返回?因为你自定义的请求头在服务器响应中不存在!
第二步:服务器accepted 第一步请求后 浏览器自动执行第二步 发送真正的请求。
注意:如果这个地方还是没有看懂,再说一下,上面的代码Filter会执行2次,第一次执行Options请求,不在进行向后传递并返回202(服务器正常接收了请求),第二次执行我们发送的ajax(非Options)请求,进入拦截器,获取请求头信息,执行拦截器中的逻辑代码。第一次的options请求也是浏览器自动帮我们发起的,这个不用过问。还是暗中正常的代码编写步骤写即可!