200
当GET
请求不存在的文件时,服务器提供响应是否有意义?响应难道不应该始终是404
?
这是响应头:
{'Date': 'Tue, 08 Jan 2019 22:56:26 GMT', 'Server': 'Apache', 'Strict-Transport-Security': 'max-age=31536000; preload', 'X-Frame-Options': 'SAMEORIGIN', 'XX-RequestId': 'pw01-225626->serv_31-225626', 'Vary': 'Accept-Encoding', 'Content-Encoding': 'gzip', 'X-Content-Type-Options': 'nosniff', 'X-Permitted-Cross-Domain-Policies': 'none', 'Cache-Control': 'max-age=0, no-cache, no-store', 'Content-Length': '20', 'Keep-Alive': 'timeout=5, max=100', 'Connection': 'Keep-Alive', 'Content-Type': 'application/json'}
尽管Content-Length
我们20
最终下载了一个零字节的 zip 文件。
答案1
是的,在某些情况下,对不存在的文件返回 200 响应是有意义的。200 响应表示客户端请求的逻辑实体存在。即使文件不存在,返回表示逻辑实体存在的响应也是完全合理的,只要文件的存在和逻辑实体的存在不是一回事。
假设我有一个文件系统,其中每个文件都表示处于某种特定状态的用户名。文件不存在并不表示用户名不存在,只是表示用户名不处于该特定状态。在这种情况下,对不存在的文件返回 403 会是一个错误,因为这表明请求的资源不存在,但实际上它确实存在。
假设名称“Adam”和“Jeff”已被保留,但其他所有名称都可用,这通过存在名为“Adam”的文件和名为“Jeff”的文件而没有其他文件来表示。该系统使用文件来表示名称已被保留。要说不存在的文件不能产生 200,您必须说我们可能不会对除“Adam”和“Jeff”之外的任何名称返回 200。
现在想象一个类似的系统,其中除“Adam”和“Jeff”之外的所有名称都被保留。只有“Adam”和“Jeff”可用。该系统使用文件来指示名称可用。要争辩说不存在的文件不能产生 200,您必须再次争辩说我们可能不会为除“Adam”和“Jeff”之外的任何名称返回 200。
但看看这两个结果放在一起有多奇怪。在这两种情况下,我们都有一个系统,人们可以查询名称可用性。我们在内部实现方面有一些差异,但对于查询系统的人来说,他们不应该知道这一点。但我们的论点是,一个系统不能为保留名称返回 200,一个系统不能为非保留名称返回 200,因为它们内部实现保留的方式不同。这很荒谬。
答案2
根据标准,当 URI 不映射时,它应该始终为 404,请参阅rfc2616第 10.4.5 节。
不幸的是,深奥的商业案例有时确实会证明违反标准是合理的。从好的方面来看,违反标准应该由提出不寻常要求的团队来决定。你总是可以回到“标准之所以是标准是有原因的”。
答案3
当对不存在的文件发出 GET 请求时,服务器提供 200 响应是否有意义?
在我看来,任何无法完成操作的 URL(即生成的文件无效或未返回)都应该返回 5XX 错误。规范暗示响应应始终以 200 响应发送:
200 OK - 请求成功。返回的信息...
204 响应的存在进一步暗示了这一点,该响应专门针对未返回响应的请求:
204 无内容 服务器已完成请求,但不需要返回实体主体
所描述的行为有意义吗?没有。
响应不应该总是 404 吗?
404 对我来说似乎是个不错的选择......
服务器未找到与请求 URI 匹配的任何内容。没有迹象表明该情况是暂时的还是永久的。... 当服务器不希望透露拒绝请求的确切原因,或没有其他适用的响应时,通常使用此状态代码。
尽管如果脚本返回 404,我仍然希望 JSON 编码的响应具有内容长度标头的大小。
请记住,“你应该”和“它会起作用”是两个不同的问题。只要网站/服务的消费者理解 0 字节响应的含义,它就完全合法。您可以将响应代码设置为 1 到 999 之间的任何数字,您可以发明新的标头等 - 但大多数客户端不知道如何处理这些响应。内容长度和收到的内容之间的不匹配可能会导致请求挂起,直到连接超时或明确关闭。
不是我的服务器/代码,并且服务器上肯定不存在
所描述的行为似乎是某些活动脚本正在拦截 URL,并悄悄地无法从某个地方(文件系统、数据库等)加载基于该 URL 的数据。这是控制访问、分析、缓存等的常见模式。
本质上,我认为服务器在实际检查数据是否存在之前就发送了响应标头。这将导致 200 响应,而不返回任何数据。简而言之,这看起来像是一个错误/不好的做法。