开发者

403 on JSON PUT request to Tomcat with Spring 3.0.5 and Jackson

开发者 https://www.devze.com 2023-02-19 23:31 出处:网络
My web application has started returning 403 errors on PUT requests. However, I\'m not seeing any debug messages in the logs for this request so I\'m stumped as to how to debug this further.

My web application has started returning 403 errors on PUT requests. However, I'm not seeing any debug messages in the logs for this request so I'm stumped as to how to debug this further.

This code used to work but there have been a number of recent changes: Client is Sencha JS:

Ext.Ajax.request({
        url       : '/RestWAR/personal/trailSegment/' + trailSegment.id + '.json',
        method    : 'PUT',
        headers   : {'Content-Type': 'application/json'},
        jsonData  : segmentDto
});

The container is Apache Tomcat 6.0. The request goes to Spring Security 3.0.0.RC1 before going to Spring 3.0.5.

@Controller
@RequestMapping("/personal")
public class PersonalController {
    @RequestMapping(value = "trailSegment/{trailSegmentId}", method=RequestMethod.PUT)
    public void updateTrailSegment(@PathVariable long trailSegmentId, @RequestBody PersonalTrailSegmentDTO trailSegmentDto) {
    //...
    }
}

Recent changes: Spring was on 3.0.0.M4 and the json library was net.sf.json-lib 1.0.2. Spring is now 3.0.5 and the json 开发者_运维问答library is now Jackson Mapper ASL 1.4.2 (i.e. what Spring recommends).

GETs and POSTs are working fine. It's just PUTs that are failing.

If Spring Security were involved then I would be seeing debug messages from Spring Security but I see nothing at all. It appears that Tomcat is stopping the request.

Thanks in advance for any help - especially in regards to debugging this.


I'm interested to see if there's a solution to this, we hit the same thing with Tomcat 6.0.x and Spring 3.0.1 using PUT & @RequestParam (I think we tried @RequestBody too), PUTs were working fine with Jetty but not with Tomcat, unless you add the parameter to url as ?someParam=value. We chose to go around it just by using POST instead.

I just posted that as a comment a few minutes ago, now that I thought back when we hit this, I remembered I found this thread (Parameters disappear from PUTs) about the issue back then. Reading through it, it seems the Tomcat-developers interpreted the HTTP-specification to mean that PUT should not support parameters:

Well, are you sure that a PUT request actually admits "parameters" ? http://www.ietf.org/rfc/rfc2616.txt, section 9.6

A PUT request requests that the attached entity (in the requst body) be stored at the location indicated by the URI. But I see no reference to parameters here.

-

There is anyway enough leeway in these paragraphs, to justify the fact that the Tomcat developers may have been justified to not implement any handling of "parameters" for PUT requests; while developers of other servlet engines may have felt justified in providing such handling. The point I am trying to make is that if you create an application which depends on parameters being processed in a PUT request, you may well create an application which is not portable to all servlet engines or HTTP servers. But that is of course your choice.

All this triggers a question however : in an earlier post, you mention that the request works fine as a POST. Why then do you insist to send it as a PUT ?


The problem was returning null from the updateTrailSegment() method. This causes Spring to attempt to map the request using InternalResourceView with a url of what's in the request - i.e. /RestWAR/personal/trailSegment/1761. The InternalResourceView means that it attempts to resolve that URL as a path within the application. As there is none - it fails.

The fix is to use as the return type:

@ResponseBody ExtResponse

ExtResponse is just a simple POJO to return a response code.

The full method is now:

@RequestMapping(value = "trailSegment/{trailSegmentId}", method=RequestMethod.PUT)
public @ResponseBody ExtResponse updateTrailSegment(@PathVariable long trailSegmentId, @RequestBody PersonalTrailSegmentDTO trailSegmentDto) {
    trailSegmentDto.setId(trailSegmentId);
    PersonalTrailSegment trailSegment = trailSegmentAssembler.assembleDomain(trailSegmentDto);
    trailSegmentDataGateway.update(trailSegment);
    return new ExtResponse("true", "");
}
0

精彩评论

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

关注公众号