使用 Spring 3.0.5 和 Jackson 对 Tomcat 发出 JSON PUT 请求时出现 403

发布于 2024-10-26 18:45:49 字数 1076 浏览 1 评论 0原文

我的 Web 应用程序已开始返回 PUT 请求的 403 错误。但是,我在日志中没有看到此请求的任何调试消息,因此我对如何进一步调试它感到困惑。

该代码曾经有效,但最近发生了一些变化: 客户端是 Sencha JS:

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

容器是 Apache Tomcat 6.0。 请求先转到 Spring Security 3.0.0.RC1,然后再转到 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) {
    //...
    }
}

最近的变化: Spring 版本为 3.0.0.M4,json 库为 net.sf.json-lib 1.0.2。 Spring 现在是 3.0.5,json 库现在是 Jackson Mapper ASL 1.4.2(即 Spring 推荐的)。

GET 和 POST 工作正常。只是 PUT 失败了。

如果涉及 Spring Security,那么我会看到来自 Spring Security 的调试消息,但我什么也看不到。 Tomcat 似乎正在停止该请求。

预先感谢您的任何帮助 - 特别是在调试方面。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

娇俏 2024-11-02 18:45:49

我有兴趣看看是否有
解决这个问题,我们遇到了同样的问题
Tomcat 6.0.x 和 Spring 的事情
3.0.1 使用PUT & @RequestParam(我想我们也尝试过@RequestBody),PUT
与 Jetty 工作正常,但不行
使用 Tomcat,除非您添加
url 的参数为 ?someParam=value。
我们选择通过使用来绕过它
改为发布。

我刚刚在几分钟前将其作为评论发布,现在我回想起当我们点击此内容时,我记得我发现 线程(参数从 PUT 中消失)关于当时的问题。通读它,Tomcat 开发人员似乎将 HTTP 规范解释为 PUT 不应该支持参数:

那么,您确定 PUT 请求吗
实际上承认“参数”?
http://www.ietf.org/rfc/rfc2616.txt,
第 9.6 节

PUT 请求要求
附加实体(在请求正文中)
存储在由 指示的位置
URI。但我看不到任何参考
参数在这里。

-

无论如何,这些都有足够的余地
段落,以证明这一事实
Tomcat 开发人员可能是
有理由不实施任何
PUT 的“参数”处理
请求;而其他开发商
servlet 引擎可能已经感觉到
提供此类处理是合理的。
我想说的是
如果您创建一个应用程序
取决于正在处理的参数
在 PUT 请求中,您很可能创建
不可移植的应用程序
到所有 servlet 引擎或 HTTP
服务器。但这当然是你的
选择。

然而,所有这些都引发了一个问题:
在之前的帖子中,你提到
该请求作为 POST 可以正常工作。为什么
那么你是否坚持将其作为 PUT 发送

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
?

计㈡愣 2024-11-02 18:45:49

问题是从 updateTrailSegment() 方法返回 null。这会导致 Spring 尝试使用 InternalResourceView 与请求中内容的 url 映射请求 - 即 /RestWAR/personal/trailSegment/1761InternalResourceView 意味着它尝试将该 URL 解析为应用程序内的路径。因为没有 - 它失败了。

修复方法是使用作为返回类型:

@ResponseBody ExtResponse

ExtResponse 只是一个简单的 POJO,用于返回响应代码。

现在完整的方法是:

@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", "");
}

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", "");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文