我是靠谱客的博主 年轻含羞草,最近开发中收集的这篇文章主要介绍nginx 处理http(发送http响应头数据篇 ----- ngx_http_header_filter_module模块处理),觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
http状态行
响应头
Server
//响应server名
Date
//响应头日期
Content-Length
//内容长度
Content-Encoding
//内容编码格式
Location
//响应的location头
Last-Modified
//响应的last-modified头
Accept-Ranges
//响应的range大小单位类型
Expires
//响应的expires过期头
Cache-Control
//Cache-Control响应头
Etag
//响应的Etag头
nginx发送http响应头数据的处理流程
1.配置响应头处理filter函数
static ngx_int_t
ngx_http_header_filter_init(ngx_conf_t *cf)
{
/*设置top_header_filter函数指针 形成链式的top_header_filter处理结构*/
ngx_http_top_header_filter = ngx_http_header_filter;
return NGX_OK;
}
2.http响应头数据发送的实际流程
static ngx_int_t
ngx_http_header_filter(ngx_http_request_t *r)
{
...
if (r->header_sent) {
/*header_sent为真 说明头部数据已经发送过了 直接返回即可*/
return NGX_OK;
}
/*标记头部数据已经发送*/
r->header_sent = 1;
if (r != r->main) {
/*当前处理的不是主请求 返回 (只有主请求才能发送响应头数据)*/
return NGX_OK;
}
if (r->http_version < NGX_HTTP_VERSION_10) {
/*只处理在1.0及以上版本的http类型*/
return NGX_OK;
}
if (r->method == NGX_HTTP_HEAD) {
/*如果请求的方法是head 则只需要发送头部数据即可*/
r->header_only = 1;
}
if (r->headers_out.last_modified_time != -1) {
/*响应头有last-modified-time信息*/
if (r->headers_out.status != NGX_HTTP_OK
&& r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT
&& r->headers_out.status != NGX_HTTP_NOT_MODIFIED)
{
/*响应头不是正常的200/206/304响应码 直接设置last-modified-time为无效*/
r->headers_out.last_modified_time = -1;
r->headers_out.last_modified = NULL;
}
}
/*取得响应数据的初始长度*/
len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1
/* the end of the header */
+ sizeof(CRLF) - 1;
/* status line */
if (r->headers_out.status_line.len) {
/*存在响应状态行信息 增加响应数据长度及获取状态行数据*/
len += r->headers_out.status_line.len;
status_line = &r->headers_out.status_line;
#if (NGX_SUPPRESS_WARN)
status = 0;
#endif
} else {
/*如果没有响应状态行数据*/
status = r->headers_out.status;
if (status >= NGX_HTTP_OK
&& status < NGX_HTTP_LAST_2XX)
{
/*响应的状态码是2XX*/
/* 2XX */
if (status == NGX_HTTP_NO_CONTENT) {
/*状态码表示没有内容 即响应为空*/
r->header_only = 1;
//标记只有响应头而没有响应的包体
/*以下的数据无用 设置成无效值*/
ngx_str_null(&r->headers_out.content_type);
r->headers_out.last_modified_time = -1;
r->headers_out.last_modified = NULL;
r->headers_out.content_length = NULL;
r->headers_out.content_length_n = -1;
}
/*得到状态值的数组索引值*/
status -= NGX_HTTP_OK;
/*取得状态行数据*/
status_line = &ngx_http_status_lines[status];
/*增加需要发送的数据长度*/
len += ngx_http_status_lines[status].len;
} else if (status >= NGX_HTTP_MOVED_PERMANENTLY
&& status < NGX_HTTP_LAST_3XX)
{ /*如果响应的状态码是3XX*/
/* 3XX */
if (status == NGX_HTTP_NOT_MODIFIED) {
/*304内容无变化 只需要发送响应头即可*/
r->header_only = 1;
}
/*取得状态行的索引*/
status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX;
/*得到状态行的数据*/
status_line = &ngx_http_status_lines[status];
/*增加需发送的数据长度*/
len += ngx_http_status_lines[status].len;
} else if (status >= NGX_HTTP_BAD_REQUEST
&& status < NGX_HTTP_LAST_4XX)
{
/*响应的状态码是4XX*/
/* 4XX */
/*得到状态行的索引值*/
status = status - NGX_HTTP_BAD_REQUEST
+ NGX_HTTP_OFF_4XX;
/*取得状态行数据*/
status_line = &ngx_http_status_lines[status];
/*增加发送数据的长度*/
len += ngx_http_status_lines[status].len;
} else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR
&& status < NGX_HTTP_LAST_5XX)
{
/*响应的状态码是5XX*/
/* 5XX */
/*取得响应状态行的索引值*/
status = status - NGX_HTTP_INTERNAL_SERVER_ERROR
+ NGX_HTTP_OFF_5XX;
/*得到状态行的数据和增加响应数据的长度*/
status_line = &ngx_http_status_lines[status];
len += ngx_http_status_lines[status].len;
} else {
/*其他响应状态码*/
len += NGX_INT_T_LEN + 1 /* SP */;
/*响应的状态行是空的*/
status_line = NULL;
}
if (status_line && status_line->len == 0) {
/*有响应状态行数据但是长度是0*/
status = r->headers_out.status;
len += NGX_INT_T_LEN + 1 /* SP */;
status_line = NULL;
}
}
/*得到http的location作用域的配置*/
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (r->headers_out.server == NULL) {
/*增加响应头的server数据 增加响应数据的长度*/
len += clcf->server_tokens ? sizeof(ngx_http_server_full_string) - 1:
sizeof(ngx_http_server_string) - 1;
}
if (r->headers_out.date == NULL) {
/*没有设置响应头的日期 就是用unix的初始时间*/
len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
}
if (r->headers_out.content_type.len) {
/*响应头存在content-type 增加响应数据长度*/
len += sizeof("Content-Type: ") - 1
+ r->headers_out.content_type.len + 2;
if (r->headers_out.content_type_len == r->headers_out.content_type.len
&& r->headers_out.charset.len)
{/*响应头有字符集信息 增加需发送的数据长度*/
len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
}
}
if (r->headers_out.content_length == NULL
&& r->headers_out.content_length_n >= 0)
{
/*
没有设置content-length头但是是具有conte-length长度数据
增加响应数据的长度 会在http响应头中发送content-length头
*/
len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2;
}
if (r->headers_out.last_modified == NULL
&& r->headers_out.last_modified_time != -1)
{
/*同上*/
len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
}
/*取得请求对应的tcp连接*/
c = r->connection;
if (r->headers_out.location
&& r->headers_out.location->value.len
&& r->headers_out.location->value.data[0] == '/')
{
/*响应头存在location数据*/
r->headers_out.location->hash = 0;
if (clcf->server_name_in_redirect) {
/*如果location域配置了redirect 即location重定向*/
/*取得http server域的配置*/
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
/*得到配置的server名称*/
host = cscf->server_name;
} else if (r->headers_in.server.len) {
/*如果请求头有sever信息 使用请求头的sever*/
host = r->headers_in.server;
} else {
/*http没有配置并且请求头没有server信息*/
host.len = NGX_SOCKADDR_STRLEN;
host.data = addr;
if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) {
/*直接使用本地的主机名*/
return NGX_ERROR;
}
}
switch (c->local_sockaddr->sa_family) {
/*判断连接的ip协议类型*/
#if (NGX_HAVE_INET6)
case AF_INET6:
/*ipv6类型 得到ipv6的地址和端口数据*/
sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
port = ntohs(sin6->sin6_port);
break;
#endif
#if (NGX_HAVE_UNIX_DOMAIN)
case AF_UNIX:
/*unix 类型 端口值设置为0*/
port = 0;
break;
#endif
default: /* AF_INET */
/*ipv4*/
sin = (struct sockaddr_in *) c->local_sockaddr;
port = ntohs(sin->sin_port);
break;
}
/*相应的location头的数据长度 增加到响应头数据的长度中*/
len += sizeof("Location: https://") - 1
+ host.len
+ r->headers_out.location->value.len + 2;
if (clcf->port_in_redirect) {
/*http server域配置了端口跳转*/
#if (NGX_HTTP_SSL)
if (c->ssl)
/*443-> 0*/
port = (port == 443) ? 0 : port;
else
#endif
/*80 -> 0*/
port = (port == 80) ? 0 : port;
} else {
/*默认端口为0*/
port = 0;
}
if (port) {
/*端口值不为0 增加响应数据长度*/
len += sizeof(":65535") - 1;
}
} else {
/*没有location响应头 host置为空值 端口也设置成0*/
ngx_str_null(&host);
port = 0;
}
if (r->chunked) {
/*数据传输的类型是chunked 增加chunked头的数据长度*/
len += sizeof("Transfer-Encoding: chunked" CRLF) - 1;
}
if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
/*响应的头状态码为协议切换
增加upgrade类型 connection头数据*/
len += sizeof("Connection: upgrade" CRLF) - 1;
} else if (r->keepalive) {
/*如果请求是keepalive类型的 增加keep-alive的头数据信息*/
len += sizeof("Connection: keep-alive" CRLF) - 1;
/*
* MSIE and Opera ignore the "Keep-Alive: timeout=<N>" header.
* MSIE keeps the connection alive for about 60-65 seconds.
* Opera keeps the connection alive very long.
* Mozilla keeps the connection alive for N plus about 1-10 seconds.
* Konqueror keeps the connection alive for about N seconds.
*/
if (clcf->keepalive_header) {
/*
http server域配置了keepalive_header
增加keep-alive响应头数据 并增加响应数据长度
*/
len += sizeof("Keep-Alive: timeout=") - 1 + NGX_TIME_T_LEN + 2;
}
} else {
/*没有keep-alive 发送的是close 状态的connection头*/
len += sizeof("Connection: close" CRLF) - 1;
}
#if (NGX_HTTP_GZIP)
if (r->gzip_vary) {
/*gzip处理*/
if (clcf->gzip_vary) {
/*server域配置了 gzip_vary 增加vary响应头数据*/
len += sizeof("Vary: Accept-Encoding" CRLF) - 1;
} else {
/*server域没有配置gzip vary 则设置gzip_vary为假*/
r->gzip_vary = 0;
}
}
#endif
/*取得响应头的数组*/
part = &r->headers_out.headers.part;
/*取得响应头数组的第一个元素*/
header = part->elts;
for (i = 0; /* void */; i++) {
/*遍历响应头的数组*/
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
header = part->elts;
i = 0;
}
if (header[i].hash == 0) {
continue;
}
/*增加响应头的数据长度*/
len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len
+ sizeof(CRLF) - 1;
}
/*建立一个临时的缓冲区用于存放需要的响应数据 len是前面的步骤计算得到的需发送的数据长度值*/
b = ngx_create_temp_buf(r->pool, len);
if (b == NULL) {
/*创建缓冲区失败 直接返回错误*/
return NGX_ERROR;
}
/*以下开始进行响应数据到缓冲区的填充过程*/
/* "HTTP/1.x " */
/*先填充http版本信息*/
b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1);
/* status line */
/*填充响应行信息*/
if (status_line) {
b->last = ngx_copy(b->last, status_line->data, status_line->len);
} else {
b->last = ngx_sprintf(b->last, "%03ui ", status);
}
/*根据http协议 响应行以rn结束*/
*b->last++ = CR; *b->last++ = LF;
/*以下是填充响应头部数据的流程*/
if (r->headers_out.server == NULL) {
/*填充响应server头*/
if (clcf->server_tokens) {
p = (u_char *) ngx_http_server_full_string;
len = sizeof(ngx_http_server_full_string) - 1;
} else {
p = (u_char *) ngx_http_server_string;
len = sizeof(ngx_http_server_string) - 1;
}
b->last = ngx_cpymem(b->last, p, len);
}
if (r->headers_out.date == NULL) {
/*填充响应date头数据*/
b->last = ngx_cpymem(b->last, "Date: ", sizeof("Date: ") - 1);
b->last = ngx_cpymem(b->last, ngx_cached_http_time.data,
ngx_cached_http_time.len);
*b->last++ = CR; *b->last++ = LF;
}
if (r->headers_out.content_type.len) {
/*填充content-type头数据*/
b->last = ngx_cpymem(b->last, "Content-Type: ",
sizeof("Content-Type: ") - 1);
p = b->last;
b->last = ngx_copy(b->last, r->headers_out.content_type.data,
r->headers_out.content_type.len);
if (r->headers_out.content_type_len == r->headers_out.content_type.len
&& r->headers_out.charset.len)
{
/*填充charset头数据*/
b->last = ngx_cpymem(b->last, "; charset=",
sizeof("; charset=") - 1);
b->last = ngx_copy(b->last, r->headers_out.charset.data,
r->headers_out.charset.len);
/* update r->headers_out.content_type for possible logging */
r->headers_out.content_type.len = b->last - p;
r->headers_out.content_type.data = p;
}
/*每个http响应头均以rn结束 以作区分*/
*b->last++ = CR; *b->last++ = LF;
}
if (r->headers_out.content_length == NULL
&& r->headers_out.content_length_n >= 0)
{
/*填充 content-length响应头*/
b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF,
r->headers_out.content_length_n);
}
if (r->headers_out.last_modified == NULL
&& r->headers_out.last_modified_time != -1)
{
/*填充last-modified响应头*/
b->last = ngx_cpymem(b->last, "Last-Modified: ",
sizeof("Last-Modified: ") - 1);
b->last = ngx_http_time(b->last, r->headers_out.last_modified_time);
*b->last++ = CR; *b->last++ = LF;
}
if (host.data) {
/*填充location响应头*/
p = b->last + sizeof("Location: ") - 1;
b->last = ngx_cpymem(b->last, "Location: http",
sizeof("Location: http") - 1);
#if (NGX_HTTP_SSL)
if (c->ssl) {
*b->last++ ='s';
}
#endif
*b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/';
b->last = ngx_copy(b->last, host.data, host.len);
if (port) {
b->last = ngx_sprintf(b->last, ":%ui", port);
}
b->last = ngx_copy(b->last, r->headers_out.location->value.data,
r->headers_out.location->value.len);
/* update r->headers_out.location->value for possible logging */
r->headers_out.location->value.len = b->last - p;
r->headers_out.location->value.data = p;
ngx_str_set(&r->headers_out.location->key, "Location");
*b->last++ = CR; *b->last++ = LF;
}
if (r->chunked) {
/*
chunked传输类型 填充transfer-encoding响应头
当然类型是chunked
*/
b->last = ngx_cpymem(b->last, "Transfer-Encoding: chunked" CRLF,
sizeof("Transfer-Encoding: chunked" CRLF) - 1);
}
/*根据状态码及keepalive配置 填充connection响应头*/
if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
b->last = ngx_cpymem(b->last, "Connection: upgrade" CRLF,
sizeof("Connection: upgrade" CRLF) - 1);
} else if (r->keepalive) {
b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF,
sizeof("Connection: keep-alive" CRLF) - 1);
if (clcf->keepalive_header) {
b->last = ngx_sprintf(b->last, "Keep-Alive: timeout=%T" CRLF,
clcf->keepalive_header);
}
} else {
b->last = ngx_cpymem(b->last, "Connection: close" CRLF,
sizeof("Connection: close" CRLF) - 1);
}
#if (NGX_HTTP_GZIP)
if (r->gzip_vary) {
/*填充gzip_vary的 vary响应头*/
b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF,
sizeof("Vary: Accept-Encoding" CRLF) - 1);
}
#endif
/*遍历响应头的 数组*/
part = &r->headers_out.headers.part;
header = part->elts;
for (i = 0; /* void */; i++) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
header = part->elts;
i = 0;
}
if (header[i].hash == 0) {
continue;
}
/*将响应头数组中的头部信息填充到缓冲区中*/
b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
*b->last++ = ':'; *b->last++ = ' ';
b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len);
*b->last++ = CR; *b->last++ = LF;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"%*s", (size_t) (b->last - b->pos), b->pos);
/* the end of HTTP header */
/*头部处理收尾工作*/
*b->last++ = CR; *b->last++ = LF;
/*设置响应头的大小*/
r->header_size = b->last - b->pos;
if (r->header_only) {
/*只需要响应头部数据 将这个缓冲区设置为最后一个*/
b->last_buf = 1;
}
out.buf = b;
out.next = NULL;
/*将填充完成的缓冲区提交到write_filter write_filter处理后 会将数据发送到请求端*/
return ngx_http_write_filter(r, &out);
}
最后
以上就是年轻含羞草为你收集整理的nginx 处理http(发送http响应头数据篇 ----- ngx_http_header_filter_module模块处理)的全部内容,希望文章能够帮你解决nginx 处理http(发送http响应头数据篇 ----- ngx_http_header_filter_module模块处理)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复