私の連絡先情報
郵便メール:
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
// core.ngx_core.h
typedef struct ngx_module_s ngx_module_t;
// core.ngx_module.h
struct ngx_module_s {
/* 表示当前模块在这个模块中的序号,
* 既表示模块的优先级,也表明模块的位置,
* 借以帮助Nginx框架快速获得某个模块的数据
*/
ngx_uint_t ctx_index;
/*
* 表示当前模块在ngx_modules数组中的序号,
* ctx_index表示当前模块在一类模块中的序号,
* index是在所有模块中的序号
*/
ngx_uint_t index;
// 模块名称
char *name;
// spare系列的保留变量
ngx_uint_t spare0;
ngx_uint_t spare1;
// 模块的版本号
ngx_uint_t version;
const char *signature; //
/*
* 用于指向一类模块的上下文结构体,
* Nginx模块有很多种类的模块,不同模块之间功能差距很大
* 事件类型的模块主要处理IO事件,HTTP类型模块主要处理HTTP应用层的功能
* ctx指向特定类型模块的公共接口,例如HTTP模块中,指向ngx_http_module_t
*/
void *ctx;
ngx_command_t *commands;// 将处理nginx.conf中的配置项
/*
* 模块的类型,有5种
* NGX_HTTP_MODULE,NGX_CORE_MODULE,NGX_CONF_MODULE,NGX_EVENT_MODULE,NGX_MALL_MODULE
* 实际上可以自己定义类型
* */
ngx_uint_t type;
/*
* 如下7个函数指针表示有7个执行点会分别调用这7个方法,对于任何一个方法
* 如果不需要Nginx在某个时刻执行它,那么可以简单的设置为NULL空指针即可
* */
// 当master进程启动时进行回调init_master,但是目前为止,框架代码从来不会调用,设置为NULL
ngx_int_t (*init_master)(ngx_log_t *log);
// init_module初始化所有模块时被调用,在master/worker模式下,这个阶段将在启动worker子进程前完成
ngx_int_t (*init_module)(ngx_cycle_t *cycle);
// 在正常服务前被调用,在master/worker模式下,多个worker子进程已经产生,在每个worker进程的初始化过程会调用所有模块的init_process
ngx_int_t (*init_process)(ngx_cycle_t *cycle);
// Nginx不支持多线程模式,所以init_thread在框架代码中没有被调用过,设置为NULL
ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
// exit_thread也不支持,设置为NULL
void (*exit_thread)(ngx_cycle_t *cycle);
// 在服务停止前调用,master/worker模式下,worker进程会在退出前调用它
void (*exit_process)(ngx_cycle_t *cycle);
// 在master进程退出前被调用
void (*exit_master)(ngx_cycle_t *cycle);
/*
* 以下8个变量也是保留字段,目前没有使用,但可用Nginx提供的NGX_MODULE_V1_PADDING宏来填充
* */
uintptr_t spare_hook0;
uintptr_t spare_hook1;
uintptr_t spare_hook2;
uintptr_t spare_hook3;
uintptr_t spare_hook4;
uintptr_t spare_hook5;
uintptr_t spare_hook6;
uintptr_t spare_hook7;
};
HTTP モジュールを定義する場合、コールバック メソッドのタイプは NGX_HTTP_MODULE に設定されます。init_module、init_process、exit_process、exit_master は、http{...} であっても、Nginx コードによって呼び出されます。が nginx.conf で定義されていない場合、この種のオープニング HTTP 機能の設定項目については、これらの破棄メソッドが引き続き呼び出されます。したがって、HTTP モジュールを開発するときは、通常、Web サーバーとして使用しない場合は NULL に設定され、HTTP モジュール内のコードは実行されません。
HTTP モジュールを定義するときに最後に行うことは、2 つのメンバー ctx とコマンドを設定することです。HTTP タイプのモジュールの場合、ctx は ngx_http_module_t インターフェイスを指します。
// http.ngx_http_config.h
typedef struct {
// 解析配置文件前被调用
ngx_int_t (*preconfiguration)(ngx_conf_t *cf);
// 完成配置文件的解析后调用
ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
//当需要创建数据结构用于存储main级别的全局配置项时,可以通过create_main_conf回调方法创建存储全局配置项的结构体
void *(*create_main_conf)(ngx_conf_t *cf);
// 常用与初始化main级别配置项
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
// 当需要创建数据结构用于存储srv级别的配置项时,可以通过create_srv_conf回调方法创建存储srv级别配置项的结构体
void *(*create_srv_conf)(ngx_conf_t *cf);
// 合并main级别和srv级别的同名配置项
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
// 当需要创建结构体用于存储loc级别的配置项时,可以实现create_loc_conf回调方法
void *(*create_loc_conf)(ngx_conf_t *cf);
// 合并srv级别和loc级别下的同名配置项
char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;
上記の 8 つのステージの呼び出し順序は、Nginx の起動プロセス中に定義された順序とは異なります。HTTP フレームワークがこれらのコールバック メソッドを呼び出す実際の順序は次のとおりです (nginx.conf 構成項目に関連します)。
1)main_confを作成する
2)srv_confを作成する
3)loc_confを作成する
4)事前設定
5)init_main_conf
6)マージ
7)マージ_loc_conf
8)ポスト構成
コマンド配列は、モジュールの構成ファイルのパラメーターを定義するために使用されます。配列の末尾は ngx_command_t で表され、Nginx が構成ファイル内の構成項目を解析するときに、最初にすべてのモジュールをコンパイルします。 . モジュールごと つまり、配列内で ngx_null_command が検出されると、現在のモジュールを使用して構成項目を解析することによって実行されます。
// core.ngx_core.h
typedef struct ngx_command_s ngx_command_t;
// core.ngx_conf_file.h
struct ngx_command_s {
ngx_str_t name;// 配置项名称,列入:gzip
ngx_uint_t type;// 配置项类型,指定可以出现的位置,例如server,location中以及它可以携带的参数个数
// 出现了name中指定的配置项后,将会调用set方法处理配置项的参数
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
// 在配置文件中的偏移量
ngx_uint_t conf;
// 通常用于预设的解析方法解析配置项
ngx_uint_t offset;
// 配置项读取后的处理方法,必须是ngx_conf_post_t结构体指针
void *post;
};
#define ngx_null_command { ngx_null_string, 0, NULL, 0, 0, NULL }
// http.modules.ngx_http_mytest_module.c
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
static char *ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_command_t ngx_http_mytest_commands[] = {
{
ngx_string("mytest"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS,
ngx_http_mytest,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL
},
ngx_null_command
};
static ngx_http_module_t ngx_http_mytest_module_ctx = {
NULL, /* preconfiguration */
NULL, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
ngx_module_t ngx_http_mytest_module = {
NGX_MODULE_V1,
&ngx_http_mytest_module_ctx, /* module context */
ngx_http_mytest_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static char *ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_mytest_handler;
return NGX_CONF_OK;
}
// http.ngx_http_core_module.h
typedef struct ngx_http_core_loc_conf_s ngx_http_core_loc_conf_t;
struct ngx_http_core_loc_conf_s {
ngx_str_t name; /* location name */
ngx_str_t escaped_name;
#if (NGX_PCRE)
ngx_http_regex_t *regex;
#endif
unsigned noname:1; /* "if () {}" block or limit_except */
unsigned lmt_excpt:1;
unsigned named:1;
unsigned exact_match:1;
unsigned noregex:1;
unsigned auto_redirect:1;
#if (NGX_HTTP_GZIP)
unsigned gzip_disable_msie6:2;
unsigned gzip_disable_degradation:2;
#endif
ngx_http_location_tree_node_t *static_locations;
#if (NGX_PCRE)
ngx_http_core_loc_conf_t **regex_locations;
#endif
/* pointer to the modules' loc_conf */
void **loc_conf;
uint32_t limit_except;
void **limit_except_loc_conf;
ngx_http_handler_pt handler;
/* location name length for inclusive location with inherited alias */
size_t alias;
ngx_str_t root; /* root, alias */
ngx_str_t post_action;
ngx_array_t *root_lengths;
ngx_array_t *root_values;
ngx_array_t *types;
ngx_hash_t types_hash;
ngx_str_t default_type;
off_t client_max_body_size; /* client_max_body_size */
off_t directio; /* directio */
off_t directio_alignment; /* directio_alignment */
size_t client_body_buffer_size; /* client_body_buffer_size */
size_t send_lowat; /* send_lowat */
size_t postpone_output; /* postpone_output */
size_t sendfile_max_chunk; /* sendfile_max_chunk */
size_t read_ahead; /* read_ahead */
size_t subrequest_output_buffer_size;
/* subrequest_output_buffer_size */
ngx_http_complex_value_t *limit_rate; /* limit_rate */
ngx_http_complex_value_t *limit_rate_after; /* limit_rate_after */
ngx_msec_t client_body_timeout; /* client_body_timeout */
ngx_msec_t send_timeout; /* send_timeout */
ngx_msec_t keepalive_time; /* keepalive_time */
ngx_msec_t keepalive_timeout; /* keepalive_timeout */
ngx_msec_t lingering_time; /* lingering_time */
ngx_msec_t lingering_timeout; /* lingering_timeout */
ngx_msec_t resolver_timeout; /* resolver_timeout */
ngx_msec_t auth_delay; /* auth_delay */
ngx_resolver_t *resolver; /* resolver */
time_t keepalive_header; /* keepalive_timeout */
ngx_uint_t keepalive_requests; /* keepalive_requests */
ngx_uint_t keepalive_disable; /* keepalive_disable */
ngx_uint_t satisfy; /* satisfy */
ngx_uint_t lingering_close; /* lingering_close */
ngx_uint_t if_modified_since; /* if_modified_since */
ngx_uint_t max_ranges; /* max_ranges */
ngx_uint_t client_body_in_file_only; /* client_body_in_file_only */
ngx_flag_t client_body_in_single_buffer;
/* client_body_in_singe_buffer */
ngx_flag_t internal; /* internal */
ngx_flag_t sendfile; /* sendfile */
ngx_flag_t aio; /* aio */
ngx_flag_t aio_write; /* aio_write */
ngx_flag_t tcp_nopush; /* tcp_nopush */
ngx_flag_t tcp_nodelay; /* tcp_nodelay */
ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */
ngx_flag_t absolute_redirect; /* absolute_redirect */
ngx_flag_t server_name_in_redirect; /* server_name_in_redirect */
ngx_flag_t port_in_redirect; /* port_in_redirect */
ngx_flag_t msie_padding; /* msie_padding */
ngx_flag_t msie_refresh; /* msie_refresh */
ngx_flag_t log_not_found; /* log_not_found */
ngx_flag_t log_subrequest; /* log_subrequest */
ngx_flag_t recursive_error_pages; /* recursive_error_pages */
ngx_uint_t server_tokens; /* server_tokens */
ngx_flag_t chunked_transfer_encoding; /* chunked_transfer_encoding */
ngx_flag_t etag; /* etag */
#if (NGX_HTTP_GZIP)
ngx_flag_t gzip_vary; /* gzip_vary */
ngx_uint_t gzip_http_version; /* gzip_http_version */
ngx_uint_t gzip_proxied; /* gzip_proxied */
#if (NGX_PCRE)
ngx_array_t *gzip_disable; /* gzip_disable */
#endif
#endif
#if (NGX_THREADS || NGX_COMPAT)
ngx_thread_pool_t *thread_pool;
ngx_http_complex_value_t *thread_pool_value;
#endif
#if (NGX_HAVE_OPENAT)
ngx_uint_t disable_symlinks; /* disable_symlinks */
ngx_http_complex_value_t *disable_symlinks_from;
#endif
ngx_array_t *error_pages; /* error_page */
ngx_path_t *client_body_temp_path; /* client_body_temp_path */
ngx_open_file_cache_t *open_file_cache;
time_t open_file_cache_valid;
ngx_uint_t open_file_cache_min_uses;
ngx_flag_t open_file_cache_errors;
ngx_flag_t open_file_cache_events;
ngx_log_t *error_log;
ngx_uint_t types_hash_max_size;
ngx_uint_t types_hash_bucket_size;
ngx_queue_t *locations;
#if 0
ngx_http_core_loc_conf_t *prev_location;
#endif
};
typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);
// http.ngx_http_request.h
#define NGX_HTTP_CONTINUE 100
#define NGX_HTTP_SWITCHING_PROTOCOLS 101
#define NGX_HTTP_PROCESSING 102
#define NGX_HTTP_OK 200
#define NGX_HTTP_CREATED 201
#define NGX_HTTP_ACCEPTED 202
#define NGX_HTTP_NO_CONTENT 204
#define NGX_HTTP_PARTIAL_CONTENT 206
#define NGX_HTTP_SPECIAL_RESPONSE 300
#define NGX_HTTP_MOVED_PERMANENTLY 301
#define NGX_HTTP_MOVED_TEMPORARILY 302
#define NGX_HTTP_SEE_OTHER 303
#define NGX_HTTP_NOT_MODIFIED 304
#define NGX_HTTP_TEMPORARY_REDIRECT 307
#define NGX_HTTP_PERMANENT_REDIRECT 308
#define NGX_HTTP_BAD_REQUEST 400
#define NGX_HTTP_UNAUTHORIZED 401
#define NGX_HTTP_FORBIDDEN 403
#define NGX_HTTP_NOT_FOUND 404
#define NGX_HTTP_NOT_ALLOWED 405
#define NGX_HTTP_REQUEST_TIME_OUT 408
#define NGX_HTTP_CONFLICT 409
#define NGX_HTTP_LENGTH_REQUIRED 411
#define NGX_HTTP_PRECONDITION_FAILED 412
#define NGX_HTTP_REQUEST_ENTITY_TOO_LARGE 413
#define NGX_HTTP_REQUEST_URI_TOO_LARGE 414
#define NGX_HTTP_UNSUPPORTED_MEDIA_TYPE 415
#define NGX_HTTP_RANGE_NOT_SATISFIABLE 416
#define NGX_HTTP_MISDIRECTED_REQUEST 421
#define NGX_HTTP_TOO_MANY_REQUESTS 429
/* Our own HTTP codes */
/* The special code to close connection without any response */
#define NGX_HTTP_CLOSE 444
#define NGX_HTTP_NGINX_CODES 494
#define NGX_HTTP_REQUEST_HEADER_TOO_LARGE 494
#define NGX_HTTPS_CERT_ERROR 495
#define NGX_HTTPS_NO_CERT 496
/*
* We use the special code for the plain HTTP requests that are sent to
* HTTPS port to distinguish it from 4XX in an error page redirection
*/
#define NGX_HTTP_TO_HTTPS 497
/* 498 is the canceled code for the requests with invalid host name */
/*
* HTTP does not define the code for the case when a client closed
* the connection while we are processing its request so we introduce
* own code to log such situation when a client has closed the connection
* before we even try to send the HTTP header to it
*/
#define NGX_HTTP_CLIENT_CLOSED_REQUEST 499
#define NGX_HTTP_INTERNAL_SERVER_ERROR 500
#define NGX_HTTP_NOT_IMPLEMENTED 501
#define NGX_HTTP_BAD_GATEWAY 502
#define NGX_HTTP_SERVICE_UNAVAILABLE 503
#define NGX_HTTP_GATEWAY_TIME_OUT 504
#define NGX_HTTP_VERSION_NOT_SUPPORTED 505
#define NGX_HTTP_INSUFFICIENT_STORAGE 507
上記の戻り値には、RFC2616 仕様で定義されているリターン コードに加えて、Nginx 自体で定義されている HTTP リターン コードも含まれます。例: NGX_HTTP_CLOSE は、HTTP フレームワークにユーザー接続を直接閉じるように要求するために使用されます。
Nginx全局定义的错误码
// core.ngx_core.h
#define NGX_OK 0
#define NGX_ERROR -1
#define NGX_AGAIN -2
#define NGX_BUSY -3
#define NGX_DONE -4
#define NGX_DECLINED -5
#define NGX_ABORT -6
最後に ngx_http_output_filter を呼び出してユーザーに応答パケットを送信するとき、ngx_http_output_filter の戻り値を ngx_http_mytest_handler メソッドの戻り値として使用できます。
// http.ngx_http.h
typedef struct ngx_http_request_s ngx_http_request_t;
// http.ngx_http_request.h
struct ngx_http_request_s {
...
ngx_uint_t method;
ngx_uint_t http_version;
ngx_str_t request_line;
ngx_str_t uri;
ngx_str_t args;
ngx_str_t exten;
ngx_str_t unparsed_uri;
ngx_str_t method_name;
ngx_str_t http_protocol;
ngx_str_t schema;
...
u_char *uri_start;
u_char *uri_end;
u_char *uri_ext;
u_char *args_start;
u_char *request_start;
u_char *request_end;
u_char *method_end;
u_char *schema_start;
u_char *schema_end;
...
}
// http.ngx_http_request.h
ngx_uint_t method;
// http.ngx_http_request.h
#define NGX_HTTP_UNKNOWN 0x00000001
#define NGX_HTTP_GET 0x00000002
#define NGX_HTTP_HEAD 0x00000004
#define NGX_HTTP_POST 0x00000008
#define NGX_HTTP_PUT 0x00000010
#define NGX_HTTP_DELETE 0x00000020
#define NGX_HTTP_MKCOL 0x00000040
#define NGX_HTTP_COPY 0x00000080
#define NGX_HTTP_MOVE 0x00000100
#define NGX_HTTP_OPTIONS 0x00000200
#define NGX_HTTP_PROPFIND 0x00000400
#define NGX_HTTP_PROPPATCH 0x00000800
#define NGX_HTTP_LOCK 0x00001000
#define NGX_HTTP_UNLOCK 0x00002000
#define NGX_HTTP_PATCH 0x00004000
#define NGX_HTTP_TRACE 0x00008000
#define NGX_HTTP_CONNECT 0x00010000
メソッドの取得方法
ngx_str_t uri;
ngx_str_t unparsed_uri;
u_char *uri_start;
u_char *uri_end;
u_char *uri_ext;
uri はリクエスト内の URI を表し、uri_start と uri_end も取得できます。
exten メンバー変数は、ユーザーが要求したファイル拡張子を指します。
unparsed_uri は、URL デコードを行わない元のリクエストを表します。たとえば、uri が /ab の場合、unparsed_uri は /a%20b になります。
args は、ユーザーのリクエスト内の URL パラメーターを指します。同様に、args_start と uri_end も URL を取得できます。
http_protocol の data メンバーはユーザー要求内の HTTP プロトコル バージョン文字列を指し、len メンバーはプロトコル バージョン文字列の長さです。
http_version は、Nginx によって解析されたプロトコルのバージョンです。
ngx_uint_t http_version;
#define NGX_HTTP_VERSION_9 9
#define NGX_HTTP_VERSION_10 1000
#define NGX_HTTP_VERSION_11 1001
#define NGX_HTTP_VERSION_20 2000
#define NGX_HTTP_VERSION_30 3000
HTTP プロトコルのバージョンを分析するには http_version を使用することをお勧めします。
request_start と request_end を使用して、元のユーザー リクエスト行を取得します。
struct ngx_http_request_s {
...
ngx_buf_t *header_in;
ngx_http_headers_in_t headers_in;
...
}
header_in は、Nginx によって受信された未解析の HTTP ヘッダーを指します。ここでは、ngx_http_headers_in_t 型の headers_in は解析された HTTP ヘッダーを格納するバッファーです。
// http.ngx_http_request.h
typedef struct {
//所有解析过的HTTP头部都在headers链表中
ngx_list_t headers;
// 每个ngx_table_elt_t成员都是RFC2616规范定义的HTTP头部,
// 它们实际上指向headers链表中相应成员,当为NULL时表示没有解析到相应的HTTP头部
ngx_table_elt_t *host;
ngx_table_elt_t *connection;
ngx_table_elt_t *if_modified_since;
ngx_table_elt_t *if_unmodified_since;
ngx_table_elt_t *if_match;
ngx_table_elt_t *if_none_match;
ngx_table_elt_t *user_agent;
ngx_table_elt_t *referer;
ngx_table_elt_t *content_length;
ngx_table_elt_t *content_range;
ngx_table_elt_t *content_type;
ngx_table_elt_t *range;
ngx_table_elt_t *if_range;
ngx_table_elt_t *transfer_encoding;
ngx_table_elt_t *te;
ngx_table_elt_t *expect;
ngx_table_elt_t *upgrade;
#if (NGX_HTTP_GZIP || NGX_HTTP_HEADERS)
ngx_table_elt_t *accept_encoding;
ngx_table_elt_t *via;
#endif
ngx_table_elt_t *authorization;
ngx_table_elt_t *keep_alive;
#if (NGX_HTTP_X_FORWARDED_FOR)
ngx_table_elt_t *x_forwarded_for;
#endif
#if (NGX_HTTP_REALIP)
ngx_table_elt_t *x_real_ip;
#endif
#if (NGX_HTTP_HEADERS)
ngx_table_elt_t *accept;
ngx_table_elt_t *accept_language;
#endif
#if (NGX_HTTP_DAV)
ngx_table_elt_t *depth;
ngx_table_elt_t *destination;
ngx_table_elt_t *overwrite;
ngx_table_elt_t *date;
#endif
ngx_table_elt_t *cookie;
// 只有ngx_http_auth_basic_module才会用到的成员
ngx_str_t user;
ngx_str_t passwd;
// server名称
ngx_str_t server;
// 计算出的HTTP包体大小(ngx_table_elt_t * content_length)
off_t content_length_n;
time_t keep_alive_n;
// HTTP连接类型,取值范围是0,
// #define NGX_HTTP_CONNECTION_CLOSE 1
//#define NGX_HTTP_CONNECTION_KEEP_ALIVE 2
unsigned connection_type:2;
unsigned chunked:1;
unsigned multi:1;
unsigned multi_linked:1;
// 以下7个标志位是 HTTP框架根据浏览器传来的useragent头部,可以判断浏览器的类型,只为1表示相应的浏览器发来的请求
unsigned msie:1;
unsigned msie6:1;
unsigned opera:1;
unsigned gecko:1;
unsigned chrome:1;
unsigned safari:1;
unsigned konqueror:1;
} ngx_http_headers_in_t;
例: 珍しい HTTP リクエスト ヘッダーを見つける方法。headers_in.headers のみをトラバースできます。
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r) {
...
ngx_list_part_t *part = &r->header_in.headers.part;
ngx_table_elt_t *header = part->elts;
for (i = 0;; ++i) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
header = part->elts;
i = 0;
}
if (header[i].hash == 0){
continue;
}
if (0 == ngx_strncasecmp(header[i].key.data,(u_char*) "Rpc-Description",header[i].key.len)){
if (0 == ngx_strncmp(header[i].value.data,"uploadFile",header[i].value.len)){
// 找到了正确的头,继续向下执行
}
}
}
...
}
HTTP パケット本体の長さが非常に長い場合、すべてのパケット本体を一度に呼び出して読み取ろうとすると、nginx プロセスがブロックされる可能性があります。HTTP フレームワークは、パケット本体を受信する非同期メソッドを提供します。
ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r,
ngx_http_client_body_handler_pt post_handler);
これは非同期メソッドです。この呼び出しは、要求されたパッケージ本体の受け入れを開始するために Nginx が必要であることを示すだけであり、パッケージ本体の内容がすべて受信されたときに、post_handler によって指定されたコールバック メソッドが通知されます。呼び戻される。
応答には、応答行、応答ヘッダー、パッケージ本体の 3 つの部分が含まれます。
ngx_int_t ngx_http_send_header(ngx_http_request_t *r)
struct ngx_http_request_s {
ngx_http_headers_out_t headers_out;
}
typedef struct {
ngx_list_t headers;
ngx_list_t trailers;
ngx_uint_t status;
ngx_str_t status_line;
ngx_table_elt_t *server;
ngx_table_elt_t *date;
ngx_table_elt_t *content_length;
ngx_table_elt_t *content_encoding;
ngx_table_elt_t *location;
ngx_table_elt_t *refresh;
ngx_table_elt_t *last_modified;
ngx_table_elt_t *content_range;
ngx_table_elt_t *accept_ranges;
ngx_table_elt_t *www_authenticate;
ngx_table_elt_t *expires;
ngx_table_elt_t *etag;
ngx_table_elt_t *cache_control;
ngx_table_elt_t *link;
ngx_str_t *override_charset;
size_t content_type_len;
ngx_str_t content_type;
ngx_str_t charset;
u_char *content_type_lowcase;
ngx_uint_t content_type_hash;
off_t content_length_n;
off_t content_offset;
time_t date_time;
time_t last_modified_time;
} ngx_http_headers_out_t;
リクエストヘッダーを追加する
ngx_table_elt_t h = ngx_list_push(&r->headers_out.headers);
if (h == NULL){
return NGX_ERROR
}
h.hash = 1;
h.key.len = sizeof("TestHeader") - 1;
h.key.data = (u_char *) "TestHeader";
h.value.len = sizeof("TestValue") - 1;
h.value.data = (u_char *) "TestValue" ;
ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
HTTPレスポンスボディをクライアントに送信する
ngx_buf_t *b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
b->start = (u_char*)ngx_pcalloc(r->pool,128);
b->pos = b->start;
b->last = b->start;
b->end = b->last + 128;
b->temporary = 1;
// 等同于如下
ngx_buf_t *b = ngx_create_temp_buf(r->pool,128)
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r) {
// 必须为GET或者HEAD,否则返回405
if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))){
return NGX_HTTP_NOT_ALLOWED;
}
// 丢弃请求中的包体
ngx_int_t rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK){
return rc;
}
// 设置返回类型
ngx_str_t type = ngx_string("text/plain");
// 设置返回体
ngx_str_t response = ngx_string("Hello World!");
// 设置响应码
r->headers_out.status = NGX_HTTP_OK;
// 设置响应体大小
r->headers_out.content_length_n = response.len;
// 设置类型
r->headers_out.content_type = type;
// 发送HTTP头部
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only){
return rc;
}
// 构造ngx_buf_t结构体发送包体
ngx_buf_t *b;
b = ngx_create_temp_buf(r->pool,response.len);
if (b == NULL){
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
// 将hello world复制到ngx_buf_t指向的内存中
ngx_memcpy(b->pos,response.data,response.len);
// 注意设置好last指针
b->last = b->pos + response.len;
// 声明这是最后一块缓冲区
b->last_buf = 1;
// 构造发送时的ngx_chain_t结构体
ngx_chain_t out;
out.buf = b;
out.next = NULL;
// 发送包体
return ngx_http_output_filter(r,&out);
}
ngx_buf_t の in_file を 1 に設定し、バッファがメモリではなくファイルであることを示します。 ファイルは ngx_file_t で、構造は次のとおりです。
struct ngx_file_s {
ngx_fd_t fd;// 文件句柄描述符
ngx_str_t name;// 文件名称
ngx_file_info_t info;// 文件大小等基本信息,就是Linux系统定义的stat结构
off_t offset;// 表示处理到文件何处了
off_t sys_offset;// 当前文件系统偏移量
ngx_log_t *log;// 日志对象,相关的日志会输出到log指定的日志文件中
#if (NGX_THREADS || NGX_COMPAT)
ngx_int_t (*thread_handler)(ngx_thread_task_t *task,
ngx_file_t *file);
void *thread_ctx;
ngx_thread_task_t *thread_task;
#endif
#if (NGX_HAVE_FILE_AIO || NGX_COMPAT)
ngx_event_aio_t *aio;
#endif
unsigned valid_info:1;
unsigned directio:1;// 在发送大文件时可以设置为1
};