Http 什么响应代码适用于这种情况?

Http 什么响应代码适用于这种情况?,http,http-response-codes,Http,Http Response Codes,我正在开发一个网络游戏。作为游戏的一部分,你从一系列有限的功能开始,并在游戏中解锁更多功能 例如,作为本教程步骤3的一部分,您可以解锁/字段。但是如果您只是导航到地址栏中的/字段,会怎么样 我正试图找出最好的状态码来回应 403似乎很理想,因为在用户解锁页面之前,禁止用户访问该页面。 404也有意义,因为在解锁之前,页面在技术上是“不存在”的,并且用户无法区分不存在的页面和尚未解锁的页面 但在这两种情况下,我都有一些用户报告浏览器缓存403/404结果时出现问题,并且即使在解锁页面后也不允许他们

我正在开发一个网络游戏。作为游戏的一部分,你从一系列有限的功能开始,并在游戏中解锁更多功能

例如,作为本教程步骤3的一部分,您可以解锁
/字段。但是如果您只是导航到地址栏中的
/字段
,会怎么样

我正试图找出最好的状态码来回应

403似乎很理想,因为在用户解锁页面之前,禁止用户访问该页面。
404也有意义,因为在解锁之前,页面在技术上是“不存在”的,并且用户无法区分不存在的页面和尚未解锁的页面

但在这两种情况下,我都有一些用户报告浏览器缓存403/404结果时出现问题,并且即使在解锁页面后也不允许他们访问页面,除非他们完全清除缓存

我想知道我是否应该继续使用403或404,或者我应该使用一个未使用的4XX代码,比如带有自定义状态文本的442,或者甚至开玩笑地发送
HTTP/1.1 418“我是一个茶壶”
,以回应用户在不应该出现的地方乱翻


我需要一个好的、可靠的理由来解释为什么一个选项应该被使用而不是其他选项。

tl;dr
409冲突
可能是个好主意,但可能您在缓存方面有问题。在这种情况下,强制重新加载的缓存清除器将起作用

详细解释

也许一个
409冲突
状态代码会有意义:

10.4.10 409冲突

由于与资源的当前状态冲突,无法完成请求。只有在预期用户可能能够解决冲突并重新提交请求的情况下,才允许使用此代码。响应主体应包含足够的信息,以便用户识别冲突的来源。理想情况下,响应实体将包括足够的信息,供用户或用户代理修复问题;然而,这可能是不可能的,也不是必须的

在响应PUT请求时最有可能发生冲突。例如,如果正在使用版本控制,并且正在放置的实体包含对资源的更改,这些更改与先前(第三方)请求所做的更改相冲突,则服务器可能会使用409响应来指示它无法完成请求。在这种情况下,响应实体可能会以响应内容类型定义的格式包含两个版本之间差异的列表

这是有道理的,因为资源只有在用户完成教程后才可用。在此之前,资源处于“无效”状态。用户可以通过完成本教程来解决此冲突

后来我进一步调查了这个案子,发现细节中有魔鬼。让我们阅读
403禁止
404未找到
的规范

10.4.4 403禁止

服务器理解该请求,但拒绝满足该请求。授权没有帮助,请求不应重复。如果请求方法不是HEAD,并且服务器希望公开请求未得到满足的原因,那么它应该在实体中描述拒绝的原因。当服务器不希望确切地揭示请求被拒绝的原因,或者当没有其他响应适用时,通常使用此状态代码

重要的是规范«请求不应重复»。一个从不重新请求403页面的浏览器可能会做正确的事情。但是,让我们继续404:

10.4.5 404未找到

服务器未找到任何与请求URI匹配的内容。没有说明该情况是暂时的还是永久的

[省略]

现在我们有问题了!如果规范允许404页面是临时的,为什么要缓存它们

可能在您的设置中,403和404页面的缓存配置不正确。如果是这样,请咨询。它给出了关于缓存4xx页面的详细答案

如果您不想弄乱缓存头,请使用所谓的cache buster并像这样传递系统时间(假设PHP是您的web语言):


就HTTP错误代码的预期用途而言,我肯定会选择
403禁止
,因为该页面确实存在(404已退出),但目前禁止用户访问该页面(这种限制不是由于资源冲突,比如并发修改,而是由于用户的帐户状态,即我认为409也不存在)。另一个基于其预期用途的明智选择可能是401,但正如nalply在其评论中指出的,该代码会触发一些(如果不是全部)浏览器显示登录对话框,因为这意味着使用标准的web身份验证机制可以解决此问题。因此,您在这里绝对不会选择401

在403的描述中,有两件事似乎有点“不匹配”,所以让我来谈谈:

  • 授权无助于…:这只讨论HTTP协议内部的授权机制,旨在区分403和401。此语句不适用于任何形式的自定义授权或会话状态管理
  • …不应重复请求…:必须始终在会话上下文中查看请求,因此,如果用户的会话上下文更改(他解锁了一项功能),然后他重试访问同一资源,则这是一个不同的请求,即没有违反此建议
  • 当然,您也可以定义自己的错误代码,但由于它可能不会以任何官方方式保留,因此无法保证某些浏览器制造商不会有意或无意地为我们保留
    private static final char[] base64chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_.".toCharArray();
    private static int tagIndex = 0;
    
    /**
     * Generates a unique 6-character tag string that is guaranteed to not repeat
     * for about 400 days, if this function is, on average, not called more often
     * than twice every millisecond.
     * 
     * @return the tag string
     */
    public static String nowTag() {
        int tag = (int) ((System.currentTimeMillis() >>> 5)); // adjust
        char[] result = new char[6];
        result[5] = base64chars[(tagIndex++) & 63];
        result[4] = base64chars[tag & 63];
        tag >>>= 6;
        result[3] = base64chars[tag & 63];
        tag >>>= 6;
        result[2] = base64chars[tag & 63];
        tag >>>= 6;
        result[1] = base64chars[tag & 63];
        tag >>>= 6;
        result[0] = base64chars[tag & 63];
        return new String(result); 
    }