前回の記事では、nginx がリクエスト ラインのデータを読み取って、リクエスト ラインを解析する方法について説明しました。この記事では、nginx がクライアントから送信されたリクエスト ヘッダー データを読み取って解析する方法について主に説明します。本質的には、リクエスト ラインとリクエスト ヘッダーのデータ読み取りプロセスは基本的に同じです。これは、どちらも断続的なデータ ストリームからデータを読み取る方法と、そのデータを処理する方法という問題に直面しているためです。 1. リクエストヘッダー読み取りメインプロセス リクエスト ヘッダーの読み取りプロセスを紹介する前に、まず http リクエスト メッセージの例を示します。 POST /web/book/read HTTP/1.1 ホスト: ローカルホスト 接続: キープアライブ コンテンツの長さ: 365 受け入れる: application/json、text/plain、*/* 例の最初のデータ行はリクエスト行であり、次の行はリクエスト ヘッダーです。各リクエスト ヘッダーは、名前: 値の形式で組み立てられ、各リクエスト ヘッダーは 1 行を占めます。 リクエスト ラインの読み取りプロセスを紹介した前回の記事では、リクエスト ラインが読み取られると、nginx は現在の読み取りイベントのコールバック関数を ngx_http_process_request_headers() メソッドに変更し、このメソッドを直接呼び出してリクエスト ヘッダー データの読み取りを試行することを説明しました。このメソッドは、リクエスト ライン データを読み取るメイン プロセスです。以下はこのメソッドのソース コードです。 /** * クライアントから送信されたヘッダーデータを解析する*/ 静的 void ngx_http_process_request_headers(ngx_event_t *rev) { u_char *p; size_t 長さ; ssize_t n; ngx_int_t rc、rv; ngx_table_elt_t *h; ngx_connection_t *c; ngx_http_header_t *hh; ngx_http_request_t *r; ngx_http_core_srv_conf_t *cscf; ngx_http_core_main_conf_t *cmcf; c = rev->データ; r = c->データ; もし (rev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "クライアントがタイムアウトしました"); c->タイムアウト = 1; ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); 戻る; } ngx_http_get_module_main_conf を r に設定します。 rc = NGX_AGAIN; のために (;;) { rc == NGX_AGAINの場合{ // 現在のヘッダーバッファに空きスペースがない場合は、新しいスペースを申請します if (r->header_in->pos == r->header_in->end) { // 新しいスペースを申請する rv = ngx_http_alloc_large_header_buffer(r, 0); rv == NGX_ERRORの場合{ ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 戻る; } // クライアントから送信されたヘッダーが長すぎて、large_client_header_buffers で指定された最大サイズを超えています if (rv == NGX_DECLINED) { p = r->ヘッダー名の開始; r->lingering_close = 1; (p == NULL)の場合{ ngx_log_error(NGX_LOG_INFO, c->log, 0, "クライアントが大きすぎるリクエストを送信しました"); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE); 戻る; } len = r->header_in->end - p; 長さが NGX_MAX_ERROR_STR - 300 以上のとき 長さ = NGX_MAX_ERROR_STR - 300; } ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE); 戻る; } } // 接続されたクライアントから新しく送信されたデータを読み取ろうとします n = ngx_http_read_request_header(r); (n == NGX_AGAIN || n == NGX_ERROR) の場合 { 戻る; } } cscf = ngx_http_get_module_srv_conf(r、ngx_http_core_module); // ここでは主に読み取ったデータを変換します rc = ngx_http_parse_header_line(r, r->header_in, cscf->underscores_in_headers); // NGX_OKは、解析とヘッダーデータの取得が成功したことを示します。if (rc == NGX_OK) { r->request_length += r->header_in->pos - r->header_name_start; // 無効なヘッダーをフィルタリングする (r->無効なヘッダー&&cscf->無効なヘッダーを無視){ 続く; } // ヘッダーを保存する構造体を作成します。h = ngx_list_push(&r->headers_in.headers); h == NULLの場合{ ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 戻る; } h->ハッシュ = r->ヘッダーハッシュ; // ヘッダー名をハッシュテーブルのキーとして使用します h->key.len = r->header_name_end - r->header_name_start; h->key.data = r->header_name_start; h->key.data[h->key.len] = '\0'; // ヘッダー値をハッシュテーブルの値として使用します h->value.len = r->header_end - r->header_start; h->value.data = r->header_start; h->値.data[h->値.len] = '\0'; h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); h->lowcase_key == NULLの場合{ ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 戻る; } h->key.len == r->lowcase_indexの場合{ ngx_memcpy(h->lowcase_key、r->lowcase_header、h->key.len); } それ以外 { ngx_strlow(h->lowcase_key、h->key.data、h->key.len); } // headers_in_hash はすべてのヘッダーを格納します。ここでは、現在のクライアントから送信されたヘッダーが有効なヘッダーであるかどうかを確認します。 hh = ngx_hash_find(&cmcf->headers_in_hash、h->hash、h->lowcase_key、h->key.len); // ここでのハンドラは、ngx_http_headers_in 内の各ヘッダーに対して定義された処理メソッドです。各ヘッダーの // handler() メソッドによって処理された後、クライアントから送信されたヘッダーは、r->headers_in 構造内のさまざまな属性に変換されます if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { 戻る; } 続く; } // NGX_HTTP_PARSE_HEADER_DONE はすべてのヘッダーが処理されたことを意味します if (rc == NGX_HTTP_PARSE_HEADER_DONE) { r->request_length += r->header_in->pos - r->header_name_start; r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; // クライアントから送信されたヘッダーデータの正当性を確認します rc = ngx_http_process_request_header(r); rc が NGX_OK の場合 { 戻る; } ngx_http_process_request() は、リクエストを処理するプロセスです。 戻る; } // NGX_AGAIN は、読み取ったヘッダー行のデータが不完全であり、さらに読み取る必要があることを示します if (rc == NGX_AGAIN) { 続く; } ngx_log_error(NGX_LOG_INFO, c->log, 0, "クライアントが無効なヘッダー行を送信しました"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); 戻る; } } ここでのリクエスト ヘッダーの読み取りは、主に次の手順に分かれます。
2. リクエストヘッダーデータの読み取り ご覧のとおり、リクエスト ヘッダーを読み取るための主なメソッドは ngx_http_read_request_header() と ngx_http_parse_header_line() の 2 つあります。ここでの 2 番目のメソッドは比較的長いですが、そのロジックは非常に単純です。主に、読み取ったデータを解析して、完全なリクエスト ヘッダー (名前: 値の形式で 1 行を占める) を形成できるかどうかを確認します。形成できる場合は NGX_OK を返し、そうでない場合は、データの読み取りを続行することを期待して NGX_AGAIN を返します。ここではこの方法については説明しません。読者は自分でソース コードを読むことができます。ここでは主に、ngx_http_read_request_header() メソッドがクライアントから送信されたリクエスト ヘッダー データを読み取る方法について説明します。 静的ssize_t ngx_http_read_request_header(ngx_http_request_t *r) { ssize_t n; ngx_event_t *rev; ngx_connection_t *c; ngx_http_core_srv_conf_t *cscf; c = r->接続; rev = c->読み取り; // まだ処理されていないデータの量を計算しま n = r->header_in->last - r->header_in->pos; // nが0より大きい場合は、まだ処理されていないデータがあることを意味するので、nを直接返します (n > 0) の場合 { n を返します。 } // ここに行くということは、現在読み込まれているデータが処理されたということなので、ここで判断が行われます。現在のイベントのreadyパラメータが1の場合、 // これは、現在の接続のハンドルに未読データが格納されているため、c->recv() メソッドが呼び出されてデータが読み取られることを意味します。それ以外の場合は、現在のイベントがイベント キューに追加され、現在の接続ハンドルの読み取りイベントが引き続き監視されます if (rev->ready) { // 接続ファイル記述子上のデータを読み取る n = c->recv(c, r->header_in->last, r->header_in->end - r->header_in->last); } それ以外 { n = NGX_AGAIN; } // n が NGX_AGAIN の場合、現在のイベントをイベント リスナーに追加し、現在の epoll ハンドルの読み取りイベントをリッスンし続けます if (n == NGX_AGAIN) { if (!rev->timer_set) { cscf = ngx_http_get_module_srv_conf(r、ngx_http_core_module); ngx_add_timer(rev、cscf->client_header_timeout); } ngx_handle_read_event(rev, 0) != NGX_OK の場合 { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); NGX_ERROR を返します。 } NGX_AGAIN を返します。 } // nが0の場合、クライアントが接続を閉じたことを意味します if (n == 0) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "クライアントが接続を途中で閉じました"); } // クライアントが接続を閉じるか異常な読み取りをした場合は、現在のリクエスト構造をリサイクルします if (n == 0 || n == NGX_ERROR) { c->エラー = 1; c->log->action = "クライアント要求ヘッダーを読み取っています"; ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); NGX_ERROR を返します。 } // 現在読み取られているデータ ポインターを更新します r->header_in->last += n; n を返します。 } ここでのリクエスト ヘッダー データの読み取りは、主に次の手順に分かれています。
3. まとめ この記事では、主に nginx がリクエスト ヘッダーを読み取って解析する方法について説明し、データを読み取るためのメイン プロセス コードと読み取りの詳細な手順に焦点を当てます。 nginx リクエスト ヘッダー データ読み取りプロセスの詳細な説明に関するこの記事はこれで終わりです。より関連性の高い nginx リクエスト ヘッダー データ読み取りコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
<<: React クラスコンポーネントのライフサイクルと実行順序
>>: mysql8.0.18 で winx64 をインストールするための詳細なチュートリアル (画像とテキスト付き)
目次ウェブパック5公式スタート建築ガイド構築を開始する依存する準備が完了したら、プロジェクトの構築を...
目次1. カスタム指示とは何ですか? 2. 指示をカスタマイズする方法フック機能3. 応用シナリオ入...
導入Alibaba Cloud のような OSS ストレージ サービスを使用している場合は、サービス...
目次1. ソリューション 1 (UDF)デモケース2. ソリューション2(binlogの解析)キャナ...
私がデザインした最初の Web ページは次のとおりです。 私はこの業界に7年間在籍し、プログラミング...
<br />原文: http://www.mikkolee.com/13私は最近、ver...
この記事では、参考までにMYSQLログとバックアップとリストアについて紹介します。具体的な内容は以下...
インストール手順1. 仮想マシンを作成する 2. [カスタム(詳細)]を選択し、[次へ]をクリックし...
監視ホストの追加ホスト 192.168.179.104 が zabbix 監視項目に追加されます (...
検索エンジン最適化 (SEO) では実行すべきタスクが多数ありますが、その中でもコードの最適化は重要...
序文:パーティショニングはテーブル設計パターンです。一般的に、テーブル パーティショニングとは、条件...
Hexo は Windows 10 でカスタムドメイン名を GitHub にバインドしますまずドメイ...
この記事では、例を使用して、MySQL のさまざまな一般的な結合テーブルクエリについて説明します。ご...
スタートアップ企業は、型破りな仕事のやり方、ユニークなビジネスモデル、特徴的な製品やサービス、パーソ...
問題の説明プロジェクトに取り組んでいるときに、タブ バーの切り替え効果を作成する必要がある場合があり...