美文网首页让前端飞Nginx高端成长之路后端xuexi
Nginx葵花宝典—草根站长Nginx运维百科全书

Nginx葵花宝典—草根站长Nginx运维百科全书

作者: zhoulujun | 来源:发表于2018-07-09 10:38 被阅读7次

    题记

    前段时间把网站迁移到腾讯云,之前是lamp,现在改为lnmp,自以为nginx功底还可以,开发这么多年,平常环境都有配置。但是,但是,最近读站点做SEO优化,发现nginx很多地方不会配。比如:

    https://www.zhoulujun.cn/

    https://www.zhoulujun.cn/index.html

    https://www.zhoulujun.cn/index.php

    http://zhoulujun.cn/index.html

    https://zhoulujun.cn/index.html

    ……

    这些页面均为重复页面,再看

    https://www.zhoulujun.cn/?a=1&b=2&****

    https://www.zhoulujun.cn/?index.phpa=1&b=2&****

    以及CDN转发,功能切分多域名转发,负载均衡,路径优化,如此等……

    nginx,也没有那么容易,先从转发开始细讲,我觉得下面的内容,基本覆盖了一个资深程序员或运维的日常需求。这里把功能点都做了分类、笔记提示等,不足之处也请道友们补充。闲暇之余,希望把nginx系统地梳理一遍

    nginx正则表达式在location匹配规则及优先级

    =精确匹配        严格匹配这个查询。如果找到,停止搜索

    ~正则匹配        为区分大小写的正则匹配

    ^~ 优先前缀匹配 匹配路径的前缀,如果找到,停止搜索

    ~* 正则匹配 为不区分大小写匹配

    !~和!~*                分别为区分大小写不匹配及不区分大小写不匹

    /                           任何请求都会匹配

    优先级: =, ^~, ~/~*, 无

    具体可以参考:Nginx Location 路径匹配优先级

    nginx文件及目录匹配

    -f和!-f用来判断是否存在文件

    -d和!-d用来判断是否存在目录

    -e和!-e用来判断是否存在文件或目录

    -x和!-x用来判断文件是否可执行

    请求URI(路径)规范化。

    所谓规范化,就是先将URI中形如“%XX”的编码字符进行解码,再解析URI中的相对路径“.”和“..”部分, 另外还可能会压缩相邻的两个或多个斜线成为一个斜线。

    举例说明:若REQUEST_URI为//trip/t.php,则规范化后为/trip/t.php,Nginx将规范前的值存放在$request_uri中,而规范化后的值存放在$uri中。

    其中,$request_uri和$uri为Nginx内嵌变量。

    请求URI路径匹配

    首先需要明确Nginx中将路径匹配分为两类:

    前缀路径匹配,即前缀字符串定义的路径,如上配置文件中“/,/static/js/,/static/css/,/api,/trip/”

    正则表达式路径匹配,即使用正则表达式需要在路径开始添加“~*”前缀 (不区分大小写),或者“~”前缀(区分大小写)。如上配置文件中“/\.ht,^/~([^/]+)(/?.*)$,\.do$,/trip/, \.php$,\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar||bmp|rtf|js|mov)”

    其次为了根据请求URI查找路径,需要明确路径匹配的顺序:

    Nginx首先检查前缀字符串定义的路径 (前缀路径),在这些路径中找到能最精确匹配请求URI的路径。然后Nginx按在配置文件中的出现顺序检查正则表达式路径,匹配上某个路径后即停止匹配并使用该路径的配置,否则使用最大前缀匹配的路径的配置。

    举例说明:请求/trip/t.php,首先进行前缀路径匹配,最精确的前缀路径为/trip/,接下来进行正则表达式匹配,匹配到\.php$,从而进行location ~ \.php$ { }处理请求。反之若请求的是/trip/t.html,由于没有正则表达式匹配到该URI,故匹配最精确的前缀路径匹配,即进入location /trip/ { }处理请求。若想不论是请求/trip/t.php,还是/trip/t.html,都匹配到/trip/进行处理,则可以使用location ^~ /trip/ { },这样Nginx就不会再检查正则表达式了。

    Nginx虚拟目录alias和root目录

    nginx是通过alias设置虚拟目录,在nginx的配置中,alias目录和root目录是有区别的:

    1)alias指定的目录是准确的,即location匹配访问的path目录下的文件直接是在alias目录下查找的;

    2)root指定的目录是location匹配访问的path目录的上一级目录,这个path目录一定要是真实存在root指定目录下的;

    3)使用alias标签的目录块中不能使用rewrite的break(具体原因不明);另外,alias指定的目录后面必须要加上"/"符号!!

    4)alias虚拟目录配置中,location匹配的path目录如果后面不带"/",那么访问的url地址中这个path目录后面加不加"/"不影响访问,访问时它会自动加上"/";

        但是如果location匹配的path目录后面加上"/",那么访问的url地址中这个path目录必须要加上"/",访问时它不会自动加上"/"。如果不加上"/",访问就会失败!

    5)root目录配置中,location匹配的path目录后面带不带"/",都不会影响访问。

    一般情况下,在nginx配置中的良好习惯是:

    1)在location /中配置root目录;

    2)在location /path中配置alias虚拟目录。

    Nginx指令详解

    if指令

    使用环境:server,location

    该指令用于检查一个条件是否符合,如果条件符合,则执行大括号内的语句。If指令不支持嵌套,不支持多个条件&&和||处理。

    return指令

    语法:returncode ;

    使用环境:server,location,if;

    该指令用于结束规则的执行并返回状态码给客户端

    Set指令

    语法:setvariable value ; 默认值:none; 使用环境:server,location,if;

    该指令用于定义一个变量,并给变量赋值。变量的值可以为文本、变量以及文本变量的联合。

    示例:set$varname "hello world";

    Uninitialized_variable_warn指令

    语法:uninitialized_variable_warnon|off

    使用环境:http,server,location,if

    该指令用于开启和关闭未初始化变量的警告信息,默认值为开启。

    rewrite 指令

    语法:rewriteregex replacement flag

    使用环境:server,location,if

    该指令根据表达式来重定向URI,或者修改字符串。指令根据配置文件中的顺序来执行。注意重写表达式只对相对路径有效。

    rewrite参数 flag标志位

    在server块下,会优先执行rewrite部分,然后才会去匹配location块 

    server中的rewrite break和last没什么区别,都会去匹配location,所以没必要用last再发起新的请求,可以留空

    location中的rewirte:

    不写last和break - 那么流程就是依次执行这些rewrite 

    使用last和break实现URI重写,浏览器地址栏不变

    break - url重写后,直接使用当前资源,不再执行location里余下的语句,完成本次请求,地址栏url不变 

    last - url重写后,马上发起一个新的请求,再次进入server块,重试location匹配,超过10次匹配不到报500错误,地址栏url不变。牢记:使用last会对server标签重新发起请求

    使用redirect 和permanent 实现URI重写,浏览器以返回的新地址重新发起请求

    redirect – 返回302临时重定向,地址栏显示重定向后的url,爬虫不会更新url(因为是临时) 

    permanent – 返回301永久重定向, 地址栏显示重定向后的url,爬虫更新url

    last 和 break 总结如下:

    1、last 和 break 当出现在location 之外时,两者的作用是一致的没有任何差异

    注意一点就是,他们会跳过所有的在他们之后的rewrite 模块中的指令,去选择自己匹配的location

            rewrite url1 url2 last; ①

            rewrite url3 url4 last; ②

            rewrite url5 url6 last; ③

            location ~  url2     ④  

            location ~  url4     ⑤

            location ~  url6     ⑥

    当① 这条rewrite 规则生效后,它后面的②和③ 将被跳过不做判断,而去直接选择 后面的location。

    这里可能有一个疑问,那些指令输入rewrite 模块中的指令呢? 若是使用nginx本身,你就要到官网上去查询了。

    但如果你使用的是tengine ,可以使用tengine -V 。会将你想要的信息列举出来。

    放在server块rewrite语句前面 :如果是直接请求某个真实存在的文件,则用break语句停止rewrite检查 

        if (-f $request_filename) { 

            break; 

        }

    2、last 和 break 当出现在location 内部时,两者就存在了差异。

       last: 使用了last 指令,rewrite 后会跳出location 作用域,重新开始再走一次刚刚的行为break: 使用了break 指令,rewrite后不会跳出location 作用域。它的生命也在这个location中终结。

            rewrite xxx1 yyy last; ⑦

            rewrite xxx2 yyy last; ⑧

            rewrite xxx3 yyy last; ⑨

            rewrite xxx4 yyy last; ⑩

            location ~  url1 {

                rewrite url1 url2 last; ①

            }

            location ~  url2  {

                rewrite url3 url4 break; ②

                fastcgi_pass 127.0.0.1:9000;

            }

    以上事例:

    第一个location 中的 rewrite 指令处理完成之后,会跳出location ,再重新判断rewrite 7 ~ 9 的规则。

    第二个location 中的 rewrite  指令处理完成之后,不会跳出location, 更不会重新判断rewrite 7 ~ 9 的规则。而只能将

    信息传递给后面的fastcgi_pass 或者proxy_pass 等指令

    牢记:使用last会对server标签重新发起请求

    如果location中rewrite后是对静态资源的请求,不需要再进行其他匹配,一般要使用break或不写,直接使用当前location中的数据源,完成本次请求 

    如果location中rewrite后,还需要进行其他处理,如动态fastcgi请求(.php,.jsp)等,要用last继续发起新的请求

    使用alias指定源:必须使用last

    使用proxy_pass指令时,需要使用break标记。

    permanent 和 redirect 总结如下:

    permanent: 大家公认的信息 ,永久性重定向。请求日志中的状态码为301

    redirect: 大家公认的信息 ,临时重定向。请求日志中的状态码为302

    从实现功能的角度上去看,permanent 和 redirect 是一样的。不存在哪里好,哪里坏。也不存在什么性能上的问题。

    但从SEO(或者是百度爬你的网站时)。 类似于这样的东西,会对你到底是永久性重定向还是临时重定向感兴趣。了解不到,需要深入,就google 吧。

    last 和 break VS permanent 和 redirect 

    在 permanent 和 redirect  中提到了 状态码 301 和 302。 那么last 和 break 想对于的访问日志的请求状态码又是多少呢?

    答案为: 200

    这两类关键字,我们能够眼睛看到的差异是什么呢? 我举个例子说明吧:

    当你打开一个网页,同时打开debug 模式时,会发现301 和 302 时的行为是这样的。第一个请求301 或者 302 后,浏览器重新获取了一个新的URL ,然后会对这个新的URL 重新进行访问。所以当你配置的是permanent 和 redirect ,你对一个URL 的访问请求,落到服务器上至少为2次。

    而当你配置了last 或者是break 时,你最终的URL 确定下来后,不会将这个URL返回给浏览器,而是将其扔给了fastcgi_pass或者是proxy_pass指令去处理。请求一个URL ,落到服务器上的次数就为1次。

    nginx内置变量

    内置变量存放在  ngx_http_core_module 模块中,下面我来把这些变量分类记忆下,这里包括日常运维的内置变量讲解

    nginx地址栏系统内置变量匹配

    https://www.zhoulujun.cn/index.php?m=content&c=index&a=lists&catid=58的匹配顺序为例:

    $scheme 请求使用的Web协议, “http” 或 “https”

    $host请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称(处理请求的server的server_name指令的值)。值为小写,不包含端口。

    $hostname主机名,机器名使用 gethostname系统调用的值

    $document_uri 与$uri相同。请求中的当前URI(不带请求参数,参数位于$args),可以不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,$uri不包含主机名,如”/foo/bar.html”。

    $document_root当前请求的文档根目录或别名——当前请求在root指令中指定的值。

    $args 这个变量等于GET请求中的参数。$query_string 与$args相同。例如,foo=123&bar=blahblah;这个变量只可以被修改

    $arg_name请求中的的参数名,即“?”后面的arg_name=arg_value形式的arg_name

    $is_args如果$args设置,值为"?",否则为""。

    $cookie_COOKIE cookie COOKIE的值。

    $cookie_namecookie名称

    nginx服务端参数内置变量匹配

    $server_protocol 服务器的HTTP版本, 通常为 “HTTP/1.0” 或 “HTTP/1.1”

    $server_nam 服务器名,如www.zhoulujun.cn

    $server_addr 服务器端地址,需要注意的是:为了避免访问linux系统内核,应将ip地址提前设置在配置文件中。

    $server_port服务器端口

    $statusHTTP响应代码 (1.3.2, 1.2.2)

    $https 如果开启了SSL安全模式,值为“on”,否则为空字符串。

    nginx客户端参数内置变量匹配

    $remote_addr 客户端的IP地址。

    $remote_port 客户端的端口。

    $remote_user 用于HTTP基础认证服务的用户名,已经经过Auth Basic Module验证的用户名。

    $request代表客户端的请求地址

    $request_filename 当前连接请求的文件路径,由root或alias指令与URI请求生成。

    $realpath_root当前请求的文档根目录或别名的真实路径,会将所有符号连接转换为真实路径。

    $request_body 客户端的请求主体,此变量可在location中使用,将请求主体通过proxy_pass, fastcgi_pass, uwsgi_pass, 和 scgi_pass传递给下一级的代理服务器。这个变量(0.7.58+)包含请求的主要信息。在使用proxy_pass或fastcgi_pass指令的location中比较有意义。

    $request_body_file 客户端请求主体信息的临时文件名。将客户端请求主体保存在临时文件中。文件处理结束后,此文件需删除。如果需要之一开启此功能,需要设置client_body_in_file_only。如果将次文件传递给后端的代理服务器,需要禁用request body,即设置proxy_pass_request_body off,fastcgi_pass_request_body off, uwsgi_pass_request_body off, or scgi_pass_request_body off 。

    $request_completion 如果请求成功,设为"OK";如果请求未完成或者不是一系列请求中最后一部分则设为空。

    $request_method 这个变量是客户端请求的动作,通常为GET或POST。包括0.8.20及之前的版本中,这个变量总为main request中的动作,如果当前请求是一个子请求,并不使用这个当前请求的动作。

    $http_HEADER HTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_(破折号变为下划线),例如:$http_user_agent(Uaer-Agent的值), $http_referer...;

    $http_name匹配任意请求头字段; 变量名中的后半部分“name”可以替换成任意请求头字段,如在配置文件中需要获取http请求头:“Accept-Language”,那么将“-”替换为下划线,大写字母替换为小写,形如:$http_accept_language即可。

    $sent_http_HEADERHTTP响应头中的内容,HEADER为HTTP响应中的内容转为小写,-变为_(破折号变为下划线),例如: $sent_http_cache_control, $sent_http_content_type...;

    nginx运维及系统状态内置变量匹配

    $nginx_version当前运行的nginx版本号。

    $time_iso8601服务器时间的ISO 8610格式 (1.3.12, 1.2.7)

    $msec 当前的Unix时间戳 (1.3.9, 1.2.6)

    $pid工作进程的PID

    $limit_rate用于设置响应的速度限制

    $binary_remote_addr 二进制码形式的客户端地址。

    $body_bytes_sent传送页面的字节数

    $connection TCP连接的序列号 (1.3.8, 1.2.5)

    $connection_requests TCP连接当前的请求数量 (1.3.8, 1.2.5)

    $content_length请求头中的Content-length字段。

    $content_type请求头中的Content-Type字段。

    nginx常用配置案例参考

    #多目录转成参数

    abc.domian.com/sort/2 => abc.domian.com/index.php?act=sort&name=abc&id=2

        if ($host ~* (.*)\.domain\.com) {

            set $sub_name $1;

            rewrite ^/sort\/(\d+)\/?$ /index.php?act=sort&cid=$sub_name&id=$1 last;

        }

    #目录对换

    /123456/xxxx -> /xxxx?id=123456

            rewrite ^/(\d+)/(.+)/ /$2?id=$1 last;

    #ie用户使用重定向到/nginx-ie目录下:

        if ($http_user_agent ~ MSIE) {

            rewrite ^(.*)$ /nginx-ie/$1 break;

        }

    #目录自动加“/”

        if (-d $request_filename){

            rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;

        }

    #禁止多个目录

        location ~ ^/(cron|templates)/ {

            deny all;

            break;

        }

    #错页面如40x.html,50x.html设置

        error_page  404 403  /40x.html;

        # 承接上面的location。

        location = /40x.html {

        # 放错误页面的目录路径。

            root  /data/wwwroot/zhoulujun/;

        }

    #只充许固定ip访问网站,并加上密码

            root  /opt/htdocs/www;

            allow   208.97.167.194;

            allow   222.33.1.2;

            allow   231.152.49.4;

            deny    all;

            auth_basic “C1G_ADMIN”;

            auth_basic_user_file htpasswd;

    #将多级目录下的文件转成一个文件,增强seo效果

    /job-123-456-789.html 指向/job/123/456/789.html

            rewrite ^/job-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /job/$1/$2/jobshow_$3.html last;

    #域名跳转

        server {

            listen       80;

            server_name  jump.88dgw.com;

            index index.html index.htm index.php;

            root  /opt/lampp/htdocs/www;

            rewrite ^/ http://www.88dgw.com/;

            access_log  off;

        }

    #去掉php页面

        if ($request_uri ~* "^(.*/)index\.php$") {

            return 301 $1;

        }

    #index跳转到域名下

        location  /index.html {

            root /;

            rewrite ^/index.html$ / permanent;

        }

    # Remove trailing slash. 去除末尾斜杠

        if (!-d $request_filename) {

            rewrite ^/(.+)/$ /$1 permanent;

        }

    # Clean Double Slashes

        if ($request_uri ~* "\/\/") {

          rewrite ^/(.*) /$1 permanent;

        }

    # 旧站资源转发,移除一个zhoulun目录 

        location  /zhoulujun/html/ {

            root /;

            rewrite ^/zhoulujun/html/(.*)$ /html/$1 permanent;

        }

        location  /zhoulujun/uploadfile/ {

            root /;

            rewrite ^/zhoulujun/uploadfile/(.*)$ /uploadfile/$1 break;

        }

    #多域名转向

        server {

            server_name  www.7oom.com/  www.divmy.com/;

            index index.html index.htm index.php;

            root  /opt/lampp/htdocs;

            if ($host ~ “c1gstudio\.net”) {

                rewrite ^(.*) http://www.7oom.com$1/ permanent;

            }

        }

    #三级域名跳转

            if ($http_host ~* “^(.*)\.i\.c1gstudio\.com$”) {

                rewrite ^(.*) http://top.88dgw.com$1/;

                break;

            }

    #域名镜向

        server {

            listen       80;

            server_name  mirror.c1gstudio.com;

            index index.html index.htm index.php;

            root  /opt/lampp/htdocs/www;

            rewrite ^/(.*) http://www.divmy.com/$1 last;

            access_log  off;

        }

    #某个子目录作镜向

            location ^~ /zhaopinhui {

            rewrite ^.+ http://zph.divmy.com/ last;

            break;

    #正则匹配

        location  = / {

          # 精确匹配 / ,主机名后面不能带任何字符串

          [ configuration A ]

        }

        location  / {

          # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求

          # 但是正则和最长字符串会优先匹配

          [ configuration B ]

        }

        location /documents/ {

          # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索

          # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条

          [ configuration C ]

        }

        location ~ /documents/Abc {

          # 匹配任何以 /documents/Abc 开头的地址,匹配符合以后,还要继续往下搜索

          # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条

          [ configuration CC ]

        }

        location ^~ /images/ {

          # 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。

          [ configuration D ]

        }

        location ~* \.(gif|jpg|jpeg)$ {

          # 匹配所有以 gif,jpg或jpeg 结尾的请求

          # 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则

          [ configuration E ]

        }

        location /images/ {

          # 字符匹配到 /images/,继续往下,会发现 ^~ 存在

          [ configuration F ]

        }

        location /images/abc {

          # 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在

          # F与G的放置顺序是没有关系的

          [ configuration G ]

        }

        location ~ /images/abc/ {

          # 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用

            [ configuration H ]

        }

    转载请注明文字出处:Nginx葵花宝典-草根站长Nginx运维百科全书 -nginx文章列表 - 周陆军的个人网站,链接https://www.zhoulujun.cn/html/tools/nginx/2018_0618_8124.html如果不妥之处,请告知,谢谢!

    参考文章:

    最新版 nginx内置变量 大全

    Nginx 中last和break 及 permanent 和 redirect 的爱恨情仇

    nginx rewrite规则

    Nginx路径匹配规则详解

    Nginx虚拟目录alias和root目录

    Nginx Location 路径匹配优先级

    相关文章

      网友评论

        本文标题:Nginx葵花宝典—草根站长Nginx运维百科全书

        本文链接:https://www.haomeiwen.com/subject/evjzuftx.html