从前后端的角度分析options预检请求——打破前后端联调的理解障碍

Posted 砖业洋__

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从前后端的角度分析options预检请求——打破前后端联调的理解障碍相关的知识,希望对你有一定的参考价值。

1.从前端的角度看options

  options请求是浏览器的一个机制,不是前端开发人员说不想发options请求就不发的。当你这个post请求跨域的时候,那options请求就出现了(当然还有putdelete请求也会发送预检请求,这些比较少见,在这里我就只谈post)。options请求就去问问浏览器,我想跨域okok?如果后端设置了允许该域名跨域,那么接着post请求就正常发送。否则你就会在控制台看到该请求跨域的错误,类似于下面这种

  就这么简单,一句话概括:当跨域的时候,post请求之前浏览器就会提前发送options请求,就是询问服务器我能否顺利发送跨域post请求,如果不能,浏览器Console就看到跨域错误提示,如果能,post请求就顺利发送。


  后端配置跨域后,options请求发到服务器,服务器就会返回,但是没有response data,你可以当作是浏览器和服务器的悄悄的对话,不是前端开发人员手动控制的,因为options也不会命中后端某个接口。

  本地调试一下,前端发送POST请求,后端在POST方法里面打断点调试时,也不会阻碍OPTIONS请求的返回

那么是不是post请求之前一定会有options请求呢?不一定,那得看后端怎么配置


2.从后端的角度看options——post请求之前一定会有options请求?胡说八道!

后端java配置跨域代码一般如下,供参考

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {

    public CorsConfig() {
    }

    @Bean
    public CorsFilter corsFilter() {
        // 1. 添加cors配置信息
        CorsConfiguration config = new CorsConfiguration();
        // Response Headers里面的Access-Control-Allow-Origin: http://localhost:8080
        config.addAllowedOrigin("http://localhost:8080");
        // 其实不建议使用*,允许所有跨域
        config.addAllowedOrigin("*");

        // 设置是否发送cookie信息,在前端也可以设置axios.defaults.withCredentials = true;表示发送Cookie,
        // 跨域请求要想带上cookie,必须要请求属性withCredentials=true,这是浏览器的同源策略导致的问题:不允许JS访问跨域的Cookie
        /**
         * withCredentials前后端都要设置,后端是setAllowCredentials来设置
         * 如果后端设置为false而前端设置为true,前端带cookie就会报错
         * 如果后端为true,前端为false,那么后端拿不到前端的cookie,cookie数组为null
         * 前后端都设置withCredentials为true,表示允许前端传递cookie到后端。
         * 前后端都为false,前端不会传递cookie到服务端,后端也不接受cookie
         */
        // Response Headers里面的Access-Control-Allow-Credentials: true
        config.setAllowCredentials(true);

        // 设置允许请求的方式,比如get、post、put、delete,*表示全部
        // Response Headers里面的Access-Control-Allow-Methods属性
        config.addAllowedMethod("*");

        // 设置允许的header
        // Response Headers里面的Access-Control-Allow-Headers属性,这里是Access-Control-Allow-Headers: content-type, headeruserid, headerusertoken
        config.addAllowedHeader("*");



        // Response Headers里面的Access-Control-Max-Age:3600
        // 表示下回同一个接口post请求,在3600s之内不会发送options请求,不管post请求成功还是失败,3600s之内不会再发送options请求
        // 如果不设置这个,那么每次post请求之前必定有options请求
        config.setMaxAge(3600L);


        // 2. 为url添加映射路径
        UrlBasedCorsConfigurationSource corsSource = new UrlBasedCorsConfigurationSource();
        // /**表示该config适用于所有路由
        corsSource.registerCorsConfiguration("/**", config);

        // 3. 返回重新定义好的corsSource
        return new CorsFilter(corsSource);
    }
}

  这就解决了上面的问题,POST请求之前不一定有OPTIONS请求,如果设置了config.setMaxAge,仅第一次发送OPTIONS请求,不管POST请求成功还是失败,在设置的时间范围内,同一个接口请求是绝对不会再次发送OPTIONS请求的。

  后端需要注意的是,我这里设置允许请求的方法是config.addAllowedMethod("*")*表示允许所有HTTP请求方法。如果未设置,则默认只允许“GET”和“HEAD”。你可以设置的HTTPMethodGET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE

  经过我的测试,OPTIONS无需手动设置,因为单纯设置OPTIONS也无效。如果你设置了允许POST,代码为config.addAllowedMethod(HttpMethod.POST); 那么其实已经默认允许了OPTIONS,如果你只允许了GET,尝试发送POST请求就会报错如下,预检请求也无法成功响应

  预检请求返回403,服务器拒绝了OPTIONS类型的请求,因为你只允许了GETOPTIONS类型的请求未被服务器允许。POST请求的状态显示CORS error

  有人会疑问了,如果我既设置了GET,又设置了OPTIONS,我能否看到不发送POSTOPTIONS成功返回的场景?

        config.addAllowedMethod(HttpMethod.GET);
        config.addAllowedMethod(HttpMethod.OPTIONS);

  答案是否定的,单纯设置OPTIONS没有意义,现象和上面一样,OPTIONS响应码仍然403POST没有被发送。

  正常情况下我们只要允许了POSTOPTIONS就自动允许了,PUTDELETE也一样。所以从后端开发人员角度来看,几乎无需考虑OPTIONS这种请求,日常需求中POST请求命中接口时根本感知不到OPTIONS请求的存在,当然你也可以和上面一样设置OPTIONS请求的有效时间,在时间范围内,同一个接口的POST请求之前不会有OPTIONS请求。


欢迎一键三连~

有问题请留言,大家一起探讨学习

转载请注明:https://blog.csdn.net/qq_34115899/article/details/116763968

----------------------Talk is cheap, show me the code-----------------------

以上是关于从前后端的角度分析options预检请求——打破前后端联调的理解障碍的主要内容,如果未能解决你的问题,请参考以下文章

使用 CORS 避免预检 OPTIONS 请求

CORS:为啥我的浏览器不发送 OPTIONS 预检请求?

http跨域预检问题

“相同域”上的角度选项 http 预检?

预检请求的 HTTP 状态代码 [重复]

如何在AngularJS中丢弃预检响应