1. 程式人生 > 實用技巧 >Codeforces Round #656 (Div. 3)部分題解

Codeforces Round #656 (Div. 3)部分題解

一 重定向概述

1.1 重定向介紹

重定向(Redirect)指通過各種方法將各種網路請求重新定個方向轉到其它位置(如:網頁重定向、域名的重定向、路由選擇的變化也是對資料報文經由路徑的一種重定向)。 URL重寫是指通過配置conf檔案,以讓網站的URL中達到某種狀態時則定向/跳轉到某個規則,比如常見的偽靜態、301重定向、瀏覽器定向等。當客戶端瀏覽某個網址時,將其訪問導向到另一個網址的技術。 其主要場景有如下兩個:
  • 將一串很長的網址,轉成較短的網址,從而實現便於傳播、易於記憶。
  • 調整或更換Web伺服器,網址(域名)又必須要變更(如訪問目錄、訪問副檔名HTML變為PHP、訪問域名),為了能使舊的訪問依舊生效,從而實現自動重定向到新的網站。

1.2 類似概念

地址重寫:為了實現地址的標準化,如位址列中中輸入 www.baidu.com. 也可以輸入 www.baidu.cn。最後都會被重寫到 www.baidu.com 上。瀏覽器的位址列也會顯示www.baidu.com。即nginx把收到的客戶端的請求後把客戶端需要請求的內容所對應的伺服器地址發給客戶端,讓客戶端自己去獲取,nginx同時返回302正確資訊。 地址轉發:指在網路資料傳輸過程中資料分組到達路由器或橋接器後,該裝置通過檢查分組地址並將資料轉發到最近的區域網的過程。 反向代理:當瀏覽器訪問網站時,nginx反向代理伺服器會代替客戶端向後端伺服器查詢所需的內容,然後nginx反向代理伺服器會把查詢的內容返回給客戶端。 地址重寫和地址轉發有以下不同點: 1. 地址重寫會改變瀏覽器中的地址,使之變成重寫成瀏覽器最新的地址。而地址轉發不會改變瀏覽器的地址的。 2. 地址重寫會產生兩次請求,而地址轉發只會有一次請求。 3. 地址轉發一般發生在同一站點專案內部,而地址重寫且不受限制。 4. 地址轉發的速度比地址重定向快。 注意:重定向和反向代理都可以實現Nginx的內容重定向。

1.3 重定向狀態碼

301:代表永久性轉移(Permanently Moved):舊地址A的資源已經被永久地移除了(這個資源不可訪問了),搜尋引擎在抓取新內容的同時也將舊的網址交換為重定向之後的網址; 302:代表暫時性轉移(Temporarily Moved):舊地址A的資源還在(仍然可以訪問),這個重定向只是臨時地從舊地址A跳轉到地址B,搜尋引擎會抓取新的內容而儲存舊的網址。 301和302狀態碼都表示重定向,表示瀏覽器在拿到伺服器返回的這個狀態碼後會自動跳轉到一個新的URL地址,這個地址可以從響應的Location首部中獲取(客戶端輸入的地址A瞬間變成了另一個地址B)。

1.4 涉及符號

  • 正則表示式
  1 ~			#表示匹配過程中區分大小寫;
2 ~* #表示匹配過程中不區分大小寫;
3 !~ #如果 '~' 匹配失敗時,那麼該條件就為true;
4 !~* #如果 '~*' 匹配失敗時,那麼該條件就為true。
示例01:
  1 if ($http_user_agent ~ MSIE) {
2 ……
3 }
$http_user_agent值中是否含有 MSIE 字串,如果包含則為true,否則為false。 注意:當表示式只是一個變數時,如果值為空或任何以0開頭的字串都會當做false。 示例02:
  1 if ( $http_user_agent ~* "(Android)|(iPhone)|(Mobile)|(WAP)|(UCWEB)" ){
2 rewrite ^/$ http://www.cnblogs.com permanent;
3 }
解釋: $http_user_agent值若為相應的手機訪問,則直接重定向至特定網頁。
  • 檔案匹配
  1 -f			#如果請求的檔案存在,那麼該條件為true;
2 !-f #如果該檔案的目錄存在,該檔案不存在,那麼返回true。如果該檔案和目錄都不存
在,請求的檔案存在,也為false。 示例:
  1 if (-f $request_filename) {
2 ……
3 }
解釋:判斷請求的檔案是否存在
  1 if (!-f $request_filename) {
2 ……
3 }
解釋:判斷請求的檔案是否不存在
  • 目錄匹配
  1 -d			#如果請求的目錄存在,則返回true。否則返回false;
2 !-d #如果請求的目錄不存在,但是該請求的上級目錄存在,則返回true。如果該上級目錄不存在,則返回false。
3 -e和!-e #用來判斷是否存在檔案或目錄
4 -x和!-x #用來判斷檔案是否可執行
  • flag標記
  1 last			#表示完成rewrite,之後繼續向下匹配新的location URI規則,瀏覽器位址列URL地址不變。
2 break #本條規則匹配完成後,終止匹配, 不再匹配後面的規則,完成重寫指令,瀏覽器位址列URL地址不變。
3 redirect #返回302臨時重定向,瀏覽器地址會顯示跳轉新的URL地址。
4 permanent #返回301永久重定向,瀏覽器地址會顯示跳轉新的URL地址。
注意:last和break的區別參考配置示例09。 last一般寫在server和if中,而break一般使用在location中;


last不終止重寫後的url匹配,即新的url會再從server走一遍匹配流程,而break終止重寫後的匹配;


break和last都能阻止繼續執行後面的rewrite指令。

  • 其他全域性變數
  1 $args			#該變數中存放了請求URL中的請求指令,同$query_string;
2 $content_length #該變數中存放了HTTP請求頭中的Content-length欄位。;
3 $content_type #該變數中存放了HTTP請求頭中的Content-type欄位;
4 $document_root #該變數中存放了針對當前請求的根路徑。
5 $document_uri #該變數中存放了請求的當前URI, 但是不包括請求指令;
6 $host #變數中存放了請求的URL中的主機部分欄位,如果請求中沒有Host行,則等於設定的伺服器名;
7 $http_host #該變數與$host唯一區別帶有埠號;
8 $http_user_agent #該變數中存放客戶端的代理資訊;
9 $http_cookie #該變數中存放客戶端的cookie資訊。
10 $limit_rate #對連線速率的限制;
11 $request_method #請求的方法,比如"GET"、"POST"等;
12 $remote_addr #該變數中存放客戶端的地址;
13 $remote_port #該變數中存放了客戶端與伺服器建立連線的埠號;
14 $remote_user #該變數中存放客戶端的使用者名稱,認證用;
15 $request_filename #該變數中存放了當前請求的資原始檔的路徑名;
16 $request_body_file #該變數中存放了發給後端伺服器的本地檔案資源的名稱;
17 $request_method #該變數中存放了客戶端的請求方式,比如 'GET'、'POST'等。
18 $request_uri #該變數中存放了當前請求的URI,並且帶請求指令,即帶查詢字串,不包含主機名,如:”/foo/bar.php?arg=baz”;
19 $query_string #與$args相同;
20 $scheme #該變數中存放了客戶端請求使用的協議,比如http或者是https;
21 $server_protocol #該變數中存放了客戶端請求協議的版本請求的協議版本,"HTTP/1.0"或"HTTP/1.1";
22 $server_addr #伺服器地址,如果沒有用listen指明伺服器地址,使用這個變數將發起一次系統呼叫以取得地址(造成資源浪費);
23 $server_name #請求到達的伺服器名;
24 $server_port #請求到達的伺服器埠號;
25 $uri #請求的URI,可能和最初的值有不同,比如經過重定向之類的。
引數示例: 訪問連結是:http://demo.linuxds.com:88/test1/test2/test.php 網站路徑是:/var/www/html
  1 $host:demo.linuxds.com
2 $server_port:88
3 $request_uri:http://demo.linuxds.com:88/test1/test2/test.php
4 $document_uri:/test1/test2/test.php
5 $document_root:/var/www/html
6 $request_filename:/var/www/html/test1/test2/test.php

1.5 return釋義

return一般用於對請求的客戶端直接返回響應狀態碼。在該作用域內return後面的所有nginx配置都是無效的。可以使用在server、location以及if配置中。除了支援跟狀態碼,還可以跟字串或者url連結。 示例01:
  1 server{
2 listen 80;
3 server_name www.linuxds.com;
4 return 403;
5 rewrite /(.*) /abc/$1; #該行配置位於return後,則不會被執行。
6 }
示例02:
  1 server {
2 .....
3
4 if ($request_uri ~ "\.htpasswd|\.bak")
5 {
6 return 404;
7 rewrite /(.*) /aaa.txt; #該行配置位於return後,則不會被執行。
8 }
9 #如下為其他server,不受上一個server中的return影響,即若下面還有其他配置,會被執行。
10 .....
11 }
示例03:
  1 server{
2 listen 80;
3 server_name www.linuxds.com;
4 return 200 "hello";
5 }
說明:如果要想返回字串,必須要加上狀態碼,否則會報錯。 示例04:
  1 location ^~ /aming {
2 default_type application/json ;
3 return 200 '{"name":"xhy","id":"100"}';
4 } #返回的字串也支援json資料。
示例05:
  1 location /test {
2 return 200 "$host $request_uri";
3 } #返回的字串也支援變數
示例06:
  1 server{
2 listen 80;
3 server_name www.linuxds.com;
4 return http://www.linuxds.com/123.html;
5 rewrite /(.*) /abc/$1; #該行配置位於return後,則不會被執行。
6 }
注意:return後面的url必須是以http://或者https://開頭的。

二 重定向配置

2.1 配置語法

語法:rewrite regex replacement [flag];; 預設值:—— 可配置段:server, location 作用:通過正則表示式的使用來改變URI。可以同時存在一個或多個指令。需要按照順序依次對URL進行匹配和處理。 示例:
  1 rewrite ^/(.*) http://www.baidu.com/$1 permanent;
解釋: rewrite:固定關鍵字,表示開始進行rewrite匹配規則。 正則表示式^/(.*):正則表示式,匹配完整的域名和後面的路徑地址。 replacement為http://www.baidu.com/$1:其中$1是取regex部分()裡面的內容。如果匹配成功後跳轉到的URL。 flag為permanent:代表永久重定向,即跳轉到 http://www.baidu.com/$1 地址上。

2.2 配置示例01

  1 [[email protected] ~]# vi /etc/nginx/conf.d/rewrite01.conf
2 server {
3 listen 80;
4 server_name cnblogs.linuxds.com;
5 access_log /var/log/nginx/cnblogs.access.log main;
6 error_log /var/log/nginx/cnblogs.error.log warn;
7 location / {
8 if ($host = 'cnblogs.linuxds.com') {
9 rewrite ^/(.*) http://www.cnblogs.com redirect;
10 }
11 }
12 }
  1 [[email protected] ~]# nginx -t -c /etc/nginx/nginx.conf	#檢查配置檔案
2 [[email protected] ~]# nginx -s reload #過載配置檔案
配置解釋:結合if指令來對nginx請求進行判斷,若訪問http://cnblogs.linuxds.com,即$host = 'cnblogs.linuxds.com' 的時候,進行重定向跳轉,重定向至 http://www.cnblogs.com。 瀏覽測試:http://cnblogs.linuxds.com,訪問後會立刻跳轉。

2.2 配置示例02

  1 [[email protected] ~]# mkdir /usr/share/nginx/file/
2 [[email protected] ~]# echo '<h1>File</h1>' > /usr/share/nginx/file/index.html
  1 [[email protected] ~]# vi /etc/nginx/conf.d/rewrite02.conf
2 server {
3 listen 80;
4 server_name file.linuxds.com;
5 access_log /var/log/nginx/file.access.log main;
6 error_log /var/log/nginx/file.error.log warn;
7 location ~ .* {
8 root /usr/share/nginx/file;
9 if ( !-e $request_filename ) {
10 rewrite ^ http://www.cnblogs.com redirect;
11 }
12 }
13 }
配置解釋:結合if指令來對nginx請求進行判斷,若訪問http://file.linuxds.com的資源存在root目錄,則返回,若當前請求的資原始檔不存在,則進行重定向跳轉,重定向至 http://www.cnblogs.com。 瀏覽測試:http://file.linuxds.com/index.html,進行測試。 訪問不存在的資源http://file.linuxds.com/aaaa,進行測試。

2.3 配置示例03

  1 [[email protected] ~]# mkdir /usr/share/nginx/constant/
2 [[email protected] ~]# echo '<h1>Constant</h1>' > /usr/share/nginx/constant/index.html
  1 [[email protected] ~]# vi /etc/nginx/conf.d/rewrite03.conf
2 server {
3 listen 80;
4 server_name constant.linuxds.com;
5 access_log /var/log/nginx/constant.access.log main;
6 error_log /var/log/nginx/constant.error.log warn;
7 location ~ .* {
8 root /usr/share/nginx/constant;
9 if ( !-e $request_filename ) {
10 rewrite ^ /itzgr/ break;
11 proxy_pass http://www.cnblogs.com;
12 }
13 }
14 }
配置解釋:結合if指令來對nginx請求進行判斷,若訪問http://constant.linuxds.com的資源存在root目錄,則返回,若當前請求的資原始檔不存在,則進行重定向跳轉,重定向至http://www.cnblogs.com/itzgr。 瀏覽測試:訪問不存在的資源http://constant.linuxds.com/aaaa,進行測試。

2.4 配置示例04

  1 [[email protected] ~]# mkdir /usr/share/nginx/last/
2 [[email protected] ~]# echo '<h1>Last</h1>' > /usr/share/nginx/last/index.html
  1 [[email protected] ~]# vi /etc/nginx/conf.d/rewrite04.conf
2 server {
3 listen 80;
4 server_name last.linuxds.com;
5 access_log /var/log/nginx/last.access.log main;
6 error_log /var/log/nginx/last.error.log warn;
7 location ~ .* {
8 root /usr/share/nginx/last;
9 rewrite /last.html /index.html last;
10 }
11 }
配置解釋:訪問 /last.html 的時候,頁面內容重寫到 /index.html 中。 瀏覽測試:瀏覽器訪問http://last.linuxds.com/。 瀏覽器訪問http://last.linuxds.com/last.html。

2.5 配置示例05

  1 [[email protected] ~]# mkdir /usr/share/nginx/break/
2 [[email protected] ~]# echo '<h1>Break</h1>' > /usr/share/nginx/break/index.html
  1 [[email protected] ~]# vi /etc/nginx/conf.d/rewrite05.conf
2 server {
3 listen 80;
4 server_name break.linuxds.com;
5 access_log /var/log/nginx/break.access.log main;
6 error_log /var/log/nginx/break.error.log warn;
7 location ~ .* {
8 root /usr/share/nginx/break;
9 rewrite /break.html /index.html break;
10 }
11 }
配置解釋:訪問 /break.html 的時候,頁面內容重寫到 /index.html 中,並停止後續的匹配。 瀏覽測試:瀏覽器訪問http://break.linuxds.com/。 瀏覽器訪問http://break.linuxds.com/break.html。

2.6 配置示例06

  1 [[email protected] ~]# mkdir /usr/share/nginx/rewrite/
2 [[email protected] ~]# echo '<h1>Rewrite</h1>' > /usr/share/nginx/rewrite/index.html
  1 [[email protected] ~]# vi /etc/nginx/conf.d/rewrite06.conf
2 server {
3 listen 80;
4 server_name rewrite.linuxds.com;
5 access_log /var/log/nginx/rewrite.access.log main;
6 error_log /var/log/nginx/rewrite.error.log warn;
7 location ~ .* {
8 root /usr/share/nginx/rewrite;
9 rewrite /rewrite.html /index.html redirect;
10 }
11 }
配置解釋:訪問 /redirect.html 的時候,頁面直接302定向到 /index.html中。 瀏覽測試:瀏覽器訪問http://rewrite.linuxds.com/。 瀏覽器訪問http://rewrite.linuxds.com/rewrite.html。

2.7 配置示例07

  1 [[email protected] ~]# mkdir /usr/share/nginx/permanent/
2 [[email protected] ~]# echo '<h1>Permanent</h1>' > /usr/share/nginx/permanent/index.html
  1 [[email protected] ~]# vi /etc/nginx/conf.d/rewrite07.conf
2 server {
3 listen 80;
4 server_name permanent.linuxds.com;
5 access_log /var/log/nginx/permanent.access.log main;
6 error_log /var/log/nginx/permanent.error.log warn;
7 location ~ .* {
8 root /usr/share/nginx/permanent;
9 rewrite /permanent.html /index.html permanent;
10 }
11 }
配置解釋:訪問 /permanent.html 的時候,頁面直接301定向到 /index.html中。 瀏覽測試:瀏覽器訪問http://permanent.linuxds.com/。 瀏覽器訪問http://permanent.linuxds.com/permanent.html。

2.8 配置示例08

  1 [[email protected] ~]# mkdir -p /usr/share/nginx/dirweb/dir
2 [[email protected] ~]# echo '<h1>Dirweb</h1>' > /usr/share/nginx/dirweb/dir/index.html
  1 [[email protected] ~]# vi /etc/nginx/conf.d/rewrite08.conf
2 server {
3 listen 80;
4 server_name dirweb.linuxds.com;
5 access_log /var/log/nginx/dirweb.access.log main;
6 error_log /var/log/nginx/dirweb.error.log warn;
7 location ~ .* {
8 root /usr/share/nginx/dirweb/;
9 rewrite ^/html/(.+?).html$ /dir/$1.html permanent;
10 }
11 }
配置解釋:訪問 /html/*.html,頁面直接301定向到 /dir/*.html 中。 瀏覽測試:瀏覽器訪問http://dirweb.linuxds.com/dir/index.html。 瀏覽器訪問http://dirweb.linuxds.com/html/index.html。

2.9 配置示例09

  1 [[email protected] ~]# mkdir -p /usr/share/nginx/lbreak
2 [[email protected] ~]# echo '<h1>Lbreak</h1>' > /usr/share/nginx/lbreak/index.html
3 [[email protected] ~]# echo '<h1>Test_Lbreak</h1>' > /usr/share/nginx/lbreak/test.html
  1 [[email protected] ~]# vi /etc/nginx/conf.d/rewrite09.conf
2 server {
3 listen 80;
4 server_name lbreak.linuxds.com;
5 access_log /var/log/nginx/lbreak.access.log main;
6 error_log /var/log/nginx/lbreak.error.log warn;
7 root /usr/share/nginx/lbreak/;
8 location / {
9 rewrite /last/ /test.html last;
10 rewrite /break/ /test.html break;
11 }
12 location = /test.html {
13 return http://www.cnblogs.com;
14 }
15 }
配置解釋:訪問/last/時重寫到/test.html,然後使用新的uri再匹配,正好匹配到locatoin = /test.html然後返回http://www.cnblogs.com; 訪問/break時重寫到/test.html,由於返回了break,則直接停止了後續匹配,因此返回/test.html內容。 瀏覽測試:瀏覽器訪問http://lbreak.linuxds.com/last/。 瀏覽器訪問http://lbreak.linuxds.com/break/。

2.10 配置示例10

  1 [[email protected] ~]# mkdir -p /usr/share/nginx/admin/xhy
2 [[email protected] ~]# echo '<h1>Admin</h1>' > /usr/share/nginx/admin/admin.html
  1 [[email protected] ~]# vi /etc/nginx/conf.d/rewrite10.conf
2 server {
3 listen 80;
4 server_name admin.linuxds.com;
5 access_log /var/log/nginx/admin.access.log main;
6 error_log /var/log/nginx/admin.error.log warn;
7 root /usr/share/nginx/admin/;
8 location / {
9 rewrite /xhyadmin.html /admin.html break;
10 }
11 location /admin.html {
12 return 403;
13 }
14 }
配置解釋:訪問http://admin.linuxds.com/admin.html時直接返回無許可權的403程式碼,必須通過http://admin.linuxds.com/xhyadmin.html來進行訪問,即訪問/xhyadmin.html重寫到/admin.html,但不能直接訪問/admin.html,可應用於隱藏真實地址。 瀏覽測試:http://admin.linuxds.com/admin.html。 瀏覽器訪問http://admin.linuxds.com/xhyadmin.html。

三 其他簡略配置

  1 # 如果檔案不存在則返回400
2 if (!-f $request_filename) {
3 return 400;
4 }
  1 # 如果host不是demo.linuxds.com,則301到www.baidu.com中
2 if ( $host != 'demo.linuxds.com' ){
3 rewrite ^/(.*)$ https://www.baidu.com/$1 permanent;
4 }
  1 # 如果請求型別不是POST則返回405
2 if ($request_method = POST) {
3 return 405;
4 }
  1 # 如果引數中有 a=1 則301到demo.linuxds.com
2 if ($args ~ a=1) {
3 rewrite ^ http://demo.linuxds.com/ permanent;
4 }
  1 # 如果客戶使用IE瀏覽器訪問,則重定向到/nginx-ie目錄下:
2 if ($http_user_agent ~ MSIE) {
3 rewrite ^(.*)$ /nginx-ie/$1 break;
4 }
  1 # 多目錄重定向為引數的形式。
2 # 將xhy.linuxds.com/images/girl 重定向為 xhy.linuxds.com/index.php?act=images&name=xhy&id=girl引數的形式。
3 if ($host ~* (.*)\.domain\.com) {
4 set $sub_name $1;
5 rewrite ^/images\/(\d+)\/?$ /index.php?act=images&cid=$sub_name&id=$1 last;
6 }
  1 # 將目錄對調,/images/girl -> /girl?id=images。
2 rewrite ^/(\d+)/(.+)/ /$2?id=$1 last;
  1 # 目錄通過重定向自動追加/
2 if (-d $request_filename){
3 rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
4 }
  1 # 簡單域名重定向
2 server
3 {
4 listen 80;
5 server_name xhy.linuxds.com;
6 index index.html index.htm index.php;
7 root /usr/share/nginx/xhy/;
8 rewrite ^/ http://www.cnblogs.com;
9 access_log off;
10 }
11 server {
12 listen 80;
13 server_name linuxds.com www.linuxds.com;
14 if ($host != 'www.linuxds.com' ) {
15 rewrite ^/(.*)$ http://www.linuxds.com/$1 permanent;
16 }
17 }
  1 # 指定域名重定向
2 server_name xhy.linuxds.com xhy.linuxds.cn;
3 index index.html index.htm index.php;
4 root /usr/share/nginx/xhy/;
5 if ($host ~ "linuxds\.cn") {
6 rewrite ^(.*) http://xhy.linuxds.com$1/ permanent;
7 }
  1 # 多域名重定向
2 server_name xhy.linuxds.com xhy.linuxds.cn xhy.linuxds.net;
3 index index.html index.htm index.php;
4 root /usr/share/nginx/xhy/;
5 if ($host !~ "linuxds\.com") {
6 rewrite ^(.*) http://xhy.linuxds.com/$1 permanent;
7 }
  1 # 三級域名跳轉。
2 if ($http_host ~* "^(.*)\.i\.linuxds\.com$") {
3 rewrite ^(.*) http://xhy.linuxds.com$1/;
4 break;
5 }
  1 # 域名映象
2 server
3 {
4 listen 80;
5 server_name mirror.linuxds.com;
6 index index.html index.htm index.php;
7 root /usr/share/nginx/xhy/;
8 rewrite ^/(.*) http://xhy.linuxds.com/$1 last;
9 access_log off;
10 }