Nginx反向代理(下)
本小節,我們繼續學習 Nginx 在 七層反向代理中的其它幾種比較常見的情況,比如 web 服務中的 WebSocket 協議的反向代理和 uwsgi 協議的反向代理。
1. WebSocket的反向代理
WebSocket 是目前比較成熟的技術了, WebSocket 協議為創建客戶端和服務器端需要實時雙向通訊的 webapp 提供了一個選擇。服務器可以向瀏覽器推送相關消息,這樣在前端實現的某個頁面中我們可以及時看到服務器的狀態變化而不用使用定時刷新去獲取后臺信息。目前大部分瀏覽器都支持 WebSocket 協議,比如 Firefox,IE,Chrome,Safari,Opera,并且越來越多的服務器框架現在也同樣支持 WebSocket。此外,在js、java 和 python 中都提供了 Websocket 開發庫,這也使得 websocket 協議的廣泛應用于 web 服務的開發中。當然作為瀏覽器和后臺服務的中間代理的 Nginx 也必定支持 Websocket,這樣能更好的完成代理角色。在 Nginx 中通過 ngx_http_proxy_module 模塊實現 Websocket 反向代理功能,具體實現配置如下:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
上述配置表示將轉發的協議提升至1.1, 同時在轉發的 http 請求的頭部中加上如下配置:
Upgrade: websocket
Connection: upgrade
這兩個字段表示請求服務器升級協議為 WebSocket。上游服務器處理完請求后,響應如下報文:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade
這個響應是告訴客戶端已成功切換協議,升級為 Websocket 協議。握手成功之后,服務器端和客戶端便角色對等,就像普通的 Socket 一樣,能夠雙向通信。 不再進行 HTTP 的交互,而是開始 WebSocket 的數據幀協議實現數據交換。默認情況下,連接將會在無數據傳輸60秒后關閉,proxy_read_timeout 參數可以延長這個時間。源站通過定期發送 ping 幀以保持連接并確認連接是否還在使用。
通過以上簡簡單單的三行配置,我們就能在 Nginx 中輕松實現 Websocket 的反向代理,這也說明了 Nginx 的簡單易用特點。
2. uwsgi的反向代理
首先,理清楚幾個概念:
- WSGI:全稱是 Web Server Gateway Interface,WSGI 只是一種規范,描述 web server 如何與 web application 通信的規范。要實現 WSGI 協議,必須同時實現 web server 和 web application,當前運行在 WSGI 協議之上的 web 框架有 Flask, Django,這也是目前最流行的 python web框架。
- uwsgi:與WSGI一樣是一種通信協議,是uWSGI服務器的獨占協議,用于定義傳輸信息的類型(type of information),每一個uwsgi packet前4byte為傳輸信息類型的描述。
- uWSGI:是一個web服務器,實現了WSGI協議、uwsgi協議、http協議等。
WSGI 協議其實是定義了一種 server 與 application 解耦的規范,即可以有多個實現 WSGI server 的服務器,也可以有多個實現 WSGI application 的框架,那么就可以選擇任意的 server 和 application 組合實現自己的 web 應用。Django,Flask 框架都有自己實現的簡單的WSGI server,一般用于服務器調試,生產環境下直接使用WSGI server。
Nginx 中將 http 協議的報文轉換成 uwsgi 協議的報文,只需要使用 uwsgi_pass 指令即可。和 proxy_pass 指令類似,前者轉發為 uwsgi 協議的報文,后者代理轉發 http 協議的報文。其余用法一致。
Syntax: uwsgi_pass [protocol://]address;
Default: —
Context: location, if in location
用法示例:
...
http {
...
server {
listen 9000;
location / {
# 包含uwsgi請求描述文件
include uwsgi_params;
# 配置請求傳遞,socket地址
uwsgi_pass 127.0.0.1:9000;
}
}
...
}
...
3. 案例測試
3.1 Websocket 反向代理
我們打開百度搜索"websocket在線測試",找到 websocket 的在線測試網站。
可以看到 121.40.165.18:8800 是該網站提供 websocket 連接的后端服務地址。我們借助這個地址來完成一個簡單的測試。我們找一臺公網上的云主機,其 ip 地址為 180.76.152.113,在上面搭建 Nginx 服務,添加監聽9000端口的服務配置如下:
...
http {
...
server {
listen 9000;
default_type text/plain;
access_log logs/ws.log;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://121.40.165.18:8800;
}
}
...
}
...
然后我們將 websocket 在線測試網站中的測試地址改成 ws://180.76.152.113:9000,斷開后再次連接,發現也能成功,同時能實現原服務的功能。這說明我們的 Nginx 服務成功完成了 Websocket 代理功能。
3.2 uwsgi協議的反向代理
本次實驗按照如下步驟進行:
- 首先我們安裝 WSGI server,直接使用 pip 安裝即可:
pip install uwsgi -i https://pypi.tuna.tsinghua.edu.cn/simple
- 編寫test.py文件:
def application(env, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'hello world\n',]
- 啟動 WSGI server并監聽7000端口。
# 指定socket連接,監聽端口,應用代碼文件以及進程數
$ uwsgi --socket :7000 --wsgi-file test.py --master --processes 4
- 在nginx.conf中添加如下 server 指令塊:
server {
listen 7001;
default_type text/plain;
access_log logs/uwsgi.log;
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:7000;
}
}
- 最后在本地可以請求 Nginx 服務地址的7001端口,可以看到返回 “hello world” 字符串,說明 Nginx 轉發 uwsgi 協議成功。
[shen@shen ~]$ curl http://180.76.152.113:7001
hello world