Upgrade to Pro — share decks privately, control downloads, hide ads and more …

HTTPリクエストの行方 - Laravelがレスポンスを返すまで

HTTPリクエストの行方 - Laravelがレスポンスを返すまで

Webアプリケーションはどうして動くのでしょうか

ブラウザ等のクライアントから送信されたHTTPリクエストを契機に、
Webアプリケーションでは様々なレイヤーでの情報処理が行われます

今回はその情報処理の流れをLaravelを例に追うことで、
Webサーバー、Laravelアプリケーション、データーベースと
レイヤー毎で行われている処理と、そのレイヤー毎のつなぎ込み部分に迫ります。

HTTPヘッダーを含むHTTPリクエストの流れを追って、真にWebアプリケーションがどうして動くのかを知り、
必要な処理をどこに組み込むことが効果的なのかを知る一助になれば幸いです。

shiro seike

August 27, 2022
Tweet

More Decks by shiro seike

Other Decks in Programming

Transcript

  1. 自己紹介
 清家 史郎
 @seike460
 - ID
 - GitHub:seike460
 - Twitter:@seike460


    - Work at
 - 株式会社 Fusic (フュージック) 
 技術開発本部/技術開発第一部門 
 - チームリーダー/プリンシパルエンジニア/ 
 エバンジェリスト
 - Skill
 - PHP/Go/AWS
 - Community
 - Fukuoka.php Organizer 
 - PHPカンファレンス沖縄2019 - 2022 
 PHPカンファレンス2018 - 2022 
 2

  2. Agenda
 3
 1. HTTPとは
 2. ClientからのHTTP Request
 3. Requestを受け取るWeb Server


    4. Requestを処理するPHPの世界
 5. PHPとDBのやり取り
 6. ResponseをClientに返却
 7. まとめ

  3. HTTP
 5
 Hypertext Transfer Protocol (HTTP) は HTML などのハイパーメディア文書を 


    転送するためのアプリケーション層プロトコル 
 ウェブブラウザー(クライアント)とウェブサーバー間の通信を目的として設計 
 ※他の用途でも使用されることが有り 
 
 HTTP は旧来のクライアント・サーバーモデルに則っており、クライアントはサーバーに 
 リクエストを送信するためにポートを開き、サーバー側からのレスポンスが返ってくるまで待機。 
 
 HTTP ヘッダーによって、プロトコルの拡張や実験が容易になっており 、新しい機能であっても、
 クライアントとサーバーが新たなヘッダーの意味について単純な合意があれば導入可能。 
 
 HTTP はいわゆるステートレスプロトコルであり、
 サーバーは二つのリクエスト間で何もデータを保持しない。 
 参考:MDN Web Docs「HTTP」: https://developer.mozilla.org/ja/docs/Web/HTTP

  4. telnetによるHTTPリクエスト
 14
 $ telnet www.httpbin.org 80
 Trying 3.94.154.124...
 Connected to

    www.httpbin.org.
 Escape character is '^]'.
 GET /get HTTP/1.1 ★実際に入力
 Host: httpbin.org ★実際に入力
 
 HTTP/1.1 200 OK
 Date: Wed, 17 Aug 2022 14:25:15 GMT
 Content-Type: application/json
 Content-Length: 197
 Connection: keep-alive
 Server: gunicorn/19.9.0
 Access-Control-Allow-Origin: *
 Access-Control-Allow-Credentials: true
 
 {
 "args": {},
 "headers": {
 "Host": "httpbin.org",
 "X-Amzn-Trace-Id": "Root=1-62fcfa4b-11ed483b37e7ba455a897f3a"
 },
 "origin": "125.56.55.69",
 "url": "http://httpbin.org/get"
 }
 telnetを利用しhttpbin.orgの 
 80番ポートに接続(HTTP標準ポート) 
 
 接続するHTTP Method (GET) 
 接続するURI (/get) 
 接続するHTTP Version(HTTP/1.1) 
 
 Host リクエストヘッダー(httpbin.org) 

  5. HTTP ヘッダー
 15
 HTTP リクエストやレスポンスでクライアントやサーバーが追加情報を渡す リクエストヘッダー … 読み込むリソースについての情報や、クライアントに関する詳細な情報 レスポンスヘッダー …

    レスポンスに関する追加情報(場所や提供しているサーバーに関する情報) エンティティヘッダー … リソースの本体に関する情報(MIMEタイプや適用されるエンコード/圧縮方式などについての情報) ペイロードヘッダー … 転送されるデータの表現から独立した情報(コンテンツ長さや転送エンコード方式) 参考:MDN Web Docs「HTTP」: https://developer.mozilla.org/ja/docs/Web/HTTP

  6. curlによるHTTPリクエスト
 16
 $ curl -v --http1.1 http://httpbin.org/get 
 
 *

    Trying 34.227.213.82:80... 
 * Connected to httpbin.org (34.227.213.82) port 80 (#0) 
 > GET /get HTTP/1.1 
 > Host: httpbin.org
 > User-Agent: curl/7.79.1 
 > Accept: */*
 >
 * Mark bundle as not supporting multiuse 
 < HTTP/1.1 200 OK 
 < Date: Fri, 19 Aug 2022 15:43:37 GMT 
 < Content-Type: application/json 
 < Content-Length: 253 
 < Connection: keep-alive 
 〜省略〜

  7. HTTPリクエストの構成要素
 17
 ▪リクエストライン
 GET … HTTP メソッド。クライアントが実行したい操作を定義する GET や POST等

    
 /get … リソースのパス 
 HTTP/1.1 … HTTP プロトコルのバージョン 
 > GET /get HTTP/1.1 
 
 ▪リクエストヘッダー 
 サーバーに追加の情報を与える任意のHTTPヘッダー 
 > Host: httpbin.org
 > User-Agent: curl/7.79.1 
 > Accept: */*
 
 ▪空行
 >
 ▪メッセージボディ
 POST等の場合はリクエスト内にボディが挿入されることがある。 

  8. 一般的なHTTPリクエストヘッダー
 20
 Accept: "*/*"
 クライアントが理解できるコンテンツタイプを MIME タイプで伝える
 
 Accept-Encoding: "gzip,

    deflate, br"
 コンテンツのエンコーディング、圧縮アルゴリズムのどれをクライアントが理解することができるかを示します。
 Apacheのmod_deflate等が利用
 gzip:Lempel-Ziv coding (LZ77) と32ビット CRC を用いた圧縮形式
 deflate:zlib 構造体と deflate 圧縮アルゴリズムを用いた圧縮形式
 br:Brotli アルゴリズムを用いた圧縮形式
 
 Accept-Language: "ja,en-US;q=0.9,en;q=0.8"
 クライアントがどの言語を理解できるか、どの種類のロケールが推奨されるかを示す
 
 Cache-Control: "max-age=0"
 キャッシュをコントロールするヘッダーで、 no-storeをつけることでキャッシュをさせなくしたり、
 有効期限を設定したりします。

  9. 拡張HTTPリクエストヘッダー
 21
 Sec-Fetch-Dest: "document", 
 Sec-Fetch-Mode: "navigate", 
 Sec-Fetch-Site: "none",

    
 Sec-Fetch-User: "?1", 
 フェッチメタデータリクエストヘッダー 
 リクエストの発信元のコンテキストに関する追加情報を提供する HTTP リクエストヘッダー 
 リクエストがどこから来たのかという追加情報をサーバーに提供し、悪意のあるリクエストを無視できるようになる 
 
 Sec-Ch-Ua: "" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"" 
 Sec-Ch-Ua-Mobile: "?0", 
 Sec-Ch-Ua-Platform: ""macOS"", 
 User-Agent Client Hints 
 ユーザーエージェント(UA)クライアントヒントヘッダにより、サーバーはユーザーエージェント(ブラウザ)、 
 オペレーティングシステム、デバイスに応じて応答を変化させることができる。 
 
 X-Amzn-Trace-Id: "Root=1-61eb64b7-24bc07aa6d8b197a203a12a9" 
 AWSが付与するTrace情報 
 Application Load Balancerが付与するIDで、リクエストの行方を追うために利用する 

  10. Sessionが利用するHTTPリクエストヘッダー
 22
 Cookie: "hoge=XxxxxxxxxxxxxxxxxxxxxxxxxxX" 
 
 サーバーが情報処理後、状態を維持するのに必要な情報をサーバーに保存して、セッションIDを発行 
 レスポンスヘッダーのSet-Cookie ヘッダーでセッションIDを送信

    
 保存されたCookieからセッションIDをリクエストヘッダーに付与する事で、最初に保存した状態の情報をやり取りする 
 
 詳しくは、PHPerKaigi2021 / PHPで学ぶ Session の基本と応用 / web-app-session-101 @hanhan1978

  11. POST リクエスト
 23
 $ curl -v -X POST --http1.1 http://httpbin.org/post

    
 * Trying 54.147.68.244:80... 
 * Connected to httpbin.org (54.147.68.244) port 80 (#0) 
 > POST /post HTTP/1.1 
 > Host: httpbin.org
 > User-Agent: curl/7.79.1 
 > Accept: */*
 >
 * Mark bundle as not supporting multiuse 
 < HTTP/1.1 200 OK 
 < Date: Fri, 19 Aug 2022 15:55:10 GMT 
 < Content-Type: application/json 
 < Content-Length: 317 
 〜省略〜

  12. POST Bodyの送信
 24
 $ curl -v -H "Content-Type: application/json" -d

    '{"hoge":"fuga"}' --http1.1 http://httpbin.org/post 
 * Trying 52.87.105.151:80... 
 * Connected to httpbin.org (52.87.105.151) port 80 (#0) 
 > POST /post HTTP/1.1 
 > Host: httpbin.org 
 > User-Agent: curl/7.79.1 
 > Accept: */*
 > Content-Type: application/json 
 > Content-Length: 15 
 >
 * Mark bundle as not supporting multiuse 
 < HTTP/1.1 200 OK 
 < Date: Fri, 19 Aug 2022 15:57:20 GMT 
 < Content-Type: application/json 
 < Content-Length: 426 
 < Connection: keep-alive 
 < Server: gunicorn/19.9.0 
 < Access-Control-Allow-Origin: * 
 < Access-Control-Allow-Credentials: true 
 <

  13. POST Bodyの送信
 25
 $ curl -v -H "Content-Type: application/json" -d

    '{"hoge":"fuga"}' --http1.1 --trace-ascii - http://httpbin.org/post 
 Warning: --trace-ascii overrides an earlier trace/verbose option 
 == Info: Trying 34.227.213.82:80... 
 == Info: Connected to httpbin.org (34.227.213.82) port 80 (#0) 
 => Send header, 132 bytes (0x84) 
 0000: POST /post HTTP/1.1 
 0015: Host: httpbin.org 
 0028: User-Agent: curl/7.79.1 
 0041: Accept: */* 
 004e: Content-Type: application/json 
 006e: Content-Length: 15 
 0082:
 => Send data, 15 bytes (0xf) 
 0000: {"hoge":"fuga"} 
 == Info: Mark bundle as not supporting multiuse 
 〜省略〜

  14. Webサーバー
 27
 HTTP Clientからのリクエストを受け付けてレスポンスを返却する HTTP Server Apache、Nginx 、あるいはPHP自身がWebサーバーになることも可能 ( php

    -S 0.0.0.0:80 ) 基本的には静的にコンテンツを返し、動的にレスポンスのコンテンツの内容を変更するのは プログラミング言語である PHP等の役目
  15. WebサーバーとPHP
 29
 静的コンテンツを返す Webサーバーが、なぜリクエストに応じた動的コンテンツを返すのかは Webサーバーの後ろに待ち構えているアプリケーション( PHP等)と連携しているから - Apache ModuleとしてPHPを動作させる -

    ApacheのプロセスとPHPのプロセスが分離していない - php-fpmを利用してFastCGIとしてPHPを動作させる - Webサーバーのプロセスと PHPのプロセスが分離している Nginxは並列性やメモリ効率、静的リソースの取り扱いに長けているので、 用途によっては選択することに意味を持たせることが出来ます
  16. php-fpm
 30
 FastCGI Process Manager (FPM) プロセスを落とすことなく CGIを高速化させる仕組み php-fpm(PHP-FastCGI Process

    Manager)が利用されるのが一般的 ポートでの通信や、Unixドメインソケットを介した通信がある ▪ポートを介した設定 [php-fpm] listen = 0.0.0.0:9000 ↓ [Nginx] fastcgi_pass XXX.XXX.XXX.XXX:9000 ▪Unixドメインソケットを介した設定(高速だが単独でのサーバー構成限定) [php-fpm] listen = /var/run/php-fpm/php-fpm.sock ↓ [Nginx] fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
  17. HTTPリクエスト情報をPHPで取得する
 35
 $ php -S localhost:8000 
 [Sat Jan 21

    23:01:11 2022] PHP 7.4.27 Development Server (http://localhost:8000) started 
 [Sat Jan 21 23:02:53 2022] [::1]:56677 Accepted 
 [Sat Jan 21 23:02:53 2022] [::1]:56677 [200]: GET / 
 [Sat Jan 21 23:02:53 2022] [::1]:56677 Closing 
 
 $ curl -v --http1.1 http://localhost:8000 

  18. Laravel public/index.php
 36
 $_SERVERに入った「HTTP_*」や 
 getallheaders()から得られるArrayから 
 HTTPヘッダーの情報を得られます 
 


    同じ様に$_GETや$_POSTを利用することで 
 HTTPリクエストの情報をPHPにて取得可能 
 
 一方スーパーグローバル変数をそのまま利用するのは 
 利用できるスコープの観点からもアンチパターン 
 
 では実際はどの様に処理しているのかを 
 Laravelを例に見てみます

  19. まとめ
 Point 2
 HTTPメッセージのやり取りを理解して、Webアプリケーションを理解する 
 60
 PHPは一般的にHTTPメッセージであるHTTPリクエストを契機にHTTPレスポンスを構築する
 Point 1
 


    各レイヤーの結合部は近代技術による抽象化により意識せずに開発が出来る
 Point 3
 Point 4
 どんな技術にも基礎はある。基礎技術を理解して正しいHTTPアプリケーション構築を行いましょう