不同HTTP方法请求无效URL时应返回哪种状态码?

5

当REST应用程序收到一个请求不存在的资源时,它是否应该始终返回404 Not Found

对于任何HTTP方法GETHEADPOSTPUTDELETEOPTIONSTRACE),它应该返回不同的状态吗?

Spring对于GETHEAD返回404,对于OPTIONS返回200 OK,对于其他方法返回405 Method Not Supported。这样做是否正确?

例如,这个Spring Boot应用程序显示了对于错误的URL请求(greetings而不是greeting)的不同响应。

@RestController
@SpringBootApplication
public class Application {
    
    private static Logger log = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
        
        RestTemplate restTemplate = new RestTemplate();
        String badUrl = "http://localhost:8080/greetings";
        for (HttpMethod httpMethod : HttpMethod.values()) {
            try {
                restTemplate.execute(badUrl, httpMethod, null, null);
            } catch (Exception e) {
                log.error("Failed to " + httpMethod + " -- " + e.getMessage());
            }
        }
    }

    @RequestMapping("/greeting")
    public String greeting() {
        return "hello";
    }
}

记录的输出是:

无法获取 -- 404 找不到

无法 HEAD -- 404 找不到

无法 POST -- 405 方法不允许

无法 PUT -- 405 方法不允许

无法 PATCH -- 在“http://localhost:8080/greetings”上进行 PATCH 请求时出现 I/O 错误:无效的 HTTP 方法:PATCH;嵌套异常为 java.net.ProtocolException: Invalid HTTP method: PATCH

无法删除 -- 405 方法不允许

对“http://localhost:8080/greetings”的 OPTIONS 请求结果为 200 (OK)

无法 TRACE -- 405 方法不允许

1个回答

5

简短的回答:它不一定总是会返回 404。更详细的回答:规范似乎提供了一些关于使用哪些状态码的选项。在https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5上的规范中写道:


10.4.5 404 Not Found

服务器未找到与请求URI相匹配的任何内容。没有指示该条件是临时还是永久的。如果服务器通过某种内部可配置机制知道旧资源已经永久不可用并且没有转发地址,则应使用410(Gone)状态代码。当服务器不希望明确地透露拒绝请求的原因,或者没有其他可用的响应时,通常使用此状态代码。

10.4.6 405 Method Not Allowed

请求行中指定的方法不允许用于由请求URI标识的资源。响应必须包括一个Allow头,其中列出了请求资源的有效方法。


在使用这两个代码时有一些解释的余地。我的理解是:如果某个资源不存在,但可能仍然可以对URI应用某些操作,则使用 405 更合适。

例如:

GET /reservation/1

405 Method not allowed
Allow: PUT

这可能意味着,虽然该特定资源不允许使用GET(因为它实际上不存在),但您仍然可以使PUT起作用,从而在此过程中创建该资源。

可以说,尽管规范允许使用404,但其可用性较低。

关于OPTIONS。规范在此处:https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.2。根据规范,它并不意味着与资源本身的交互。它更像是一个查询服务器的请求,以确定在给定URI上“理论上”支持哪些方法。它支持通配符(“*”)查询,这也很可能根本不存在。


是的,我明白你所说的GET(等)与PUT之间的区别。例如,so/questionId/answerId可能不存在,因此我们无法进行GET操作,但只要so/questionId存在,我们就可以进行PUT操作-因此405是适当的。如果问题不存在,则无法对其进行GET或PUT回答-因此404是适当的。 - whistling_marmot
是的,完全正确。但是,再次阅读上面的错误代码时,存在一些解释的空间,这在特定情况下可能或可能不合理。我认为大多数服务器或客户端都没有准备好进行这样的区分。在大多数情况下,这甚至可能没有任何影响。 - Robert Bräutigam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接