OpenResty 中的流式 HTTP 響應輸出
在這個影片中,我將演示如何在 OpenResty 中進行流式 HTTP 響應體輸出。
cd ~/
mkdir stream-resp/
cd stream-resp/
我們一如既往地建立子目錄結構。
mkdir logs conf html
我們快速寫出模板配置。
vim conf/nginx.conf
並在此檔案中進行以下編輯。
- 我們建立一個 HTTP 伺服器,監聽 8080 埠。
- 增加一個
/test
位置。 - 指定這個
application/octet-stream
MIME 型別是很重要的,這樣才能讓 Chrome 網路瀏覽器滿意。 - 透過 content_by_lua_block 指令新增一些 Lua 程式碼。
- 我們每隔一秒輸出一行輸出。
- 我們需要顯式呼叫 ngx.flush 方法來重新整理 Nginx 的寫緩衝區。這是一個 100% 非阻塞的呼叫。
- 而我們使用
ngx.sleep
在每次迴圈迭代中睡一秒鐘。這也是非阻塞的。 - 然後我們為
html
目錄建立一個根位置。
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 8080 reuseport;
location = /test {
default_type application/octet-stream;
content_by_lua_block {
for i = 1, 4 do
ngx.say("hello ", i)
ngx.flush(true)
ngx.sleep(1) -- sec
end
}
}
location / {
default_type text/html;
root html;
}
}
}
我們現在就來檢查一下整個目錄樹。
tree .
看起來不錯。
現在啟動這個 OpenResty 應用程式。
openresty -p $PWD/
是時候用 curl
來查詢我們的 HTTP 位置了。
curl 'http://127.0.0.1:8080/test'
酷,確實是每秒生成一行字!
為了驗證一切是否真的是非阻塞的,我們可以用 weighttp
工具載入這個 HTTP API。請注意,這將需要一段時間,因為我們在這裡故意放慢響應速度。
weighttp -c 500 -k -n 500 127.0.0.1:8080/test
因此,在 500 個併發請求的情況下,我們仍然可以實現每秒 120 個以上的請求!需要注意的是,每個請求需要 4 秒才能完成。而這裡我們只使用了一個工作程序和一個作業系統執行緒。
我們仍然可以將併發量提高很多,但是我們需要對 Nginx 配置進行相應的調整。
vim conf/nginx.conf
比如把 worker_connections
調到一個較大的數值。
透過啟用訪問日誌緩衝也可以獲得更好的效能。我們還可以減少請求記憶體池的大小。
現在讓我們建立一個 HTML 頁面,在 Web 瀏覽器中進行測試。
vim html/a.html
我們在這個檔案中進行以下編輯。
- 增加一個
DIV
標籤,以保持輸出。 - 新增一些 JavaScript 來傳送 AJAX 請求到我們之前的 HTTP 位置。
- 我們取出
DIV
元素。 - 讓我們新增一個 JavaScript 函式來進行流式響應接收。
- 確保有新的資料。
- 將我們的新資料追加到
DIV
元素中。在這裡,我們是懶惰的。我們不需要對特殊的 HTML 字元進行轉義。 - 而且我們每秒都會檢查新的傳入響應資料。
- 火狐支援更巧妙的方式,但我們也要支援 Chrome。
- 最後,我們處理響應體流的結束。
- 最後一次檢查響應資料。
- 刪除我們的定期計時器。
- 並將最終的輸出結果追加到網頁上。
- 為了簡潔起見,我們在此省略錯誤處理。
<!doctype html>
<html>
<body>
<div style="margin: 2em;" id="out"></div>
<script>
(function () {
let xhttp = new XMLHttpRequest();
xhttp.open("GET", "/test", true);
xhttp.send();
let div = document.getElementById("out")
let total_len = 0
let check_resp = function () {
let resp = xhttp.responseText
let len = resp.length
if (len > total_len) {
let new_data = resp.substring(total_len, len)
total_len = len;
div.innerHTML += new_data + "<br/>"
}
};
let timer = setInterval(check_resp, 1000);
check_resp();
xhttp.onreadystatechange = function () {
if (this.readyState == 4) {
check_resp();
clearInterval(timer);
div.innerHTML += "done<br/>";
}
};
})();
</script>
</body>
</html>
我們再來檢查一下整個目錄樹。
tree .
我們不需要重新載入或重新啟動 OpenResty 伺服器,因為它只是一個靜態的 HTML 頁面。
ps aux|grep nginx|grep -v /tmp/
是時候用 Chrome 開啟這個 HTML 頁面了。
生效了!這就是我今天要講的全部內容。 如果你喜歡這個教程,請訂閱這個部落格網站和我們的 YouTube 頻道 或 B 站頻道。謝謝!
關於本文和關聯影片
本文和相關聯的影片都是完全由我們的 OpenResty Showman 產品從一個簡單的劇本檔案自動生成的。
關於作者
章亦春是開源 OpenResty® 專案創始人兼 OpenResty Inc. 公司 CEO 和創始人。
章亦春(Github ID: agentzh),生於中國江蘇,現定居美國灣區。他是中國早期開源技術和文化的倡導者和領軍人物,曾供職於多家國際知名的高科技企業,如 Cloudflare、雅虎、阿里巴巴, 是 “邊緣計算“、”動態追蹤 “和 “機器程式設計 “的先驅,擁有超過 22 年的程式設計及 16 年的開源經驗。作為擁有超過 4000 萬全球域名使用者的開源專案的領導者。他基於其 OpenResty® 開源專案打造的高科技企業 OpenResty Inc. 位於美國矽谷中心。其主打的兩個產品 OpenResty XRay(利用動態追蹤技術的非侵入式的故障剖析和排除工具)和 OpenResty Edge(最適合微服務和分散式流量的全能型閘道器軟體),廣受全球眾多上市及大型企業青睞。在 OpenResty 以外,章亦春為多個開源專案貢獻了累計超過百萬行程式碼,其中包括,Linux 核心、Nginx、LuaJIT、GDB、SystemTap、LLVM、Perl 等,並編寫過 60 多個開源軟體庫。
關注我們
如果您喜歡本文,歡迎關注我們 OpenResty Inc. 公司的部落格網站 。也歡迎掃碼關注我們的微信公眾號:
翻譯
我們提供了英文版原文和中譯版(本文) 。我們也歡迎讀者提供其他語言的翻譯版本,只要是全文翻譯不帶省略,我們都將會考慮採用,非常感謝!