7

概要: Django セッションに競合状態はありますか?どうすれば回避できますか?

同じユーザーによる同時リクエストによる競合状態が関係していると思われる Django セッションに関する興味深い問題があります。

複数のファイルを同時にアップロードするスクリプトで発生し、localhost でテストされています。これにより、同じユーザーからの同時リクエストが発生する可能性が非常に高いと思います(ローカルホストによる応答時間の短縮、ファイルのアップロードによる長いリクエスト)。ただし、localhost 以外の通常のリクエストは可能ですが、可能性は低くなります。

これを行うと思われるいくつかの(ファイル投稿)リクエストを送信しています:

  1. Django はユーザーのセッションを自動的に取得します*
  2. 時間がかかる無関係なコード
  3. 取得request.session['files'](辞書)
  4. 現在のファイルに関するデータを辞書に追加します
  5. 辞書をrequest.session['files']再度格納する
  6. 本当に保存されているか確認する
  7. 時間がかかる無関係なコードの増加
  8. Django はユーザーのセッションを自動的に保存します

ここで 6. のチェックは、情報が実際にセッションに保存されたことを示します。ただし、将来の要求は、ある場合とない場合があることを示しています。

私が考えているのは、これらの要求のうち 2 つ (A と B) が同時に発生していることです。リクエスト Arequest.session['files']が最初に取得し、次に B が同じことを行い、変更して保存します。A が最終的に終了すると、B によるセッションの変更が上書きされます。

2 つの質問:

  1. これは本当に起こっていることですか?django 開発サーバーはマルチスレッドですか? Google で、マルチスレッド化に関するページを見つけましたが、デフォルトではそうではないことを示唆していますか? それ以外の場合、何が問題になる可能性がありますか?
  2. この競合状態が問題である場合、それを解決する最善の方法は何でしょうか? 不便ではありますが、セキュリティ上の問題ではないので、その可能性を大幅に減らすことができれば幸いです.

変更の直前にセッションデータを取得し、直後に保存すると、チャンスが大幅に減少すると思います。request.sessionただし、 でこれを行う方法は見つかりませんでしたdjango.contrib.sessions.backends.db.SessionStore。ただし、そのように変更すると、Django はrequest.sessionリクエストの最後に上書きするだけだと思います。

したがって、基本的にrequest.session.reload()andが必要です。request.session.commit()

4

3 に答える 3

6
  1. はい、別のリクエストが完了する前にリクエストが開始される可能性があります。ビューの最初と最後に何かを出力し、同時に一連のリクエストを起動することで、これを確認できます。

  2. 実際、セッションはビューの前にロードされ、ビューの後に保存されます。を使用してセッションをリロードし、 を使用request.session = engine.SessionStore(session_key)して保存できrequest.session.save()ます。

ただし、セッションをリロードすると、その前に (ビュー内またはその前に) セッションに追加されたデータはすべて破棄されます。リロードする前に保存すると、ロードが遅くなるという点が失われます。より良い方法は、ファイルを新しいモデルとしてデータベースに保存することです。

答えの本質は、トーマスの答えの議論にありますが、これは不完全だったので、完全な答えを投稿しました。

于 2012-12-18T01:19:44.437 に答える
2

マークはそれを釘付けにしました。私からのマイナーな追加は、そのセッションをロードする方法です。

for key in session.keys():  # if you have potential removals
    del session[key]
session.update(session.load())
session.modified = False  # just making it clean

最初の行はオプションです。セッションから特定の値が削除される可能性がある場合にのみ必要です。

最後の行はオプションです。セッションを更新する場合、実際には問題になりません。

于 2013-09-10T10:16:10.563 に答える
1

それは本当です。をご覧いただくことでご確認いただけますdjango.contrib.sessions.middleware.SessionMiddleware

基本的に、はビューにヒットするrequest.session前にロードされ( )、がビューを離れた後 (必要に応じて) セッション バックエンドで更新されます ( )。requestprocess_requestresponseprocess_response

私の言いたいことがはっきりしない場合は、 Middleware の django ドキュメントを参照してください。


問題を解決する最善の方法は、その情報で何を達成しようとしているかによって異なります。その情報を提供していただければ、回答を更新します。

于 2012-12-06T16:49:18.480 に答える