nginx基础概念(100%)之request

这节我们讲request,在nginx中我们指的是http请求,具体到nginx中的数据结构是ngx_http_request_t。ngx_http_request_t是对一个http请求的封装。 我们知道,一个http请求,包含请求行、请求头、请求体、响应行、响应头、响应体。

http请求是典型的请求-响应类型的的网络协议,而http是文件协议,所以我们在分析请求行与请求头,以及输出响应行与响应头,往往是一行一行的进行处理。如果我们自己来写一个http服务器,通常在一个连接建立好后,客户端会发送请求过来。然后我们读取一行数据,分析出请求行中包含的method、uri、http_version信息。然后再一行一行处理请求头,并根据请求method与请求头的信息来决定是否有请求体以及请求体的长度,然后再去读取请求体。得到请求后,我们处理请求产生需要输出的数据,然后再生成响应行,响应头以及响应体。在将响应发送给客户端之后,一个完整的请求就处理完了。当然这是最简单的webserver的处理方式,其实nginx也是这样做的,只是有一些小小的区别,比如,当请求头读取完成后,就开始进行请求的处理了。nginx通过ngx_http_request_t来保存解析请求与输出响应相关的数据。

那接下来,简要讲讲nginx是如何处理一个完整的请求的。对于nginx来说,一个请求是从ngx_http_init_request开始的,在这个函数中,会设置读事件为ngx_http_process_request_line,也就是说,接下来的网络事件,会由ngx_http_process_request_line来执行。从ngx_http_process_request_line的函数名,我们可以看到,这就是来处理请求行的,正好与之前讲的,处理请求的第一件事就是处理请求行是一致的。通过ngx_http_read_request_header来读取请求数据。然后调用ngx_http_parse_request_line函数来解析请求行。nginx为提高效率,采用状态机来解析请求行,而且在进行method的比较时,没有直接使用字符串比较,而是将四个字符转换成一个整型,然后一次比较以减少cpu的指令数,这个前面有说过。很多人可能很清楚一个请求行包含请求的方法,uri,版本,却不知道其实在请求行中,也是可以包含有host的。比如一个请求GET http://www.taobao.com/uri HTTP/1.0这样一个请求行也是合法的,而且host是www.taobao.com,这个时候,nginx会忽略请求头中的host域,而以请求行中的这个为准来查找虚拟主机。另外,对于对于http0.9版来说,是不支持请求头的,所以这里也是要特别的处理。所以,在后面解析请求头时,协议版本都是1.0或1.1。整个请求行解析到的参数,会保存到ngx_http_request_t结构当中。

在解析完请求行后,nginx会设置读事件的handler为ngx_http_process_request_headers,然后后续的请求就在ngx_http_process_request_headers中进行读取与解析。ngx_http_process_request_headers函数用来读取请求头,跟请求行一样,还是调用ngx_http_read_request_header来读取请求头,调用ngx_http_parse_header_line来解析一行请求头,解析到的请求头会保存到ngx_http_request_t的域headers_in中,headers_in是一个链表结构,保存所有的请求头。而HTTP中有些请求是需要特别处理的,这些请求头与请求处理函数存放在一个映射表里面,即ngx_http_headers_in,在初始化时,会生成一个hash表,当每解析到一个请求头后,就会先在这个hash表中查找,如果有找到,则调用相应的处理函数来处理这个请求头。比如:Host头的处理函数是ngx_http_process_host。

当nginx解析到两个回车换行符时,就表示请求头的结束,此时就会调用ngx_http_process_request来处理请求了。ngx_http_process_request会设置当前的连接的读写事件处理函数为ngx_http_request_handler,然后再调用ngx_http_handler来真正开始处理一个完整的http请求。这里可能比较奇怪,读写事件处理函数都是ngx_http_request_handler,其实在这个函数中,会根据当前事件是读事件还是写事件,分别调用ngx_http_request_t中的read_event_handler或者是write_event_handler。由于此时,我们的请求头已经读取完成了,之前有说过,nginx的做法是先不读取请求body,所以这里面我们设置read_event_handler为ngx_http_block_reading,即不读取数据了。刚才说到,真正开始处理数据,是在ngx_http_handler这个函数里面,这个函数会设置write_event_handler为ngx_http_core_run_phases,并执行ngx_http_core_run_phases函数。ngx_http_core_run_phases这个函数将执行多阶段请求处理,nginx将一个http请求的处理分为多个阶段,那么这个函数就是执行这些阶段来产生数据。因为ngx_http_core_run_phases最后会产生数据,所以我们就很容易理解,为什么设置写事件的处理函数为ngx_http_core_run_phases了。在这里,我简要说明了一下函数的调用逻辑,我们需要明白最终是调用ngx_http_core_run_phases来处理请求,产生的响应头会放在ngx_http_request_t的headers_out中,这一部分内容,我会放在请求处理流程里面去讲。nginx的各种阶段会对请求进行处理,最后会调用filter来过滤数据,对数据进行加工,如truncked传输、gzip压缩等。这里的filter包括header filter与body filter,即对响应头或响应体进行处理。filter是一个链表结构,分别有header filter与body filter,先执行header filter中的所有filter,然后再执行body filter中的所有filter。在header filter中的最后一个filter,即ngx_http_header_filter,这个filter将会遍历所有的响应头,最后需要输出的响应头在一个连续的内存,然后调用ngx_http_write_filter进行输出。ngx_http_write_filter是body filter中的最后一个,所以nginx首先的body信息,在经过一系列的body filter之后,最后也会调用ngx_http_write_filter来进行输出(有图来说明)。

这里要注意的是,nginx会将整个请求头都放在一个buffer里面,这个buffer的大小通过配置项client_header_buffer_size来设置,如果用户的请求头太大,这个buffer装不下,那nginx就会重新分配一个新的更大的buffer来装请求头,这个大buffer可以通过large_client_header_buffers来设置,这个large_buffer这一组buffer,比如配置4 8k,就是表示有四个8k大小的buffer可以用。注意,为了保存请求行或请求头的完整性,一个完整的请求行或请求头,需要放在一个连续的内存里面,所以,一个完整的请求行或请求头,只会保存在一个buffer里面。这样,如果请求行大于一个buffer的大小,就会返回414错误,如果一个请求头大小大于一个buffer大小,就会返回400错误。在了解了这些参数的值,以及nginx实际的做法之后,在应用场景,我们就需要根据实际的需求来调整这些参数,来优化我们的程序了。

处理流程图:

请求处理流程

以上这些,就是nginx中一个http请求的生命周期了。我们再看看与请求相关的一些概念吧。

<think>好的,我现在需要解决用户在Nginx中遇到的Invalid CORS请求配置问题。首先,我应该回忆一下CORS(跨源资源共享)的基本概念,以及Nginx如何配置来处理CORS问题。用户提到他们遇到了无效的CORS请求配置错误,这可能是因为响应头没有正确设置,导致浏览器拒绝跨域请求。 首先,CORS问题的核心在于服务器必须返回适当的HTTP头,如Access-Control-Allow-Origin,来允许特定的源访问资源。如果配置不正确,浏览器会阻止跨域请求,导致错误。因此,用户需要在Nginx的配置文件中添加或修改相关的头部信息。 接下来,我应该检查用户提供的引用内容,看看是否有相关的配置提示。例如,引用[1]中提到了处理OPTIONS请求的方法,这在CORS中很重要,因为预检请求使用OPTIONS方法。正确的处理方式是允许OPTIONS请求并返回适当的CORS头。这可能需要在Nginx的location块中添加相应的指令。 此外,引用[2]中的SCP命令可能和文件传输有关,用户可能需要将修改后的Nginx配置文件上传到服务器,因此可能需要使用类似的命令。不过这可能不是解决CORS问题的直接步骤,但需要注意配置文件的位置和重新加载Nginx服务。 然后,我需要考虑标准的Nginx CORS配置步骤。通常,这包括设置Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers等头部。同时,处理预检请求(OPTIONS方法)需要单独配置,返回204状态码并包含必要的头信息。 可能的错误点包括:头部名称拼写错误、未正确允许OPTIONS方法、未指定具体的源或方法。例如,使用通配符*作为Access-Control-Allow-Origin时,如果请求需要携带凭证(如cookies),则浏览器会拒绝,这时必须指定具体的源。 另外,用户可能需要检查他们的Nginx配置文件语法是否正确,是否有遗漏的分号或括号。使用nginx -t命令测试配置是否正确,然后重新加载配置。 还需要考虑缓存问题,有时候修改配置后未重新加载Nginx会导致旧的配置仍然生效,因此需要执行nginx -s reload。 现在,综合这些步骤,我应该给出一个具体的配置示例,并详细说明每个部分的作用。同时,提醒用户注意事项,比如通配符的使用限制、预检请求的处理等。最后,生成相关问题,帮助用户进一步理解和排查问题。</think>要解决Nginx中Invalid CORS请求配置问题,需通过添加CORS响应头并正确处理OPTIONS预检请求。以下是具体步骤和配置示例: --- ### 1. 基础CORS配置 在Nginx配置文件的`server`或`location`块中添加以下响应头: ```nginx add_header 'Access-Control-Allow-Origin' '$http_origin' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; add_header 'Access-Control-Allow-Credentials' 'true' always; ``` **说明**: - `$http_origin`动态匹配请求来源,避免硬编码[^1] - `always`确保所有响应状态码都返回头部 - `Allow-Credentials`需与具体来源(非通配符`*`)配合使用 --- ### 2. 处理OPTIONS预检请求 针对`OPTIONS`方法单独配置: ```nginx location / { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '$http_origin'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type'; add_header 'Access-Control-Max-Age' 1728000; # 缓存20天 add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; } } ``` --- ### 3. 验证与重载配置 1. 检查语法: ```bash nginx -t ``` 2. 重新加载配置: ```bash nginx -s reload ``` --- ### 注意事项 1. **通配符限制**:若使用`Access-Control-Allow-Credentials: true`,则`Access-Control-Allow-Origin`不能为`*`,需明确指定域名 2. **安全风险**:生产环境建议使用白名单机制,如: ```nginx map $http_origin $cors_origin { default ""; ~^https?://(example\.com|subdomain\.example\.com) $http_origin; } add_header 'Access-Control-Allow-Origin' $cors_origin; ``` 3. **配置位置**:确保CORS头添加在正确的`location`块中,静态文件需在`/static`等路径单独配置 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值