Nginx中URL重写功能以及内置变量

1、Nginx内置变量

常见的内置变量有如下几种:

  • $args,此变量与请求行中的参数相等

  • $query_string,此变量与$args含义一致。

  • $document_root,此变量等同于当前请求的root指令指定的值

  • $uri,表示不带请求参数的当前URL,$uri不包含主机名。如http://www.magedu.net/main/index.do?id=090&partner=search会被定义为/main/index.do

  • $document_uri,此变量与$uri含义一样。

  • $request_uri #包含请求参数的原始URI,不包含主机名,由客户端请求决定,不能修改。如http://www.magedu.net/main/index.do?id=090&partner=search会被定义为/main/index.do?id=090&partner=search

  • $host,此变量与请求头部中“Host”行指定的值一致。

  • $limit_rate,此变量用来设置限制连接的速率

  • $request_method,#请求资源的方式,GET/PUT/DELETE等

  • $remote_addr,此变量表示客户端IP地址。

  • $server_addr #表示请求的服务器地址

  • $remote_port,此变量表示客户端端口

  • $server_port,此变量表示请求到达的服务器的端口号

  • $server_name,此变量表示请求到达的服务器名。默认是localhost

  • $remote_user,此变量等同于用户名,由ngx_http_auth_basic_module认证。

  • $request_filename,#当前请求的资源文件的路径名称,由root或alias指令与URI请求生成的文件绝对路径,如/apps/nginx/html/main/index.html

  • $request_body_file;#做反向代理时发给后端服务器的本地资源的名称

  • $cookie_name; #表示key为 name 的cookie值

  • $http_cookie; #客户端的cookie信息

  • $http_user_agent; #客户端浏览器的详细信息

  • $scheme; #请求的协议,如ftp,https,http等

  • $server_protocol; #请求资源的协议版本,如HTTP/.0,HTTP/.,HTTP/.0等

例1:http://188.19.236.18:8000/abc?test=123&test2=abc :

其中:

  • $args:test=123&test2=abc

  • $uri: /abc

  • $server_addr:188.19.236.18

  • $server_port:8000

  • $request_filename:abc

  • $request_uri:/abc?test=123&test2=abc

例2:http://172.16.213.199:88/test1/test2/test.php ,假定虚拟主机根目录为/var/www/html

其中:

  • $host:172.16.213.199

  • $server_port:88

  • $request_uri: /test1/test2/test.php

  • $document_uri:/test1/test2/test.php

  • $document_root:/var/www/html

  • $request_filename:/var/www/html/test1/test2/test.php

2、if指令

if指令用于判断一个条件,如果条件成立,则后面的大括号内的语句将执行,相关配置从上级继承。if指令的使用方法如下:
语法:if (condition) { … }
默认值:none
使用字段:server, location
在默认情况下,if指令默认值为空,可在nginx配置文件的server、location部分使用

另外,if指令可以在判断语句中指定正则表达式或通过nginx内置变量匹配条件等

相关匹配条件如下:

正则表达式匹配规则:

  • ~ 表示区分大小写匹配
  • ~* 表示不区分大小写匹配
  • !~!~*分别表示区分大小写不匹配及不区分大小写不匹配

文件及目录匹配:

  • -f!-f用来判断是否存在文件
  • -d!-d用来判断是否存在目录
  • -e!-e用来判断是否存在文件或目录
  • -x!-x用来判断文件是否可执行
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$  {
				#先在这个路径下查找
                root    /data/wwwroot/www.ixdba.net;
                if (!-f $request_filrname)
                {
                	#找不到就在这个路径下查找
                	root /var/www/html/img;
                }
                if (!-f $request_filrname)
                {
                	#再找不到就到这个路径下查找
                	root /apps/images;
                }
}
location ~ .*.jsp$ { 
			   root /webdata/webapp/www/ROOT;
                if (!-f $request_filrname)
                {
                	#再找不到就到这个路径下查找
                	root /apps/images;
                }
                #找到了就交给本地的8080端口处理
			   proxy_pass http://localhost:8080;
}

$ vim /etc/nginx/nginx.conf
	location /test {
		index index.html;
		default_type text/html;
		if ( $scheme = http ){
		return 301 https://www.hxg.com/;		#如果请求协议为http时,范围301,并跳转到https://www.hxg.com/上 
		}
	}

return
return code [text]; #返回客户端指定的状态码和文本说明
return code URL; #返回code和新地址
return URL; #直接返回新地址
停止处理,并返回给客户端指定的响应码(包括: 204, 400, 402 — 406, 408,410, 411, 413, 416, 500 — 504)

并对 301, 302, 303, 307, 308跳转到URL

3、rewrite指令

Nginx通过ngx_http_rewrite_module模块支持url重写、支持if条件判断

但要使用rewrite功能,需要PCRE支持,应在编译nginx时指定PCRE源码目录。

rewrite的使用语法如下:

语法:rewrite regex replacement [flag]

默认值:none

使用字段:server, location, if

其中:

  • regex 正则表达式

  • replacement 跳转的地址

  • flag标记,其支持的flag标记主要有以下几种:

    • last, 相当于Apache里的[L]标记,表示完成rewrite之后搜索相应的URI或location。匹配到会继续匹配,直到匹配完。
    • break,表示终止匹配, 不再匹配后面的规则
    • redirect,将返回302临时重定向,在浏览器地址栏会显示跳转后的URL地址。
    • permanent,将返回301永久重定向,在浏览器地址栏会显示跳转后的URL地址。

    其中,last和break用来实现URL重写,浏览器地址栏中的URL地址不变

重点

如果想实现重写到其他主机而不变浏览器地址栏地址,需要注意

需要结合proxy_pass来实现

location / {
      rewrite ^/(.*)$ http://www.tb.cn/$1 break;#这种重写加主机的方式,无论加break还是permanent都无法实现原地址不变
}
    
#要实现原地址不变跳转,需要结合proxy_pass来实现
location /aaa{
       rewrite ^/aaa /abc break;
       proxy_pass http://10.50.20.3;
}

下面是一个示例配置,仅列出整个配置中的location部分:

location ~ ^/new/ {
        rewrite ^/new/(.*)$  /old/$1  break;#当访问的是/new/开头的链接是重定向到/old下  $1是后项引用,引用的是前面第一个小括号里面的内容
        proxy_pass  http://www.tb.com;#当上面匹配到了资源,然后交给http://www.tb.com主机处理
 }
 #在这个例子中
 #假定访问的域名是www.newtb.com,那么当访问www.newtb.com/new/web.html时
 #nginx可以通过rewrite将页面重定向到www.tb.com/old/web.html
 #由于是通过反向代理实现了重定向,因此页面重写后不会引起浏览器地址栏中URL的变化
 #这个功能在新旧网站交替的时候非常有用
 
 
 location /break {
		rewrite ^/break/(.*)$ /test/$1 break; 	#break不会跳转到其他的location
		return 666 "break";
}
 location /last {
		rewrite ^/last/(.*)$ /test/$1 last; 	#last会跳转到其他的location继续匹配新的URI
		return 888 "last";
}
 location /abc {
		return 666 "return";     #返回状态码666 并直接返回文本return
		index index.html;
		root /data/nginx;
}

实验

实验:将 http:// 请求跳转到 https:// (用rewrite)

$ vim /etc/nginx/nginx.conf
server {
		listen 443 ssl; #用listen 跟ssl开启ssl服务
		listen 80 ;	    #同时监听80和443端口
		server_name www.abc.com;
		root /data/abc;	#网站主目录
		ssl_certificate /data/ssl/hxg.crt;	#指明证书地址
		ssl_certificate_key /data/ssl/hxg.key;#指明密钥地址
		ssl_session_cache shared:sslcache:20m;
		ssl_session_timeout 10m;
		location / {
		if ($scheme = http ) {#判断,如果是http协议,则跳转到https上
			rewrite ^/(.*)$ https://www.abc.com/$1 redirect;
		}
	}
}

测试:http://www.abc.com --> https://www.abc.com/

实验:当用户访问到公司网站的时输入了一个错误的URL,可以将用户重定向至官网首页

location / {
		root /data/abc;
		index index.html;
		if (!-e $request_filename) {#判断文件是否存在,不存在则执行rewrite
		rewrite /(.*) http://www.abc.com/ redirect;
	}
}

4、set指令

下面是一个示例配置,仅列出整个配置中的location部分:

location / {
    if ($query_string ~ "id=(.*)") {
    set $myid $1; 
    rewrite ^/app.php$ /m-$myid.html?;     
    }
}

这是一个伪静态的例子

假如访问的域名是 www.abc.com,那么上面这个配置要实现的功能是将请求为 www.abc.com/app.php?id=100 重定向到 www.abc.com/m-100.html

这里用到了if指令和set指令,并且还使用了 $query_string 变量,此变量用于获取请求行中的参数

if指令用来判断请求参数中的id值

然后通过set指令定义了一个变量 $myid ,并将 $query_string 变量中获取到的id值赋给 `$myid
最后通过rewrite指令进行了url重写。


这里需要注意的是:

rewrite只能针对请求的uri进行重写,而对请求参数无能为力,/app.php 问号后面的 id=100 是请求参数,要获取到参数,需要使用nginx的一个内部变量 $query_string,这样在重写的时候只需把 $query_string 变量追加到重写的uri后面即可,另外,为了防止uri中的参数追加到重写后的uri上,需要在rewrite最后面加个问号

不加问号演示

location / {
        index index.html index.htm;
        root html;
        if ($query_string ~ "id=(.*)&") {
        set $id $1;
        rewrite ^/abc.php$ /m-$id.html permanent;
    }
}

访问http://10.0.0.5/abc.php?id=123&cc=123 ----------->浏览器地址栏会变成http://10.0.0.5/m-123.html?id=123&cc=123 后面的参数会原封不动的加载后面

加问号演示

location / {
        index index.html index.htm;
        root html;
        if ($query_string ~ "id=(.*)&") {
        set $id $1;
        rewrite ^/abc.php$ /m-$id.html? permanent;
    }
}

访问http://10.0.0.5/abc.php?id=123&cc=123 ----------->浏览器地址栏会变成http://10.0.0.5/m-123.html 后面就不会有参数了

5、break指令

break的用法在前面的介绍中其实已经出现过,它表示完成当前设置的规则后,不再匹配后面的重写规则。break使用语法如下:

语法:break

默认值:none

使用字段:server, location, if

下面是一个应用实例,仅列出整个配置中的server部分:

server {
    listen    80;
    server_name www.tb.cn;
    if ($host != 'www.tb.cn') {
    rewrite ^/(.*)$ http://www.tb.cn/error.txt break;  #重定向
    rewrite ^/(.*)$ http://www.tb.cn/$1 permanent;
    }
}

在这个例子中,定义了一个域名www.tb.cn

当访问的域名不是www.tb.cn时,会将请求重定向到“http://www.tb.cn/error.txt” 页面, 由于设置了break指令

因此下面的rewrite规则不再被执行,直接退出

而当访问的域名是www.tb.cn时,将直接执行最后一个rewrite指令。

这里需要重点掌握一下break的功能,它表示完成当前设置的规则后,不再匹配后面的重写规则,也就是当满足if指令后,直接退出,而不会去执行最后一个rewrite指令的规则。

posted @ 2023-12-18 15:49  厚礼蝎  阅读(885)  评论(0编辑  收藏  举报