如何配置嵌入式Jetty来处理OPTIONS预检请求?

时间:2014-09-24 17:16:58

标签: jetty cors embedded-jetty http-options-method preflight

我正在开发一个使用嵌入式Jetty的项目(不幸的是我只是“继承”了项目的服务器端,并且对Jetty及其配置的使用不太熟悉。)

刚出现一个奇怪的案例 - 我会尽力描述:

基于Web的UI(使用AngularJS,来自不同的域,因此使用CORS)发送POST请求以更改服务器上某些内容的状态。这在过去的某个时刻起作用(它可能是大约一个月前使用过的)。

昨天这停止了工作。检查REST调用,我看到首先发出OPTIONS请求。 POST的内容类型是application / json,所以基于我读过的内容,这是正确的。我不确定为什么之前没有发送过 - 有可能该公司最近更新了Chrome版本,旧版本没有发送预检请求,但这只是猜测。在任何情况下,我认为这是我的应用程序中为JetS配置CORS的相关代码:

FilterHolder holder = new FilterHolder(new CrossOriginFilter());
holder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM,  "*");
holder.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true");
appHandler.addFilter(holder, "/*", EnumSet.of(DispatcherType.REQUEST));

一切都适用于POST请求。我可以通过使用--disable-web-security标志启动Chrome来验证这一点。没有发送OPTIONS请求,并且POST工作正常。

我的想法是,因为它适用于POST,它不是授权或安全问题 - 它只是没有正确配置Jetty来处理预检请求(它只返回401)。

我找不到很多关于嵌入式Jetty的文档,以及哪些CrossOriginFilter常量在调用setInitParameter时用作属性键(此外,因为该方法调用的第二个参数是一个String,我真的没有想法如何格式化值。)

我应该在CrossOriginFilter上设置哪些参数来处理OPTIONS请求?如果我上面说过任何错误或做出任何错误的假设,请纠正我!我对这方面的经验非常有限。

3 个答案:

答案 0 :(得分:5)

CrossOriginFilter的文档:

http://www.eclipse.org/jetty/documentation/current/cross-origin-filter.html

CrossOriginFilter的Javadoc:

http://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/servlets/CrossOriginFilter.html

实际源代码:(有时这也有助于人们理解):

https://github.com/eclipse/jetty.project/blob/jetty-9.2.3.v20140905/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java

简而言之,您可能希望将OPTIONS添加到允许的方法中。

就像javadoc所说

FilterHolder holder = new FilterHolder(new CrossOriginFilter());
holder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,POST,HEAD,OPTIONS");
appHandler.addFilter(holder, "/*", EnumSet.of(DispatcherType.REQUEST));

现在,要解决另一个错误......

这没什么用......

holder.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER,
  "true");

这不是init参数键。 (实际上这是Access-Control-Allow-Credentials的标题名称常量),如果你想允许凭证,那么就像javadoc所说的那样。

holder.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "true");

答案 1 :(得分:1)

我通过对FilterHolder使用以下配置解决了这个问题:

FilterHolder cors = new FilterHolder(CrossOriginFilter.class);
cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
cors.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "OPTIONS,GET,POST,HEAD");
cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin,Cache-Control");
cors.setInitParameter(CrossOriginFilter.CHAIN_PREFLIGHT_PARAM, "false");

Chrome发送"缓存控制"如果您不允许此标头使用CORS过滤器,则不会使用正确的标头响应OPTIONS请求。大多数CrossOriginFilter在线示例都不包含此标题。

您可以选择将CHAIN_PREFLIGHT_PARAM设置为false(默认为true)。如果将其设置为false,则过滤器将响应请求而不将请求发送到Servlet。如果您想自己处理OPTIONS请求,则无需设置此参数。

答案 2 :(得分:-2)

更新:我完全尝试了你的代码,但我在上下文处理程序中添加了过滤器,而不是在应用程序上。它以这种方式工作。

        FilterHolder holder = new FilterHolder(new CrossOriginFilter());
    holder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM,  "http://localhost:8100");
    holder.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true");

    contextHandler.addFilter(holder, "/*", EnumSet.of(DispatcherType.REQUEST));