9

私はウェブゲームを開発しています。ゲームの一部として、限られた一連の機能から始めて、プレイするにつれてそれらのロックを解除していきます。

たとえば/fields、チュートリアルのステップ 3 の一部としてロックを解除します。/fieldsしかし、アドレス バーで に移動した場合はどうなるでしょうか。

応答するのに最適なステータス コードを見つけようとしています。

403 は、ユーザーがロックを解除するまでページへのアクセスが禁止されているため、理想的です。
404 は、ロックが解除されるまでページが技術的に「存在しない」ため、意味があり、ユーザーは存在しないページとまだロックを解除していないページの違いを区別できなくなります。

しかし、どちらの場合も、ブラウザーが 403/404 の結果をキャッシュし、キャッシュを完全に消去しない限り、ロックを解除した後でもページにアクセスできないという問題を報告したユーザーがいます。

403 または 404 を使用し続ける必要があるのか​​、それとも 442 などの未使用の 4XX コードをカスタム statusText と共に使用するべきなのか、それとも、あるHTTP/1.1 418 I'm A Teapotべきではない場所を突っついたユーザーに冗談めかして送信するべきなのか疑問に思っています。

あるオプションを他のオプションよりも優先して使用する必要がある、確固たる正当な理由が必要です。

4

3 に答える 3

5

tl;dr 409 Conflictはアイデアですが、おそらくキャッシュに問題があります。この場合、リロードを強制するキャッシュバスターが機能します。

長い説明

おそらく409 Conflictステータスコードは理にかなっているでしょう:

10.4.10 409 コンフリクト

リソースの現在の状態と競合するため、要求を完了できませんでした。このコードは、ユーザーが競合を解決してリクエストを再送信できると予想される状況でのみ許可されます。応答本文には、ユーザーが競合の原因を認識するのに十分な情報を含める必要があります。理想的には、応答エンティティには、ユーザーまたはユーザー エージェントが問題を解決するのに十分な情報が含まれます。ただし、それは不可能な場合があり、必須ではありません。

競合は、PUT 要求への応答で発生する可能性が最も高くなります。たとえば、バージョニングが使用されていて、PUT されているエンティティに、以前の (サードパーティの) 要求によって行われたものと競合するリソースへの変更が含まれていた場合、サーバーは 409 応答を使用して、要求を完了できないことを示す可能性があります。 . この場合、応答エンティティには、応答の Content-Type によって定義された形式で、2 つのバージョン間の相違点のリストが含まれている可能性があります。

ユーザーがチュートリアルを実行した後にのみリソースが利用可能になるため、これは理にかなっています。それ以前は、リソースは «無効» 状態にあります。ユーザーはチュートリアルを完了することで、この競合を解決できます。

その後、私はこの事件をもう少し調査し、悪魔は細部に宿っていることを発見しました。403 Forbiddenとの仕様を読んでみましょう404 Not Found

10.4.4 403 禁止

サーバーは要求を理解しましたが、要求を満たすことを拒否しています。承認は役に立たず、要求を繰り返すべきではありません。リクエスト メソッドが HEAD ではなく、サーバーがリクエストが実行されなかった理由を公開したい場合、拒否の理由をエンティティに記述する必要があります。このステータス コードは、サーバーが要求が拒否された理由を正確に明らかにしたくない場合、または他の応答が適用できない場合に一般的に使用されます。

重要なのは、「リクエストは繰り返されるべきではない」という仕様です。403 ページを再要求しないブラウザーは、正しいことを行う可能性があります。ただし、404 を続けましょう。

10.4.5 404が見つかりません

サーバーは Request-URI に一致するものを見つけられませんでした。状態が一時的なものか永続的なものかは示されていません。

[省略]

今、私たちは問題を抱えています!仕様で一時的なものを許可しているのに、404 ページがキャッシュされるのはなぜですか?

おそらく、セットアップで、403 および 404 ページに対してキャッシュが正しく構成されていない可能性があります。その場合は、 StackOverflow でこの回答を参照してください。4xx ページのキャッシュに関する詳細な回答が得られます。

キャッシュヘッダーをいじりたくない場合は、いわゆるキャッシュバスターを使用して、次のようにシステム時間を渡します (Web 言語として PHP を想定しています)。

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

/fields?1361948122これにより、毎秒増加する のような URL が生成されます。これは、Markus A によって提案されたソリューションの変形です。

クエリ文字列1361948122はリソースによって無視されると思います。そうでない場合は、代わりにクエリ文字列パラメーターでキャッシュバスターを渡します。たとえばt=1361948122、パラメーターtがリソースによって評価されないようにします。

于 2013-02-22T21:23:26.987 に答える
2

HTTP エラー コードの意図された目的に関しては403 Forbidden、ページが存在する (404 が出ている) ため、間違いなく使用しますが、ユーザーは今のところアクセスを禁止されています (この制限はリソースの競合によるものではありません)。 、同時変更と同様ですが、ユーザーのアカウントの状態により、つまり、私の意見では 409 もアウトです)。意図された目的に基づく別の賢明なオプションは 401 であった可能性がありますが、nalply が彼のコメントで既に述べたように、このコードは、すべてではないにしても一部のブラウザにログイン ダイアログを表示させます。問題を解決します。したがって、ここでの選択肢は間違いありません。

403 の説明では 2 つの点が少し「不適切」に思われるので、それらについて説明します。

  1. Authorization will not help ...:これは、HTTP プロトコル内の承認メカニズムについてのみ説明しており、403 と 401 を区別することを目的としています。このステートメントは、カスタム承認またはセッション状態管理の形式には適用されません。
  2. ... リクエストは繰り返されるべきではありません ...:リクエストは常にセッション コンテキストで表示される必要があるため、ユーザーのセッション コンテキストが変更された (ユーザーが機能のロックを解除した) 場合、ユーザーは同じリソースへのアクセスを再試行します。つまり、つまり、この提案に違反するものではありません。

もちろん、独自のエラー コードを定義することもできますが、おそらく正式な方法で予約されることはないため、一部のブラウザー メーカーが意図的または誤ってそのコードを使用して特定のエラーをトリガーしないという保証はありません。 (デバッグ) アクション。可能性は低いですが、禁止されているわけではありません。

418でもOKです。:)

もちろん、機能の潜在的な利用可能性を具体的に覆い隠したい場合は、404 を使用することもできます。それが、せんさく好きなユーザーにヒントを与えない唯一の方法だからです。

さて、キャッシュの問題に:

これらのステータス コード (403、404、409、418) のいずれも、ブラウザーが他のどのコードよりもユーザーの意思に反してページをキャッシュするようにトリガーするべきではありません。問題は、多くのブラウザが狂ったようにすべてをキャッシュしようとするだけで、よりスムーズになることです。私の意見では、オペラはここで最悪です。私はこれらのことで何度も髪を引っ張ってきました。正しいヘッダー設定ですべてを解決できるはずですが、ブラウザ、サーバー、または中間プロキシのいずれかがそれらを無視してページを壊すことを決定した状況がありました。

私がこれまでに見つけた確実なリロードを確実に保証する唯一の方法は、/fields?t=29873 のようなダミーのリクエスト パラメータを追加することです。タイムスケール。もちろん、サーバーでは、このパラメーターを無視することができます。ユーザーが最初にページを開いたときに単純に 1 から開始し、次のリクエストをカウントアップするだけでは不十分であることに注意してください。

私は Java で Web 開発を行い (GWT を使用してサーバー側とクライアント側の両方で)、このコードを使用してダミーの「数字」を生成します。

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); 
}

システムのクロックをカウンターと組み合わせて使用​​し、ミリ秒ごとに最大約 2 つの保証された一意の値を提供できるようにします。この速度は必要ないかもしれないので、>>> 5必要に応じて「調整」とマークした を自由に変更してください。これを 1 増やすと、レートは 2 分の 1 になり、一意性の期間は 2 倍になります。したがって、たとえば、>>> 8代わりに、4 ミリ秒ごとに約 1 つの値を生成でき、値は 3200 日間繰り返されません。もちろん、ユーザーがシステムクロックをいじると、値が繰り返されないというこの保証はなくなります。ただし、これらの値は連続して生成されるわけではないため、同じ数を 2 回ヒットすることはほとんどありません。このコードは、URL をできるだけ短くするために、10 進数ではなく 6 文字のテキスト文字列 (base64) を生成します。

お役に立てれば。:)

于 2013-02-26T03:28:26.940 に答える
0

次のようなメッセージを表示するだけですが、エラーコードをスローする必要はないと思います

このページにアクセスするには、レベル XX である必要があります

コード 200-OK 自体を使用しているため、キャッシュの問題は発生せず、目的も達成されます。

于 2013-02-27T07:30:23.867 に答える