Nginx
Nginx(engine x) 是一個(gè)高性能的HTTP和反向代理web服務(wù)器,同時(shí)也提供了IMAP/POP3/SMTP服務(wù)。其將源代碼以類BSD許可證的形式發(fā)布,因它的穩(wěn)定性、豐富的功能集、簡(jiǎn)單的配置文件和低系統(tǒng)資源的消耗而聞名。
正向代理與反向代理
代理是在服務(wù)器和客戶端之間假設(shè)的一層服務(wù)器,代理將接收客戶端的請(qǐng)求并將它轉(zhuǎn)發(fā)給服務(wù)器,然后將服務(wù)端的響應(yīng)轉(zhuǎn)發(fā)給客戶端。
正向代理
正向代理,意思是一個(gè)位于客戶端和原始服務(wù)器(origin server)之間的服務(wù)器,為了從原始服務(wù)器取得內(nèi)容,客戶端向代理發(fā)送一個(gè)請(qǐng)求并指定目標(biāo)(原始服務(wù)器),然后代理向原始服務(wù)器轉(zhuǎn)交請(qǐng)求并將獲得的內(nèi)容返回給客戶端。
1、正向代理是為我們服務(wù)的,即為客戶端服務(wù)的,客戶端可以根據(jù)正向代理訪問(wèn)到它本身無(wú)法訪問(wèn)到的服務(wù)器資源。
2、正向代理對(duì)我們是透明的,對(duì)服務(wù)端是非透明的,即服務(wù)端并不知道自己收到的是來(lái)自代理的訪問(wèn)還是來(lái)自真實(shí)客戶端的訪問(wèn)。
反向代理
反向代理(Reverse Proxy)方式是指以代理服務(wù)器來(lái)接受internet上的連接請(qǐng)求,然后將請(qǐng)求轉(zhuǎn)發(fā)給內(nèi)部網(wǎng)絡(luò)上的服務(wù)器,并將從服務(wù)器上得到的結(jié)果返回給internet上請(qǐng)求連接的客戶端,此時(shí)代理服務(wù)器對(duì)外就表現(xiàn)為一個(gè)反向代理服務(wù)器。
1、反向代理是為服務(wù)端服務(wù)的,反向代理可以幫助服務(wù)器接收來(lái)自客戶端的請(qǐng)求,幫助服務(wù)器做請(qǐng)求轉(zhuǎn)發(fā),負(fù)載均衡等。
2、反向代理對(duì)服務(wù)端是透明的,對(duì)我們是非透明的,即我們并不知道自己訪問(wèn)的是代理服務(wù)器,而服務(wù)器知道反向代理在為他服務(wù)。
為什么需要Nginx反向代理
使用反向代理最主要的兩個(gè)原因: 1)安全及權(quán)限??梢钥闯觯褂梅聪虼砗?,用戶端將無(wú)法直接通過(guò)請(qǐng)求訪問(wèn)真正的內(nèi)容服務(wù)器,而必須首先通過(guò)Nginx。可以通過(guò)在Nginx層上將危險(xiǎn)或者沒(méi)有權(quán)限的請(qǐng)求內(nèi)容過(guò)濾掉,從而保證了服務(wù)器的安全。 2)負(fù)載均衡。例如一個(gè)網(wǎng)站的內(nèi)容被部署在若干臺(tái)服務(wù)器上,可以把這些機(jī)子看成一個(gè)集群,那么Nginx可以將接收到的客戶端請(qǐng)求“均勻地”分配到這個(gè)集群中所有的服務(wù)器上(內(nèi)部模塊提供了多種負(fù)載均衡算法),從而實(shí)現(xiàn)服務(wù)器壓力的負(fù)載均衡。此外,nginx還帶有健康檢查功能(服務(wù)器心跳檢查),會(huì)定期輪詢向集群里的所有服務(wù)器發(fā)送健康檢查請(qǐng)求,來(lái)檢查集群中是否有服務(wù)器處于異常狀態(tài),一旦發(fā)現(xiàn)某臺(tái)服務(wù)器異常,那么在以后代理進(jìn)來(lái)的客戶端請(qǐng)求都不會(huì)被發(fā)送到該服務(wù)器上(直到后面的健康檢查發(fā)現(xiàn)該服務(wù)器恢復(fù)正常),從而保證客戶端訪問(wèn)的穩(wěn)定性。
前端可以用Nginx做些什么
- 快速實(shí)現(xiàn)簡(jiǎn)單的訪問(wèn)限制 經(jīng)常會(huì)遇到希望網(wǎng)站讓某些特定用戶的群體(比如只讓公司內(nèi)網(wǎng))訪問(wèn),或者控制某個(gè)uri不讓人訪問(wèn)。Nginx配置如下:
location / {
deny 192.168.1.100;
allow 192.168.1.10/200;
allow 10.110.50.16;
deny all;
}
其實(shí)deny和allow是ngx_http_access_module模塊(已內(nèi)置)中的語(yǔ)法。采用的是從上到下匹配方式,匹配到就跳出不再繼續(xù)匹配。上述配置的意思就是,首先禁止192.168.1.100訪問(wèn),然后允許192.168.1.10-200 ip段內(nèi)的訪問(wèn)(排除192.168.1.100),同時(shí)允許10.110.50.16這個(gè)單獨(dú)ip的訪問(wèn),剩下未匹配到的全部禁止訪問(wèn)。實(shí)際生產(chǎn)中,經(jīng)常和ngx_http_geo_module模塊(可以更好地管理ip地址表,已內(nèi)置)配合使用。
- 解決跨域 在眾多的解決跨域方式中, 都不可避免的都需要服務(wù)端進(jìn)行支持, 使用Nginx可以純前端解決請(qǐng)求跨域問(wèn)題。 特別是在前后端分離調(diào)試時(shí), 經(jīng)常需要在本地起前端工程, 接口希望拉取服務(wù)端的實(shí)際數(shù)據(jù)而不是本地的mock。 而如果本地程序直接訪問(wèn)遠(yuǎn)程接口, 肯定會(huì)遇到跨域問(wèn)題?,F(xiàn)在前端成熟的做法,一般是把node proxy server集成進(jìn)來(lái)。事實(shí)上,用Nginx同樣可以解決問(wèn)題,甚至可以應(yīng)用于線上。 本地起一個(gè)nginx server。server_name是mysite-base.com,比如現(xiàn)在需要請(qǐng)求線上www.kaola.com域下的線上接口 www.kaola.com/getPCBanner… 的數(shù)據(jù),當(dāng)在頁(yè)面里直接請(qǐng)求,瀏覽器會(huì)報(bào)錯(cuò),為了繞開(kāi)瀏覽器的跨域安全限制,[現(xiàn)在需要將請(qǐng)求的域名改成mysite-base.com。同時(shí)約定一個(gè)url規(guī)則來(lái)表明代理請(qǐng)求的身份,然后Nginx通過(guò)匹配該規(guī)則,將請(qǐng)求代理回原來(lái)的域。Nginx配置如下:
#請(qǐng)求跨域,這里約定代理請(qǐng)求url path是以/apis/開(kāi)頭
location ^~/apis/ {
# 這里重寫了請(qǐng)求,將正則匹配中的第一個(gè)()中$1的path,拼接到真正的請(qǐng)求后面,并用break停止后續(xù)匹配
rewrite ^/apis/(.*)$ /$1 break;
proxy_pass https://www.kaola.com/;
}
在頁(yè)面代碼里,把請(qǐng)求url換成http://mysite-base.com/apis/getPCBannerList.html 。這樣就可以正常請(qǐng)求到數(shù)據(jù)。 這樣其實(shí)是通過(guò)nginx,用類似于hack的方式規(guī)避掉了瀏覽器跨域限制,實(shí)現(xiàn)了跨域訪問(wèn)。
- 適配PC與移動(dòng)環(huán)境 現(xiàn)在很多網(wǎng)站都存在PC站和H5站兩個(gè)站點(diǎn),因此根據(jù)用戶的瀏覽環(huán)境自動(dòng)切換站點(diǎn)是很常見(jiàn)的需求。Nginx可以通過(guò)內(nèi)置變量$http_user_agent,獲取到請(qǐng)求客戶端的userAgent,從而知道用戶處于移動(dòng)端還是PC,進(jìn)而控制重定向到H5站還是PC站。 例如:pc端站點(diǎn)是mysite-base.com,H5端是mysite-base-H5.com 。pc端Nginx配置如下:
location / {
# 移動(dòng)、pc設(shè)備適配
if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
set $mobile_request '1';
}
if ($mobile_request = '1') {
rewrite ^.+ http://mysite-base-H5.com;
}
}
這樣當(dāng)瀏覽設(shè)備切換成移動(dòng)模式,再次刷新頁(yè)面后,站點(diǎn)被自動(dòng)切換到H5站。
- 合并請(qǐng)求 前端性能優(yōu)化中重要一點(diǎn)就是盡量減少http資源請(qǐng)求的數(shù)量。通過(guò)nginx-http-concat模塊(淘寶開(kāi)發(fā)的第三方模塊,需要單獨(dú)安裝)用一種特殊的請(qǐng)求url規(guī)則,前端可以將多個(gè)資源的請(qǐng)求合并成一個(gè)請(qǐng)求,后臺(tái)Nginx會(huì)獲取各個(gè)資源并拼接成一個(gè)結(jié)果進(jìn)行返回。例如上面的例子通過(guò)一個(gè)請(qǐng)求將1.js,2.js,3js三個(gè)js資源合并成一個(gè)請(qǐng)求,減少了瀏覽器開(kāi)銷。 本地server mysite-base.com為例,static/js文件夾下有三個(gè)文件,文件內(nèi)容很簡(jiǎn)單,分別為:
# js資源http-concat
# nginx-http-concat模塊的參數(shù)遠(yuǎn)不止下面三個(gè),剩下的請(qǐng)查閱文檔
location /static/js/ {
concat on; # 是否打開(kāi)資源合并開(kāi)關(guān)
concat_types application/javascript; # 允許合并的資源類型
concat_unique off; # 是否允許合并不同類型的資源
concat_max_files 5; # 允許合并的最大資源數(shù)目
}
當(dāng)在瀏覽器請(qǐng)求http://mysite-base.com/static/js/??a.js,b.js,c.js 時(shí),發(fā)現(xiàn)三個(gè)js被合并成一個(gè)返回了。
- 圖片處理 在前端開(kāi)發(fā)中,經(jīng)常需要不同尺寸的圖片。現(xiàn)在的云儲(chǔ)存基本對(duì)圖片都提供有處理服務(wù)(一般是通過(guò)在圖片鏈接上加參數(shù))。其實(shí)用Nginx,可以通過(guò)幾十行配置,搭建出一個(gè)屬于自己的本地圖片處理服務(wù),完全能夠滿足日常對(duì)圖片的裁剪/縮放/旋轉(zhuǎn)/圖片品質(zhì)等處理需求。要用到ngx_http_image_filter_module模塊。這個(gè)模塊是非基本模塊,需要安裝。 下面是圖片縮放功能部分的Nginx配置:
# 圖片縮放處理
# 這里約定的圖片處理url格式:以 mysite-base.com/img/路徑訪問(wèn)
location ~* /img/(.+)$ {
alias /Users/cc/Desktop/server/static/image/$1; #圖片服務(wù)端儲(chǔ)存地址
set $width -; #圖片寬度默認(rèn)值
set $height -; #圖片高度默認(rèn)值
if ($arg_width != "") {
set $width $arg_width;
}
if ($arg_height != "") {
set $height $arg_height;
}
image_filter resize $width $height; #設(shè)置圖片寬高
image_filter_buffer 10M; #設(shè)置Nginx讀取圖片的最大buffer。
image_filter_interlace on; #是否開(kāi)啟圖片圖像隔行掃描
error_page 415 = 415.png; #圖片處理錯(cuò)誤提示圖,例如縮放參數(shù)不是數(shù)字
}
這里只是最基本的配置。此外,可以通過(guò)proxy_cache配置Nginx緩存,避免每次請(qǐng)求都重新處理圖片,減少Nginx服務(wù)器處理壓力;還以可以通過(guò)和 nginx-upload-module 一起使用加入圖片上傳的功能等。
- 頁(yè)面內(nèi)容修改 Nginx可以通過(guò)向頁(yè)面底部或者頂部插入額外的css和js文件,從而實(shí)現(xiàn)修改頁(yè)面內(nèi)容。這個(gè)功能需要額外模塊的支持,例如:nginx_http_footer_filter或者ngx_http_addition_module (都需要安裝)。 工作中,經(jīng)常需要切換各種測(cè)試環(huán)境,而通過(guò)switchhosts等工具切換后,有時(shí)還需要清理瀏覽器dns緩存??梢酝ㄟ^(guò)頁(yè)面內(nèi)容修改+Nginx反向代理來(lái)實(shí)現(xiàn)輕松快捷的環(huán)境切換。 這里首先在本地編寫一段js代碼(switchhost.js),里面的邏輯是:在頁(yè)面插入hosts切換菜單以及點(diǎn)擊具體某個(gè)環(huán)境時(shí),將該host的ip和hostname儲(chǔ)存在cookie中,最后刷新頁(yè)面;接著編寫一段css代碼(switchhost.css)用來(lái)設(shè)置該hosts切換菜單的樣式。 然后Nginx腳本配置:
server {
listen 80;
listen 443 ssl;
expires -1;
# 想要代理的域名
server_name m-element.kaola.com;
set $root /Users/cc/Desktop/server;
charset utf-8;
ssl_certificate /usr/local/etc/nginx/m-element.kaola.com.crt;
ssl_certificate_key /usr/local/etc/nginx/m-element.kaola.com.key;
# 設(shè)置默認(rèn)$switch_host,一般默認(rèn)為線上host,這里的1.1.1.1隨便寫的
set $switch_host '1.1.1.1';
# 設(shè)置默認(rèn)$switch_hostname,一般默認(rèn)為線上'online'
set $switch_hostname '';
# 從cookie中獲取環(huán)境ip
if ($http_cookie ~* "switch_host=(.+?)(?=;|$)") {
set $switch_host $1;
}
# 從cookie中獲取環(huán)境名
if ($http_cookie ~* "switch_hostname=(.+?)(?=;|$)") {
set $switch_hostname $1;
}
location / {
expires -1;
index index.html;
proxy_set_header Host $host;
#把html頁(yè)面的gzip壓縮去掉,不然sub_filter無(wú)法替換內(nèi)容
proxy_set_header Accept-Encoding '';
#反向代理到實(shí)際服務(wù)器ip
proxy_pass http://$switch_host:80;
#全部替換
sub_filter_once off;
#ngx_http_addition_module模塊替換內(nèi)容。
# 這里在頭部插入一段css,內(nèi)容是hosts切換菜單的css樣式
sub_filter '</head>' '</head><link rel="stylesheet" type="text/css" media="screen" href="/local/switchhost.css" />';
#將頁(yè)面中的'網(wǎng)易考拉'文字后面加上環(huán)境名,便于開(kāi)發(fā)識(shí)別目前環(huán)境
sub_filter '網(wǎng)易考拉' '網(wǎng)易考拉:${switch_hostname}';
#這里用了另一個(gè)模塊nginx_http_footer_filter,其實(shí)上面的模塊就行,只是為了展示用法
# 最后插入一段js,內(nèi)容是hosts切換菜單的js邏輯
set $injected '<script language="javascript" src="/local/switchhost.js"></script>';
footer '${injected}';
}
# 對(duì)于/local/請(qǐng)求,優(yōu)先匹配本地文件
# 所以上面的/local/switchhost.css,/local/switchhost.js會(huì)從本地獲取
location ^~ /local/ {
root $root;
}
}
這個(gè)功能其實(shí)為Nginx在前端開(kāi)發(fā)中的應(yīng)用提供了無(wú)限可能。例如,可以通過(guò)區(qū)分本地、測(cè)試和線上環(huán)境,為本地/測(cè)試環(huán)境頁(yè)面增加很多開(kāi)發(fā)輔助功能:給本地頁(yè)面加一個(gè)常駐二維碼便于手機(jī)端掃碼調(diào)試;本地調(diào)試線上頁(yè)面時(shí),在js文件底部塞入sourceMappingURL,便于本地debug等等。
文章摘自:https://juejin.cn/post/6844903684967825421
ngnix的基本配置:https://blog.csdn.net/weixin_42167759/article/details/85049546