跨域(CORS) 解决方案中,为什么 Access-Control-Allow-Methods 不起作用?

首先,通过阅读Mozilla的官方文档,对CORS的解决方案进行了理解。
然后,自己动手做实验来验证一下这个方案。
结果,发现当我在“Access-Control-Allow-Methods”中未设置“POST”时,页面上的POST仍然可以发送成功。无法理解,请各位赐教!
如下是我的请求截图:
按照Mozilla的官方文档上的关于“Preflighted requests”这段的描述:
第一张图应该是“预检”的请求,它的“Request Method”的确为“OPTIONS”,
而且返回的responseHeader中,“Access-Control-Allow-Methods”的值为"GET,PUT,DELETE",并未包含“POST”,所以理论上POST请求应该是无法发送的才是。

但是,从第二张图来看,POST类型的请求仍然被发送了。这是怎么回事呢?想不通。

PS:我使用 Chrome、Firefox、Safari测试了,都是同样的结果。

追加

或者说,我想实现在跨域的时候,禁止客户端使用POST请求,要怎么设置才行呢?

添加测试代码

实现 CORS的filter

/**
 * Servlet Filter implementation class CorsFilter
 */
@WebFilter("/*")
public class CorsFilter implements Filter {

    /**
     * Default constructor.
     */
    public CorsFilter() {
    }

    /**
     * @see Filter#destroy()
     */
    public void destroy() {
    }

    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        String currentOrigin = request.getHeader("Origin");
        response.setHeader("Access-Control-Allow-Origin", "*");

        response.setHeader("Access-Control-Allow-Methods", "GET,PUT,DELETE");
        response.setHeader("Access-Control-Allow-Headers", "Content-type");
//        response.setHeader("Access-Control-Allow-Headers", "xxx");

        chain.doFilter(req, resp);
    }

    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException {
    }
}

测试用的 ajax

$.ajax({
    "type" : "POST",
    "url" : "http://ip:port/bcdae/v1/user/file/1",
    "contentType" : "application/json",
    "data" : JSON.stringify({
        "id" : "123",
        "text" : "test"
    }),
    "success" : function(msg){
        $("#corsRes").text(msg);
    }
});
阅读 30.1k
5 个回答

火狐也是如此行为。因为标准是这么说的:

Otherwise (the HTTP status code is in the 2xx range)
...
七. If request method is not a case-sensitive match for any method in methods and is not a simple method, apply the cache and network error steps.

simple method 是指 GET, HEAD 或者 POST。所以这三个方法是例外的。Google 搜索时也可以观察到人们只遇到了因为这个头导致 delete 啊 put 啊 patch 啊之类的被拒绝的情况。

服务端如果不同意 POST 的话,可以不允许对应的 Origin,或者返回 403 啊什么的都可以的吧。(标准读起来好枯燥啊 :-( )

PS: 死 markdown 我明明写的「7.」,它非要给我改成「1.」,所以只好写汉字了……

第二张图状态码是 201
不太了解 chrome ,是不是会把 OPTION POST 合并显示呀?

个人感觉Access-Control-Allow-Methods设置的并不是服务端允许请求的方法,而是服务器支持的所有跨域请求的方法。是为了避免浏览次请求的多次'预检'请求。

通过阅读Mozilla的官方文档……QAQ……

你没搞清楚Access-Control-Allow的作用啊。。。
这个是服务端返回的一个数据啊,当然是要请求了之后,才知道你的Access是不是允许的啊……
不管跨域不跨域,请求都会发出去……
请求发送了不代表JS能获取到……
区别在于浏览器是否会报错,提示你跨域了(然后获取不到数据)。
这个才是Access-Control-Allow的作用。

总之,跨域机制是阻止了数据的获取,不是阻止了请求的发送
另外,不同浏览器不一样。

宣传栏