如何配置嵌入式Jetty来处理OPTIONS飞行前请求



我正在处理一个使用嵌入式Jetty的项目(不幸的是,我只是"继承"了该项目的服务器端,对Jetty的使用及其配置不太熟悉)。

一个奇怪的案例突然出现了——我会尽力描述:

基于web的UI(使用AngularJS,来自不同的域,因此使用CORS)发送POST请求以更改服务器上的某些状态。这在过去的某个时候起到了作用(上一次使用可能是在一个月左右之前)。

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

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网络安全标志启动Chrome来验证这一点。没有发送OPTIONS请求,POST正常工作。

我的想法是,由于它适用于POST,所以这不是授权或安全问题——只是Jetty没有正确配置来处理飞行前请求(它只是返回401)。

我找不到太多关于嵌入式Jetty的文档,也找不到在对setInitParameter的调用中使用哪些CrossOriginFilter常量作为属性键(此外,由于该方法调用的第二个参数是String,我真的不知道如何格式化值)。

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

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");

我通过使用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请求,则无需设置此参数。

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

        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)); 

最新更新