1、如果请求是post,而且请求原是188.188.3.171,处理方式403
if ($request_method ~* "POST") # $request_method 等同于request的method,通常是“GET”或“POST”
# 如果访问request的method值为POST则返回“o”
{
set $test o;
}
if ($remote_addr = '188.188.3.171') //如果访问地址等于188.188.3.171则返回“k”
同理 #if ($remote_addr != '188.188.3.171') //如果访问地址非188.188.3.171则返回“k”
{
Set $test "${test}k"; # ${test}=o,所以${test}k=ok
}
//如果满足上述条件则返回“ok”处理方式为返回403
if ( $test = ok )
{
Return 403;
#rewrite ^(.*) http://www.fengyuba.com permanent;
#如果满足条件则重定向到www.fengyuba.com
}
参数注释如下:
正则表达式匹配,其中:
* ~ 为区分大小写匹配
* ~* 为不区分大小写匹配
* !~和!~*分别为区分大小写不匹配及不区分大小写不匹配
文件及目录匹配,其中:
* -f和!-f用来判断是否存在文件
* -d和!-d用来判断是否存在目录
* -e和!-e用来判断是否存在文件或目录
* -x和!-x用来判断文件是否可执行
flag标记有:
* last 相当于apache里的[L]标记,表示完成rewrite
* break 终止匹配, 不再匹配后面的规则
* redirect 返回302临时重定向 地址栏会显示跳转后的地址
* permanent 返回301永久重定向 地址栏会显示跳转后的地址
nginx常用变量:
$args 此变量与请求行中的参数相等
$content_length 等于请求行的“Content_Length”的值。
$content_type 等同与请求头部的”Content_Type”的值
$document_root 等同于当前请求的root指令指定的值
$document_uri 与$uri一样
$host 与请求头部中“Host”行指定的值或是request到达的server的名字(没有Host行)一样
$limit_rate 允许限制的连接速率
$uri 等同于当前request中的URI,可不同于初始值,例如内部重定向时或使用index
$server_protocol 等同于request的协议,使用“HTTP/1.0”或“HTTP/1.1”
$server_port 请求到达的服务器的端口号
$server_name 请求到达的服务器名
$server_addr request到达的server的ip,一般获得此变量的值的目的是进行系统调用。为了避免系统调用,有必要在listen指令中指明ip,并使用bind参数。
$request_uri 含有参数的完整的初始URI
$request_method 等同于request的method,通常是“GET”或“POST”
$request_filename 当前请求的文件的路径名,由root或alias和URIrequest组合而成
$request_body_file
$remote_user 等同于用户名,由ngx_http_auth_basic_module认证
$remote_port 客户端port
$remote_addr 客户端ip
$query_string 与$args一样
2、如果是.php或者是.php5结尾的
server {
listen 80;
server_name www.wokao.com;
index index.html index.htm index.php;
root /data/www/wokao;
location ~ .*.(php|php5)?$
{
Include test.conf;
fastcgi_pass unix:/tmp/php-cgi.sock;
#fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fcgi.conf;
}
}
3、NGINX配置中的 events 模块详解
nginx events 模块主要是nginx 和用户交互网络连接优化的配置内容
nginx events模块主要包含了accept_mutex, multi_accept,worker_connections 和 use这几个指令
accept_mutex
这个配置主要可以用来解决常说的"惊群"问题。大致意思是在某一个时刻,客户端发来一个请求连接,Nginx后台是以多进程的工作模式,也就是说有多个worker进程会被同时唤醒,但是最终只会有一个进程可以获取到连接,如果每次唤醒的进程数目太多,就会影响Nginx的整体性能。如果将上述值设置为on(开启状态),将会对多个Nginx进程接收连接进行序列号,一个个来唤醒接收,就防止了多个进程对连接的争抢。
multi_accept
设置一个进程是否同时接受多个网络连接,默认为off
worker_connections
用来配置单个worker进程最大的连接数,nginx 默认连接数是1024,可以设置20480
use
用来设置Nginx服务器选择哪种事件驱动来处理网络消息,事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport注意:此处所选择事件处理模型是Nginx优化部分的一个重要内容,method的可选值有select/poll/epoll/kqueue等,使用linux内核在2.6以上,就是为了能使用epoll函数来优化Nginx
另外这些值的选择,我们也可以在编译的时候使用:–with-select_module、–without-select_module、 --with-poll_module、–without-poll_module来设置是否需要将对应的事件驱动模块编译到Nginx的内核。
events {
accept_mutex on; #设置网路连接序列化,防止惊群现象发生,默认为on
multi_accept on; #设置一个进程是否同时接受多个网络连接,默认为off
use epoll; #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
worker_connections 1024; # 最大连接数
}
4、NGINX配置中的 http 模块详解
client_header_buffer_size
假设client_header_buffer_size的配置为1k,如果(请求行+请求头)的大小如果没超过1k,放行请求。如果(请求行+请求头)的大小如果超过client_header_buffer_size配置的1k,如果配置large_client_header_buffers 以配置为准,如果没配置large_client_header_buffers,请求失败
large_client_header_buffers
large_client_header_buffers 4 8k,则对请求有如下要求
1、请求行(request line)的大小不能超过8k,否则返回414错误
2、请求头(request header)中的每一个头部字段的大小不能超过8k,否则返回400错误(实际是494错误,但nginx统一返回400了)
curl -H "header1=aaa" -H "header2=bbb" -v http://127.0.0.1/,这里的header1=xxx和header2=xxx就是请求头中的头部字段
(请求行+请求头)的大小不能超过32k(4 * 8k)
实验client_header_buffer_size、large_client_header_buffers
1、修改nginx配置
vi nginx.confhttp { # 声明日志格式,request_length用来输出每一个请求的大小(请求行+请求头+请求体) log_format main '$remote_addr - $remote_user [$time_local] "$request" $request_length ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; # 指定访问日志的格式和存放路径 access_log /usr/local/var/log/nginx/access.log main; # 请求行+请求头的标准大小为1k client_header_buffer_size 1k; # 请求行+请求头的最大大小为2k large_client_header_buffers 2 1k; }
2、使用curl模拟http请求
返回 414错误
foo=''; for i in {1..1008}; do foo=${foo}"a"; done curl -v http://127.0.0.1:80\?$foo # 先找一个能curl无问题的页面,比如curl 127.0.0.1:8081无问题
curl请求明细
> GET /?1008个a HTTP/1.1 > Host: 127.0.0.1:80 > User-Agent: curl/7.64.1 > Accept: */* > < HTTP/1.1 414 Request-URI Too Large < Server: nginx/1.17.2 < Date: Sat, 02 May 2020 01:45:57 GMT < Content-Type: text/html < Content-Length: 177 < Connection: close < <html> <head><title>414 Request-URI Too Large</title></head> <body> <center><h1>414 Request-URI Too Large</h1></center> <hr><center>nginx/1.17.2</center> </body> </html>
nginx日志
这里显示的是0,但请求行的大小已超过1k了127.0.0.1 - - [02/May/2020:09:45:57 +0800] "GET /?1008个a HTTP/1.1\x0D" 0 414 177 "-" "-" "-"
返回 494错误
foo='';bar=''; for i in {1..1012}; do foo=${foo}"a"; bar=${bar}"a"; done curl -H "header1: $foo" -H "header2: $bar" -v http://127.0.0.1:80
curl请求明细
> GET / HTTP/1.1 > Host: 127.0.0.1:80 > User-Agent: curl/7.64.1 > Accept: */* > header1: 1012个a > header2: 1012个a > < HTTP/1.1 400 Bad Request < Server: nginx/1.17.2 < Date: Sat, 02 May 2020 01:48:45 GMT < Content-Type: text/html < Content-Length: 233 < Connection: close < <html> <head><title>400 Request Header Or Cookie Too Large</title></head> <body> <center><h1>400 Bad Request</h1></center> <center>Request Header Or Cookie Too Large</center> <hr><center>nginx/1.17.2</center> </body> </html>
nginx日志
127.0.0.1 - - [02/May/2020:09:48:45 +0800] "GET / HTTP/1.1" 2123 400 233 "-" "curl/7.64.1" "-"
源码及流程图
include mime.types
mime.types 是一个文件,此文件记录了nginx能识别哪些类型的文件
[root@master01 nginx]# cd /etc/nginx/ [root@master01 nginx]# ls nginx.conf nginx.conf [root@master01 nginx]# cat mime.types types { text/html html htm shtml; text/css css; text/xml xml; image/gif gif; image/jpeg jpeg jpg; application/javascript js; application/atom+xml atom; application/rss+xml rss; text/mathml mml; text/plain txt; text/vnd.sun.j2me.app-descriptor jad; text/vnd.wap.wml wml; text/x-component htc; image/png png; image/svg+xml svg svgz; image/tiff tif tiff; image/vnd.wap.wbmp wbmp; image/webp webp; image/x-icon ico; image/x-jng jng; image/x-ms-bmp bmp; font/woff woff; font/woff2 woff2; application/java-archive jar war ear; application/json json; application/mac-binhex40 hqx; application/msword doc; application/pdf pdf; application/postscript ps eps ai; application/rtf rtf; application/vnd.apple.mpegurl m3u8; application/vnd.google-earth.kml+xml kml; application/vnd.google-earth.kmz kmz; application/vnd.ms-excel xls; application/vnd.ms-fontobject eot; application/vnd.ms-powerpoint ppt; application/vnd.oasis.opendocument.graphics odg; application/vnd.oasis.opendocument.presentation odp; application/vnd.oasis.opendocument.spreadsheet ods; application/vnd.oasis.opendocument.text odt; application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; application/vnd.wap.wmlc wmlc; application/x-7z-compressed 7z; application/x-cocoa cco; application/x-java-archive-diff jardiff; application/x-java-jnlp-file jnlp; application/x-makeself run; application/x-perl pl pm; application/x-pilot prc pdb; application/x-rar-compressed rar; application/x-redhat-package-manager rpm; application/x-sea sea; application/x-shockwave-flash swf; application/x-stuffit sit; application/x-tcl tcl tk; application/x-x509-ca-cert der pem crt; application/x-xpinstall xpi; application/xhtml+xml xhtml; application/xspf+xml xspf; application/zip zip; application/octet-stream bin exe dll; application/octet-stream deb; application/octet-stream dmg; application/octet-stream iso img; application/octet-stream msi msp msm; audio/midi mid midi kar; audio/mpeg mp3; audio/ogg ogg; audio/x-m4a m4a; audio/x-realaudio ra; video/3gpp 3gpp 3gp; video/mp2t ts; video/mp4 mp4; video/mpeg mpeg mpg; video/quicktime mov; video/webm webm; video/x-flv flv; video/x-m4v m4v; video/x-mng mng; video/x-ms-asf asx asf; video/x-ms-wmv wmv; video/x-msvideo avi; } [root@master01 nginx]#
++++++++++'MIME-type和Content-Type的关系'++++++++++
1)HTTP服务器在'响应'一份'报文主体'时,在HTTP'报文头部'插入'解释自身数据类型'的MIME头部信息-->'Content-Type'
2)当web'服务器收到'静态的资源文件请求时,依据'请求文件的后缀名'在服务器的'MIME配置文件中找'到对应的'MIME Type',再根据MIME Type'设置HTTP Response的Content-Type',然后'客户端如浏览器'根据Content-Type的值'处理文件'
Content-Type详解
① 服务端如何处理静态资源文件
媒体类型通常是通过 'HTTP' 协议,由 Web 服务器过'Content-Type值'来告知'浏览器'的
媒体类型通常是通过 'HTTP' 协议,由 Web 服务器过'Content-Type值'来告知'浏览器'的
例如:'响应头' -->Content-Type: text/html② 客户端如何处理Content-Type值请求
浏览器是'如何区分'它们,进而决定'什么内容'用'什么形式'来显示呢?
nginx中关于媒体类型
nginx访问静态文件不下载
① nginx中的 mime.types文件
'include'表示'纳入mime.types文件'的配置
举例: 形如text'/html格式'的字符串就是用来说明'数据类型'的
1)'/'前的是'主'类型
2)'/之后'的是该主类型下的'子类型'
备注:详细的类型定义在'RFC2046'中解决nginx下加载eot|otf|ttf|woff|svg等404 错误问题
作用:在'mime.type'文件中找不到'文件'映射的'type'时'采用'默认的'default_type'
如果web程序'没设置,'Nginx也'没找到'对应文件的'扩展名'的'type'话,就使用'默认的Type'③ types
四 案例讲解
比如:当我们打开'chrome浏览器'看一个'PNG格式的图片'的时候,Nginx是这样'发送格式信息'的:
1)服务器上'有wzj.png'这个文件,后缀名是png;
2)根据'include mime.types'查找到这个文件的'数据类型'应该是'image/png';
3)将'Content-Type'的值设置为'image/png',然后发送给'客户端(浏览器)'1)如果处理'本地的'文件,在'没有人告诉'浏览器某个文件的 MIME Type 的情况下,浏览器也会做一些'默认的处理' 2)'默认的处理'和你'在操作系统中'给文件配置的 'MIME Type 有关' Windows 下: 打开注册表的"HKEY_LOCAL_MACHINESOFTWAREClassesMIMEDatabaseContent Type"主键,可以看到'所有 MIME Type' 的配置信息 Linux下:通过一个'文本文件静态'关联数据库,负责将'application'(应用程序描述文件)与'MIME type'(Shared MIME Database)对应起来 Centos7该'数据库'为:/usr/share/applications/mimeinfo.cache
Linux MIME Type
+++++++++ 'Content-Type更通用的格式' +++++++++ Content-Type: [type]/[subtype]; parameter 用于定义网络文件的'类型'和网页的'编码',决定浏览器将以'什么形式'、'什么编码读取'这个文件 Content-Type 标头是'服务器'告诉客户端'实际返回的内容'的'内容类型' ++++++++++'语法格式'++++++++++ Content-Type: text/html; charset=utf-8
① 查看文件的MIME Type
格式: mimetype filename 备注: mimetype命令'需要安装' yum install perl-File-MimeInfo.noarch -y
②根据文件的MIME type找到打开方式gio mime mime_type
五 思考
(1)浏览器对于一个文件类型是如何判断渲染显示还是下载
浏览器的'原则'是能'打开'就打开-->'在自己的媒体类型中',不能打开'就下载' 1)每个'浏览器内置支持'的 Content-Type 类型表各不相同,这导致了'某些类型字符串'在'某些浏览器下'不被识别 2)另外如果'出现错误'的 Content-Type 类型,各个浏览器又会'以不同的方式'处理
思考: 如果客户端请求-->'request'的'Content-Type'和服务器响应-->'response'的'Content-Type'不一致呢?
(2)对于特定的文件类型,强制让其显示内容,而不是不能识别导致下载
常见: 'application/octet-stream' 是'HTTP规范中'Content-Type的一种.意思是:'未知'的'应用程序'文件,浏览器一般'不会自动执行'或'询问执行',表示这是个'二进制流',需要'下载到本地'后由'用户端环境决定'如何使用 备注: '如果'提交文件的话,只能'提交一个文件',后台'接收参数'只能有'一个',而且只能是流(或者字节数组)
nginx配置让任何文件在浏览器中显示文本text/plain或者xml,而不是下载
已知: 对于'text/plain'格式的文件,可以在'任何浏览器'中'直接打开'而不会下载 需求: 在nginx中配置'perl'这种特殊结尾的文件为'直接打开',而不是下载 +++++++++'从三个粒度来解析'+++++++++ 主要作为'对比'实验
① 默认是下载
说明: nginx的无法识别'perl结尾的文件',能识别'pl和pm'结尾的文件,'并且'如果安装了对应的模块,并在nginx种做了相应的配置,则会'解析该脚本'后返回内容给客户端
② 方式1:全局
vim /etc/nginx/mime.types 说明: 最好不要'一种后缀文件'对应'多种媒体类型' 注意: 修改之后一定要'restart','reload'不生效 备注: 可以'写在同一行',以'空格隔开';也可以'另起一行' 细节: 这个方法修改后'影响所有nginx网站'的配置
③ 方式2:只针对某种文件类型(推荐)
备注: 甚至可以'自定义文件'类型,但是浏览器可能'不能'按照该种格式解析-->因为是'伪造'的
单独打开'某个网站'的配置文件,在server中修改 案例: 所有目录下'以perl结尾的文件'显示为'text/plain'格式 location ~ .*\.perl$ { add_header Content-Type text/plain; }
④ 方式3:只针对某个站点的某个目录下的文件
location /perl/ { 'location嵌套' location ~* .*\.perl$ { add_header Content-Type text/plain; }
⑤ 效果展示
(6)强制设置所有文件都是下载的
header中Content-Disposition的作用与使用方法
location / { root html; add_header Content-Disposition "attachment; filename=$1"; index index.html }
(7)nginx支持播放mkv视频
#nginx.conf #在server > location块内加入 types{ video/webm mkv; }
default_type application/octet-stream
如果访问的类型,在 mime.types 中没匹配上,默认使用二进制流的方式传输显示内容
log_format main
log_format main '$remote_addr|$remote_user|[$time_local]|"$request"|' '$status|$body_bytes_sent|$http_host|"$http_referer"|' '"$http_user_agent"|$http_x_forwarded_for|$upstream_cache_status|' '"$upstream_http_content_type"|$request_time|$upstream_response_time|$bytes_sent|$request_length|' '"$upstream_addr"|$uuid|$span_id';
此配置为 nginx 日志中,显示的信息
nginx服务器日志相关指令主要有两条:一条是log_format,用来设置日志格式;另外一条是access_log,用来指定日志文件的存放路径、格式和缓存大小,可以参加ngx_http_log_module。一般在nginx的配置文件中日记配置(/usr/local/nginx/conf/nginx.conf)。
log_format指令用来设置日志的记录格式,它的语法如下: log_format name format {format ...} 其中name表示定义的格式名称,format表示定义的格式样式。 log_format有一个默认的、无须设置的combined日志格式设置,相当于Apache的combined日志格式,其具体参数如下: log_format combined '$remote_addr-$remote_user [$time_local]' ‘"$request"$status $body_bytes_sent’ ‘"$http_referer" "$http_user_agent"’ 也可以自定义一份日志的记录格式,不过要注意,log_format指令设置的名称在配置文件中是不能重复的。 假设将Nginx服务器作为Web服务器,位于负载均衡设备、Squid、Nginx反向代理之后,不能获取到客户端的真实IP地址了。 原因是经过反向代理后,由于在客户端和Web服务器之间增加了中间层,因此Web服务器无法直接拿到客户端的IP。 通过$remote_addr变量拿到的将是反向代理服务器的IP地址。 但是,反向代理服务器在转发请求的HTTP头信息中,可以增加X-Forwarded-For信息,用以记录原有的客户端IP地址和原来客户端请求的服务器地址。 这时候,要用log_format指令设置日志格式,让日志记录X-Forearded-For信息中的IP地址,即客户的真实IP。 例如,创建一个名为mylogformat的日志格式,再$http_x_forwarded_forlog_for变量记录用户的X_Forwarded-For IP 地址: log_format mylogformat '$http_x_forwarded_for_$remote_user [$time_local]' ‘"$request"$status $body_bytes_sent’ ‘"$http_referer" "$http_user_agent"’ 在日志格式样式中,变量$remote_addr和$http_x_forwarded_for用于记录IP地址; $remote_user用于记录远程客户端用户名称; $time_local用于记录访问时间与时区; $request用于记录请求URL与HTTP协议; $status用于记录请求状态,例如成功时状态为200,页面找不到时状态为404; $body_bytes_sent用于记录发送客户端的文件主体内容大小; $http_referer用于记录是从哪个页面链接访问过来的; $http_user_agent用于记录客户浏览器的相关信息。
一般来说:nginx的log_format有很多可选的参数用于指示服务器的活动状态,默认的是:
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
想要记录更详细的信息需要自定义设置log_format,具体可设置的参数格式及说明如下:
参数 说明 示例 $remote_addr 客户端地址 211.28.65.253 $remote_user 客户端用户名称 -- $time_local 访问时间和时区 18/Jul/2012:17:00:01 +0800 $request 请求的URI和HTTP协议 "GET /article-10000.html HTTP/1.1" $http_host 请求地址,即浏览器中你输入的地址(IP或域名) www.wang.com 192.168.100.100 $status HTTP请求状态 200 $upstream_status upstream状态 200 $body_bytes_sent 发送给客户端文件内容大小 1547 $http_referer url跳转来源 https://www.baidu.com/ $http_user_agent 用户终端浏览器等信息 "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; SV1; GTB7.0; .NET4.0C; $ssl_protocol SSL协议版本 TLSv1 $ssl_cipher 交换数据中的算法 RC4-SHA $upstream_addr 后台upstream的地址,即真正提供服务的主机地址 10.10.10.100:80 $request_time 整个请求的总时间 0.205 $upstream_response_time 请求过程中,upstream响应时间 0.002
如下是在nginx的LB代理层使用过的一个配置(nginx.conf中配置):
log_format main '$remote_addr $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '$http_user_agent $http_x_forwarded_for $request_time $upstream_response_time $upstream_addr $upstream_status';
然后在nginx.conf文件或vhosts/*.conf文件中的access_log日志中指定级别为main。如下:
access_log logs/wiki_access.log main; error_log logs/wiki_error.log;
........ 110.156.114.121 - [11/Aug/2017:09:57:19 +0800] "GET /rest/mywork/latest/status/notification/count?_=1502416641768 HTTP/1.1" 200 67 "http://wiki.wang-inc.com/pages/viewpage.action?pageId=11174759" Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 - 0.006 0.006 12.129.120.121:8090 200 112.116.25.18 - [11/Aug/2017:09:57:24 +0800] "POST /json/startheartbeatactivity.action HTTP/1.1" 200 234 "http://wiki.wang-inc.com/pages/resumedraft.action?draftId=12058756&draftShareId=014b0741-df00-4fdc-90ca-4bf934f914d1" Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 - 0.023 0.023 12.129.120.121:8090 200
其中错误日志 error log 级别分为 debug、info、notice、 warn、error、crit,默认为error ,crit记录的日志最少,而 debug 记录的日志最多,如果你的 nginx 遇到问题,比如502频繁出现,但是看默认的error og并没有看到有意义的信息,那么可以调一下错误日志的级别,调成error 级别时,错误日志记录的内容会更加丰富,该级别在日志名后边定义格式如下,而且也可以将不同的错误类型分开存储如,可以定义多条 error_log
error_log logs/error.log; # 不写则是全部类型错误 error_log logs/error.log notice; # notice 类型错误 error_log logs/error.log info;
每个日志级别包括更高级别。例如,如果您将日志级别设置为wam,则Nginx还将记录emror,crit,alert 和 emerg 消息。未指定log_level参数时,默认为error。
debug-调试消息。 info-信息性消息 notice-公告。 wamn-警告。 error-处理请求时出错。 crit-关键问题。需要立即采取行动。. alert -警报。必须立即采取行动。 emerg-紧急情况。系统处于无法使用的状态
sendfile
使用linux的 sendfile(socket, file, len) 高效网络传输,也就是数据0拷贝。 未开启sendfile。再发个比方:咱们现在有两台电脑,我们需要从PC1拿点东西去PC2,那我们就得先拿U盘去PC1里面拷贝,然后再用U盘拷贝到PC2中,而如果开启了这个sendfile,那就相当于直接隔空传过去,省去了拷贝的过程。
sendfile off;
咱们的Nginx是假设在CentOS操作系统上的,当服务过来的时候是通过CentOS的网络接口然后转发给Nginx。Nginx拿到信息后会根据其内容去硬盘(SSD)中找到那个目标文件,然后Nginx会把这个文件完整的读一遍,读到自己的内存中再交给应用程序,应用程序也把拿到的文件完整的读进自己的内存,再转发到CentOS的网络接口(当然这里面还有DMA [ Direct Memory Access直接访问内存 ] 的调度,网络接口的缓存和内核的缓存)网络接口再把其发送出去。这里的层层缓存就相当于上面所说的层层复制。
sendfile on;
这里通过Nginx会给内核发送一个信号,此时的应用程序不会再去把文件读取进自己的内存了,而是直接发送这个 sendfile() 信号(当然这其实是一个方法,里面会写明需要传出的文件和socket)给CentOS的网络接口,网络接口在收到信号后回去找到这个目标文件,然后发送出去。
keepalive_timeout 65;
连接的超时时间限制。keepalive_timeout:表示设置客户端连接保持活动的超时时间,单位是秒。在超过这个时间之后,服务器会关闭连接,因此如果您上传数据量较大,连接时间较长,也需要修改该参数的值。完成修改后,重启nginx即可。
client_max_body_size
client_max_body_size:2048 表示客户端请求服务器最大允许大小,单位是兆。如果请求的数据量大于client_max_body_size中设置的值,HTTP协议会报错413"Request Entity Too Large",因此当您上传的数据量较大时,需要将参数值改大。
client_max_body_size 413"Request Entity Too Large" client_header_buffer_size large_client_header_buffers 414 Request-URI Too Large、400 Request Header Or Cookie Too Large
5、nginx 配置$Query String
摘录:nginx 配置$Query String_赶路人儿的博客-CSDN博客_$query_string
实际开发中经常有根据请求参数来路由到不同请求处理者的情况,根据POST请求参数需要些nginx插件,这里主要简单介绍下如何根据GET参数来路由。
1、location进行路径
最常见的是通过location进行路径匹配的时候,但是没办法使用正则表达一起捕获这个路径和querstring的参数。如果我们想通过URL里面的Query String进行不同的rewrite,应该如何处理呢?答案就是$arg变量。
Nginx里面$query_string 与$args相同,存储了所提交的所有$query_string;比如&p=2887&q=test
如果想要在nginx里面单独访问这些变量。可以这样
比如$p变量可以这样访问 $arg_p
2、rewrite:
需求用到rewrite 其中有一个是要把a.php?id=2重定向到b-2.html
开始简单的写为
rewrite "^/a(.*)?(.*)$" /b-$2.html permanent;
总是不能正确的301到b-2.html
查资料发现
rewrite只能针对请求的uri进行重写,/a.php问号后面的是请求参数,在nginx用$query_string表示,直接写这样的一条重写肯定不会正确匹配,因为rewrite参数只会匹配请求的uri,在写重写的时候需要把$query_string变量追加到重写的uri后面,为了防止uri中的参数追加到重写后的uri,可以在后面加个问号:
if ($query_string ~ "id=(.*)") {
set $id $1;
rewrite ^/a.php$ /b-$id.html? permanent;
}
【示例1】
比如我们希望访问http://192.168.71.51:6061/do1.aspx?t=1212&c=uplog当url中的参数c为config或uplog的时候(忽略大小写)我们路由到其他地方:
下面是用这样一个实例讲述一下。
首先增加一个upstream:
……
upstream other {
server 192.168.71.41:2210;
}
……
在location中加入判断:
……
location / {
if ( $query_string ~* ^(.*)c=config\b|uplog\b(.*)$ ){
proxy_pass http://other;
}
……
\b 解释:http://t.csdn.cn/sgo4L
【示例2】
要求是 如果请求中的$query_string包含"q=数字",301重新定向到首页交由index.php处理。否则只是301重新定向到首页。
location ~* ^/wap/ {
# if ( $http_user_agent ~* "(MSIE|bot|Spider|Slurp)" ) {
# }
if ($args ~* "p=\d+$") {
rewrite ^ $scheme://$host/?p=$arg_p? permanent;
}
#Rewrite 后面带一个?表示在重定向中使用query_tring
rewrite ^/(.*)$ $scheme://$host/<del datetime="2012-01-24T14:18:20+00:00">?</del> permanent;
}
注:关于rewrite后面的问号,其作用是去除后面的qrerystring,不加?的话,就是这样的比如原来的query_string是p=2887,不加问号的话 是重新定向到
http://ihipop.info/?2887&p=2887 多了一个&p=2887这样产生的 URI 不是很美观。
【示例3】
location / {
if ( $query_string ~* "p=\d+$" ) {
proxy_pass http://www.ifeng.com;
}
proxy_pass http://www.baidu.com;
}
通过如上配置,当访问nginx时,如果后面带有p=数字的参数(http://10.153.140.42/?p=1),就会跳转到ifeng,否则跳转到baidu。
【示例4】
url路径中uid参数的值如果以a结尾,访问百度;如果以b结尾访问凤凰。
location / {
root html;
index index.html index.htm index.php;
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header Connection "";
if ( $query_string ~* "uid=(.*a$)" ) {
proxy_pass http://www.baidu.com;
}
if ( $query_string ~* "uid=(.*b$)" ) {
proxy_pass https://github.com;
}
}
如果连接后面会有多个参数,这种配置的匹配方式是错误的,正确的做法参照:
6、nginx location中多个if里面proxy_pass
1)location的匹配指令:
~ #波浪线表示执行一个正则匹配,区分大小写
~* #表示执行一个正则匹配,不区分大小写
^~ #^~表示普通字符匹配,不是正则匹配。如果该选项匹配,只匹配该选项,不匹配别的选项,一般用来匹配目录
= #进行普通字符精确匹配
@ #"@" 定义一个命名的 location,使用在内部定向时,例如 error_page, try_files
2)location 匹配的优先级(与location在配置文件中的顺序无关)
= 精确匹配会第一个被处理。如果发现精确匹配,nginx停止搜索其他匹配。
普通字符匹配,正则表达式规则和长的块规则将被优先和查询匹配,也就是说如果该项匹配还需去看有没有正则表达式匹配和更长的匹配。
^~ 则只匹配该规则,nginx停止搜索其他匹配,否则nginx会继续处理其他location指令。
最后匹配理带有"~"和"~*"的指令,如果找到相应的匹配,则nginx停止搜索其他匹配;当没有正则表达式或者没有正则表达式被匹配的情况下,那么匹配程度最高的逐字匹配指令会被使用。
2、nginx多个if里面proxy_pass:
server {
listen 127.0.0.1:80;
set $test A;
set $testB B;
location / {
if ($test ~* "A") {
proxy_pass http://www.so.com;
break;
}
if ($testB ~* "B") {
proxy_pass http://www.sogou.com;
#break;
}
}
}
希望满足某个条件的时候,走某个proxy_pass。但是如果多个if都满足,比如上例中的情况:在第一个if中没有break的时候,就会执行下面的;为了第一个匹配上之后就执行proxy_pass,可以加上break。(在nginx中貌似没有if else这样的指令)
3、判断参数进行不同的proxy_pass:
rewrite只能通过url路径进行匹配,不能进行参数匹配,所以如果要实现参数的判断需要用$arg_parameter。
location / {
root html;
index index.html index.htm index.php;
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header Connection "";
if ( $query_string ~* "usg=0" ) {
proxy_pass http://local_workera;
}
if ( $query_string ~* "usg=1" ) {
proxy_pass http://local_workerb;
}
if ( $arg_uid ~* "(.*[AB]$)" ) {
proxy_pass http://local_workerf;
}
proxy_pass http://local_workera;
}
1)请求路径中的usg=0和usg=1这两个参数是确定的,所以使用了$query_string进行正则匹配即可;($query_string的值是请求中所有参数)
2)接下来,我们想对uid的值如果是以A、B结尾的请求,转向local_workerf处理,这时候就无法用$query_string进行正则匹配了;(因为对于/?uid=1A&t=1&usg=1和/?uid=123&t=A&usg=0 不太好匹配)这时,只能用$arg_uid进行正则匹配了。
3)由于usg=0和usg=2这两个参数是互斥的,所以根据上面location中if指令的逻辑,不用break也可以正确处理,且放到最上面。对于uid的匹配,由于会和usg进行冲突,所以只能放到最下面或者加break,即:
location / {
root html;
index index.html index.htm index.php;
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header Connection "";
if ( $arg_uid ~* "(.*[AB]$)" ) {
proxy_pass http://local_workerf;
break;
}
if ( $query_string ~* "usg=0" ) {
proxy_pass http://local_workera;
}
if ( $query_string ~* "usg=1" ) {
proxy_pass http://local_workerb;
}
proxy_pass http://local_workera;
}