开发者

How do I change the response for a HTTP OPTIONS request in a Spring MVC 2.5 application?

This sounds like a trivial question but somehow I can't seem to figure it out.

I have a Spring MVC application. I don't support any http methods except GET and POST. I h开发者_StackOverflow社区ave the following set in all my controllers beans:

<property name="supportedMethods" value="GET,POST"/>

However, an OPTIONS request sent to my application sends back a response that shows all http methods as allowed.

How do I change the OPTIONS response to show only GET and POST methods as allowed? I know I could do this in a servlet by overriding the doOptions method, but I am not sure about a Spring MVC application. Do I have to extend the DispatcherServlet and override doOptions?

The application is using Spring mvc 2.5.6 with SimpleFormController based controllers and xml based config.


Caveat: I have not handled OPTIONS messages.

In your request handler (annotated with @Controller) you can use RequestMethod.OPTIONS to handle an Options request. For example you might use

  ... stuff ...  
  @RequestMapping(RequestMethod.OPTIONS)  
  public String processOptions()
  {
  ... stuff ...
  }


I think you could invoke WebContentGenerator#setSupportedMethods which receives as input parameter an array of strings containing supported methods. WebContentGenerator is the base class for spring 2.x controllers, so you just need to invoke this method during the construction of your controller that surely extends it. You also could use the Constructor of WebContentGenerator that receives a string varargs (supported methods) as input parameter.

Unfortunately, the doOptions method in FrameworkServlet class invokes super.doOptions(request, response); of HttpServlet class. The ouput of this method is based on the declared methods in the servlet, something like this:

Method[] methods = getAllDeclaredMethods(this.getClass());

for (int i = 0; i < methods.length; i++) {
    Method m = methods[i];

    if (m.getName().equals("doGet")) {
        ALLOW_GET = true;
        ALLOW_HEAD = true;
    }
    if (m.getName().equals("doPost"))
        ALLOW_POST = true;
    if (m.getName().equals("doPut"))
        ALLOW_PUT = true;
    if (m.getName().equals("doDelete"))
        ALLOW_DELETE = true;
}

The DispatcherServlet class (and its base class FrameworkServlet) declares all these methods: doPut, doDelete, doGet, doPost etc., so the output of doOptions is not what you desire. I think the only way is subclassing the DispatcherServlet.


I know that this is a bit old but I've found additional info on this question that I hope will help others in the future.

The @RequestMapping(RequestMethod.OPTIONS) approach won't work immediately using the DispatcherServlet out of the box since its superclass, FrameworkServlet, first delegates to its superclass, HttpServlet, as noted above which scans the servlet to see if it implements the doXXX methods and sets the Allow header accordingly. But following the call to super.doOptions(...) it then has these lines:

if (this.dispatchOptionsRequest) {
     processRequest(request, response);
}

And there is a setDispatchOptionsRequest(boolean) that can be used to set the dispatchOptionsRequest value to true. Only then will the DispatcherServlet pass to the controller the OPTIONS request to an appropriately annotated method.

I needed to do this to allow the OPTIONS request to return different values based upon authorizations of the current user. So by subclassing DispatcherServlet and setting that parameter in its default constructor I was finally able to receive the call in my controller for http OPTIONS requests and handle it on my own.

And one more thought, in that controller method you can declare a parameter of type HttpServletResponse and Spring will hand the instance to you. Once had you can call reset() to purge the Allow header already set and roll your own as needed.

(Note: A similar patter is had in FrameworkServlet for http TRACE support via a setDispatchTraceRequest if you plan on getting those requests through to your controller methods annotated with @RequestMapping(RequestMethod.TRACE)).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜