3.7 发送响应
请求处理完毕后,需要向用户发送HTTP响应,告知客户端Nginx的执行结果。HTTP响应主要包括响应行、响应头部、包体三部分。发送HTTP响应时需要执行发送HTTP头部(发送HTTP头部时也会发送响应行)和发送HTTP包体两步操作。本节将以发送经典的“Hello World”为例来说明如何发送响应。
3.7.1 发送HTTP头部
下面看一下HTTP框架提供的发送HTTP头部的方法,如下所示。
ngx_int_t ngx_http_send_header(ngx_http_request_t*r);
调用ngx_http_send_header时把ngx_http_request_t对象传给它即可,而ngx_http_request_t的返回值是多样的,在本节中,可以认为返回NGX_ERROR或返回值大于0就表示不正常,例如:
ngx_int_t rc=ngx_http_send_header(r);
if(rc==NGX_ERROR||rc>NGX_OK||r->header_only){
return rc;
}
下面介绍设置响应中的HTTP头部的过程。
如同headers_in,ngx_http_request_t也有一个headers_out成员,用来设置响应中的HTTP头部,如下所示。
struct ngx_http_request_s{
……
ngx_http_headers_in_t
headers_in;
ngx_http_headers_out_t
headers_out;
……
};
只要指定headers_out中的成员,就可以在调用ngx_http_send_header时正确地把HTTP头部发出。下面介绍headers_out的结构类型ngx_http_headers_out_t。
typedef struct{
//待发送的HTTP头部链表,与headers_in中的headers成员类似
ngx_list_t
headers;
/响应中的状态值,如200表示成功。这里可以使用3.6.1节中介绍过的各个宏,如NGX_HTTP_OK/
ngx_uint_t
status;
//响应的状态行,如“HTTP/1.1 201 CREATED”
ngx_str_t
status_line;
/以下成员(包括ngx_table_elt_t)都是RFC1616规范中定义的HTTP头部,设置后,ngx_http_header_filter_module过滤模块可以把它们加到待发送的网络包中/
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_str_t
*override_charset;
/可以调用ngx_http_set_content_type(r)方法帮助我们设置Content-Type头部,这个方法会根据URI中的文件扩展名并对应着mime.type来设置Content-Type值/
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;
ngx_array_t
cache_control;
/在这里指定过content_length_n后,不用再次到ngx_table_elt_tcontent_length中设置响应长度*/
off_t
content_length_n;
time_t
date_time;
time_t
last_modified_time;
}ngx_http_headers_out_t;
在向headers链表中添加自定义的HTTP头部时,可以参考3.2.3节中ngx_list_push的使用方法。这里有一个简单的例子,如下所示。
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("TestHead")-1;
h->key.data=(u_char*)"TestHead";
h->value.len=sizeof("TestValue")-1;
h->value.data=(u_char*)"TestValue";
这样将会在响应中新增一行HTTP头部:
TestHead:TestValud\r\n
如果发送的是一个不含有HTTP包体的响应,这时就可以直接结束请求了(例如,在ngx_http_mytest_handler方法中,直接在ngx_http_send_header方法执行后将其返回值return即可)。
注意 ngx_http_send_header方法会首先调用所有的HTTP过滤模块共同处理headers_out中定义的HTTP响应头部,全部处理完毕后才会序列化为TCP字符流发送到客户端,相关流程可参见11.9.1节。