2013-02-19 91 views
7

我正在开发一个网页游戏。作为游戏的一部分,您开始使用一些有限的功能,并且在玩游戏时解锁更多功能。什么响应代码适合这种情况?

例如,你解锁/fields作为步骤3中的教程的一部分。但是如果你只是在地址栏中导航到/fields呢?

我试图找出什么是最好的状态代码与响应。

403由于用户访问的页面,直到他们解锁禁止似乎理想。
404也是有意义的,因为页面在技术上“不存在”,直到它被解锁并且还阻止用户能够分辨不存在的页面和他们还没有解锁的页面之间的区别。

但在这两种情况下,我已经有一些用户使用浏览器cacheing的404分之403结果,而不是让他们即使在解锁它,除非他们清除缓存后完全访问页报告问题。

我想知道如果我应该继续使用403或404,或者我应该使用一个未使用的4XX代码(如442自定义statusText),或者甚至开玩笑地发送HTTP/1.1 418 I'm A Teapot以响应用户在他们不应该在哪里拨动是。

我需要一个良好的,坚实的理由,为什么一个选项应该在他人使用。

+2

我不知道正确的答案,但下面的帖子提供了一些有趣的参数:http://stackoverflow.com/questions/3297048/403-forbidden-vs-401-unauthorized-http-responses – RobJohnson 2013-02-21 16:22:57

+1

为什么不到只是重定向到他们被允许在的页面?也可能显示弹出窗口,说该功能尚未提供。 – 2013-02-21 22:11:57

+2

顺便说一句,'401 Unauthorized'会是一个坏主意,因为这个状态码仅用于HTTP身份验证,浏览器专门处理这个状态码。 – nalply 2013-02-22 21:17:57

回答

3

tl; dr409 Conflict将是一个想法,但也许你有缓存问题。在这种情况下,强制重新加载的缓存破坏程序将会起作用。

龙解释

也许409 Conflict状态码才有意义:

10.4.10 409冲突

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

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

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

后来我调查的情况多一点,我发现,魔鬼在细节。让我们来看看403 Forbidden404 Not Found的规格。

10.4.4 403禁止

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

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

10.4.5 404未找到

服务器没有找到任何匹配的请求URI。没有迹象表明病情是暂时的还是永久性的。

[省略]

现在我们有一个问题!为什么你的404页面会被缓存?如果规范允许它们是临时的?

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

如果你不想用缓存头很乱,使用所谓的缓存无效,并通过系统的时间是这样的(假设PHP作为Web语言):

<a href="/fields?<?php echo time(); ?>">

这产生像/fields?1361948122这样的URL,每秒都在增加。这是Markus A提出的解决方案的一个变种。

我假设查询字符串1361948122被您的资源忽略。如果不是,请将查询字符串参数中的cache-buster传递给例如t=1361948122,并确保参数t未被您的资源评估。

2

在的HTTP错误代码的预期目的而言,我肯定会用403 Forbidden去,因为页面不存在(404出),但用户禁止访问它,现在(和这个限制不是由于资源冲突,如同时修改,但由于用户的帐户状态,即我认为409也是如此。基于其预期目的的另一个明智的选择可能是401,但正如他的评论中已经注意到的那样,此代码会触发一些(如果不是全部的话)浏览器显示登录对话框,因为这意味着使用标准Web认证机制可以解决问题。所以,这绝对不是您的选择。

两件事情似乎在403的描述有点“misfitting”,所以让我解决这些问题:

  1. 授权不会帮助...:有关HTTP内部授权机制这只会谈协议,旨在区分403与401。此声明不适用于任何形式的自定义授权或会话状态管理。
  2. ...请求不应该重复...:请求必须始终在会话上下文中看到,因此如果用户的会话上下文发生更改(他解锁某个功能),然后他重试访问相同的资源,这是一个不同的要求,即没有违反这一建议。

当然,你也可以定义自己的错误代码,但由于它可能不会在任何官方的方式保留,也不能保证,一些浏览器厂商是不会有意或无意地使用完全相同该代码来触发特定的(调试)操作。这是不可能的,但不被禁止。

418也可以,但是。 :)

当然,如果您想特别隐藏功能的潜在可用性,您也可以决定使用404,因为这是不给任何黑暗用户任何提示的唯一方法。现在

,你的缓存问题:

无论这些状态代码(403,404,409,418)应该触发浏览器缓存页面违背自己的意愿比其他任何一个。问题是,许多浏览器只是试图缓存一切就像疯了一样,以加快速度。在我看来,歌剧是最糟糕的。我在这些事情上多次拉我的头发。它应该可以使用正确的标题设置来处理它,但是我有过浏览器或服务器或某个中间代理决定忽略它们并且无论如何都会中断我的页面的情况。

到目前为止我发现的绝对肯定保证重新加载的唯一可靠方法是添加一个虚拟请求参数,如/ fields?t = 29873,其中29873是每个请求所独有的数字在任何可能相关的时间范围内。当然,在服务器上,你可以简单地忽略这个参数。请注意,仅当用户首次打开页面时,从1开始并不足以满足以下请求,因为浏览器可能会跨页重新加载缓存。

我做我的Web开发中的Java(服务器和使用GWT客户端),我用这个代码来生成虚拟的“数字”:

private static final char[] base64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_.".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); 
} 

它使用系统的时钟结合一个计数器能够每ms提供约两个保证唯一值。您可能不需要这种速度,所以您可以随时更改我标记为“调整”的>>> 5以符合您的需求。如果你将它增加1,你的利率下降两倍,你的唯一性时间加倍。因此,例如,如果您将>>> 8代替,则可以每4毫秒生成一个值,并且这些值不应在3200天内重复。当然,如果用户使用系统时钟混淆,这种保证值不会重复的情况将会消失。但是,由于这些值不是按顺序生成的,所以您很可能不会再次输入相同的数字。该代码生成一个6个字符的文本字符串(base64),而不是一个十进制数字,以使URL尽可能短。

希望这会有所帮助。:)

0

我觉得没有必要抛出一个错误代码,尽管你只是显示一个类似

你必须等级XX访问此页面或有趣的东西像的消息来当你长大后回来

代码200-OK本身,所以不会有缓存问题,目标也实现了。