前后端分离实现,后端基于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请求也是浏览器自动帮我们发起的,这个不用过问。还是暗中正常的代码编写步骤写即可!