在使用axios进行post方法时遇到的一个跨域问题记录

191 阅读3分钟

axios跨域post问题

先看看我的代码(多余部分省略)

前端代码:

// 跨域请求后端,发送JSON对象          
this.$axios.post("/getDataByConfigInfo",{
	tableCode:this.tableCode,
    xCoordinateRange:this.dateRange,
    classification:this.classification,
    attributes:this.checkedAttributes        
}).then(Response=>{
    console.log(Response.data);
})

后端代码:

    @CrossOrigin
    @RequestMapping(value = "/getDataByConfigInfo",method = RequestMethod.POST)
    public List<Object> getDataByConfigInfo(@RequestBody ForSearch forSearch){
        System.out.println(forSearch.toString());
        // 省略剩余部分代码
        return data;
    }

由于需要提交JSON对象,则需要通过post的方式利用axios向后端发送json对象,但是前端报错,提示跨域错误,可是在使用axios进行get时却没有问题

原因:

在执行跨域请求时,具体的请求会被分为两种:简单请求和非简单请求

简单请求需要同时满足两个条件:

  1. 请求方法是以下三种方法之一:GET POST HEAD
  2. Http的头信息不超出以下几种字段:Accept Accept-Language Content-Language Last-Event-ID Content-Type 只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

由于我的方法是post并且向后端发送的是JSON,所以后端的当前请求被归为非简单请求

以下部分为关键

浏览器对这两种请求的处理是不一样的.

如果是简单请求的话,一次完整的请求过程是不需要服务端预检的,直接响应回客户端,而非简单请求则浏览器会在发送真正请求之前先用OPTIONS发送一次预检请求preflight request,从而获知服务端是否允许该跨域请求,当服务器确认允许之后,才会发起真正的请求.那么前面所出现的异常很明显就是由这个preflight request导致的了,回头看代码可发现我们在发起ajax调用时往请求头里面塞了两个自定义的header参数token和device,所以此次调用属于非简单请求,并触发了一次预检请求,由于我们服务端使用了shiro权限认证框架,通过拦截用户请求头中传过来的token信息来判定客户端是否为非法调用,而Preflight请求过程中并不会携带我们自定义的token信息到服务器,这样服务器校验就永远也无法通过了,就算是合法的登录用户也会被拦截.

解决办法:在后端检测到该请求为预检请求时,不让它继续往下走(也可以返回一个2xx的状态码),直接告诉浏览器此次跨域请求可以继续,很明显过滤器符合我们的要求,我们来把之前的addCorsMappings方法去掉,重写这块代码

在SpringBoot启动类上加入一下部分即可

@SpringBootApplication  
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);  
    }
    @Bean
    public FilterRegistrationBean registration(){
        return new FilterRegistrationBean(new Filter() {
            public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
                    throws IOException, ServletException {
                HttpServletRequest request = (HttpServletRequest) req;
                HttpServletResponse response = (HttpServletResponse) res;
                String method = request.getMethod();
                // this origin value could just as easily have come from a database
                response.setHeader("Access-Control-Allow-Origin", "*");
                response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS");
                response.setHeader("Access-Control-Max-Age", "3600");
                response.setHeader("Access-Control-Allow-Credentials", "true");
                response.setHeader("Access-Control-Allow-Headers", "Accept, Origin, X-Requested-With, Content-Type,Last-Modified,device,token");
                if ("OPTIONS".equals(method)) {//检测是options方法则直接返回200
                    response.setStatus(HttpStatus.OK.value());
                } else {
                    chain.doFilter(req, res);
                }
            }
            public void init(FilterConfig filterConfig) {
            }
            public void destroy() {
            }
        });
    }

}

本文部分摘自Briseis大佬的文章,以下为原文链接

作者:Briseis 链接:www.jianshu.com/p/1ad4358be… 来源:简书