以前、wsgi-intercept
を使った時に、PythonのHTTPライブラリとして、Requestsを使いました。
Requests: HTTP for Humans — Requests 2.13.0 documentation
使っている中で、RequestのCookieの使い方について迷ったことがあったため、メモを残します。
環境
Requestsを試すための用意したBottleアプリ
CookieをセットするだけのBottleアプリを用意しました。
仕様は
です。
from bottle import run, get, redirect, response @get('/') def get_root(): # Cookieにrootをセット response.set_cookie('root', 'foo') return 'Hello world' @get('/redirect') def get_redirect(): # Cookieにredirectをセットし、`/`へリダイレクト response.set_cookie('redirect', 'bar') redirect('/') if __name__ == "__main__": run(host='localhost', debug=True, reloader=True)
このBottleアプリが想定した動作をするか、Chromeで挙動を見てみます。
/
にアクセスした時
レスポンスヘッダを見ると、Cookieにroot
がセットされました。
Server:WSGIServer/0.2 CPython/3.6.1 Set-Cookie:root=foo
/redirect
へアクセスした時
リダイレクト元の/redirect
でのレスポンスヘッダを見ると、Cookieにredirect
がセットされました。
Location:http://localhost:8080/ Server:WSGIServer/0.2 CPython/3.6.1 Set-Cookie:redirect=bar
リダイレクト先の/
でのレスポンスヘッダでは、Cookieにroot
がセットされました。
Server:WSGIServer/0.2 CPython/3.6.1 Set-Cookie:root=foo
なお、リクエストヘッダを見ると、
Cookie:root=foo; redirect=bar Host:localhost:8080
と、2つのCookieが設定されていることも確認できました。
RequestsのResponseオブジェクトのCookieを使う
ドキュメントを見ると、ResponseオブジェクトにCookieがありました。
Cookies | Quickstart — Requests 2.13.0 documentation
そこで、reqeusts.Responseを使った
/
へGET/redirect
へGETし、/
へリダイレクト/redirect
へGETし、リダイレクトは行わない- requests.get()の引数に
allow_redirects=False
を設定 - Redirection and History | Quickstart — Requests 2.13.0 documentation
- requests.get()の引数に
という3種類テストコードを作成します。
なお、テストを試す時は、上記のBottleアプリを起動した後、テストコードを実行します。
/
へGET
def test_get(self): response = requests.get('http://localhost:8080') assert response.status_code == 200 assert response.cookies.get('root') == 'foo'
テストはパスしました。
/redirect
へGETし、/
へリダイレクト
def test_allow_redirect(self): response = requests.get('http://localhost:8080/redirect') assert response.status_code == 200 assert response.cookies.get('root') == 'foo' # ここで失敗する assert response.cookies.get('redirect') == 'bar' #=> AssertionError: assert None == 'bar'
テストが失敗しました。リダイレクト元のCookieは保持しないようです。
/redirect
へGETし、リダイレクトは行わない
def test_forbid_redirect(self): response = requests.get('http://localhost:8080/redirect', allow_redirects=False) assert response.status_code == 303 assert response.cookies.get('root') is None assert response.cookies.get('redirect') == 'bar'
リダイレクトしない時は、Cookieが正しくセットされています。
reqeusts.SessionオブジェクトのCookieを使う
ResponseオブジェクトのCookieでは、リダイレクトが発生するとCookieがなくなるため、あまり実用的ではないかもしれません。
他を探したところ、SessionオブジェクトにCookieがありました。
Using Python Requests: Sessions, Cookies, and POST - Stack Overflow
そこで、requests.Sessionオブジェクトを試してみます。
/
へGET
def test_get(self): session = requests.Session() response = session.get('http://localhost:8080') assert response.status_code == 200 # responseとsessionの両方にCookieがセットされる assert response.cookies.get('root') == 'foo' assert session.cookies.get('root') == 'foo'
テストがパスしました。
/redirect
へGETし、/
へリダイレクト
def test_allow_redirect(self): session = requests.Session() response = session.get('http://localhost:8080/redirect') assert response.status_code == 200 # Cookie「redirect」はsessionのみセットされる assert response.cookies.get('root') == 'foo' assert response.cookies.get('redirect') is None assert session.cookies.get('root') == 'foo' assert session.cookies.get('redirect') == 'bar'
テストがパスしました。
Responseオブジェクトと異なり、Sessionオブジェクトはリダイレクト時にもCookieの値を保持するようです。
/redirect
へGETし、リダイレクトは行わない
def test_forbid_redirect(self): session = requests.Session() response = session.get('http://localhost:8080/redirect', allow_redirects=False) assert response.status_code == 303 # responseとsessionの両方にCookieがセットされる assert response.cookies.get('root') is None assert response.cookies.get('redirect') == 'bar' assert session.cookies.get('root') is None assert session.cookies.get('redirect') == 'bar'
テストがパスしました。
requests.SessionオブジェクトをContext Managerとして使う
Requestsのドキュメントを読むと、requests.SessionはContext Managerとしても使えるようでした。
Session Objects | Advanced Usage — Requests 2.13.0 documentation
そのため、上記のSessionオブジェクトのコードは、以下の通りにも書けます。
def test_get(self): with requests.Session() as session: response = session.get('http://localhost:8080') assert response.status_code == 200 # responseとsessionの両方にCookieがセットされる assert response.cookies.get('root') == 'foo' assert session.cookies.get('root') == 'foo' def test_allow_redirect(self): with requests.Session() as session: response = session.get('http://localhost:8080/redirect') assert response.status_code == 200 # Cookie「redirect」はsessionのみセットされる assert response.cookies.get('root') == 'foo' assert response.cookies.get('redirect') is None assert session.cookies.get('root') == 'foo' assert session.cookies.get('redirect') == 'bar' def test_forbid_redirect(self): with requests.Session() as session: response = session.get('http://localhost:8080/redirect', allow_redirects=False) assert response.status_code == 303 # responseとsessionの両方にCookieがセットされる assert response.cookies.get('root') is None assert response.cookies.get('redirect') == 'bar' assert session.cookies.get('root') is None assert session.cookies.get('redirect') == 'bar'
ソースコード
GitHubにあげました。e.g._usage_cookie
が今回のサンプルです。
thinkAmi-sandbox/python_requests-sample