## Lua
**注意:Lua腳本HTTP過濾器是實驗性的。在生產中使用需要您自擔風險。它正在被公布,以便對暴露的API進行初步反饋,并進行進一步的開發,測試和驗證。當我們認為Lua過濾器已經受到足夠的API穩定性測試,通常稱其為生產準備就緒時,該警告將被移除。**
### 概述
HTTP Lua過濾器允許在請求和響應流程中運行Lua腳本。在運行時使用[LuaJIT](http://luajit.org/)。正因為如此,支持的Lua版本大部分是5.1,具有一些5.2的特性。有關更多詳細信息,請參閱[LuaJIT文檔](http://luajit.org/extensions.html)。
該過濾器僅支持在配置中直接加載Lua代碼。如果需要本地文件系統代碼,則可以使用簡單的內聯腳本從本地環境加載代碼的其余部分。
過濾器和支持Lua是基于如下高級設計:
- 所有Lua環境都是每個工作者線程。這意味著沒有真正的全局數據。任何在加載時創建和填充的全局變量在工作線程之間相互隔離。真正的全局支持可能會在未來通過API添加。
- 所有腳本都以協程運行。這意味著即使它們可能執行復雜的異步任務,它們也是以同步樣式編寫的。這使得腳本更容易編寫。所有網絡/異步處理由Envoy通過一組API執行。Envoy將酌情切換(yield)腳本,并在異步任務完成時恢復腳本。
- 不要在腳本中執行阻塞操作。因為Envoy API會用于所有IO,以及性能相關的重要操作。
### 目前支持高級功能
**注:預計隨著Lua過濾器在生產中的應用,以下列表將隨著時間的推移而擴大范圍。這些API一直保持很小的用意。為了使腳本編寫非常簡單和安全。若存在非常復雜或更高性能的場景,請使用本地C++過濾器API。**
- 在傳輸的請求,響應流或兩者同時,提供頭部,正文和尾部的檢查;
- 對頭部和尾部進行修改;
- 阻止或者緩沖完整的請求/響應正文,進行檢查;
- 對上游主機執行異步HTTP調用。這樣可以在緩沖正文數據的同時執行處理,以便當調用完成時,可以修改上行頭部;
- 直接執行響應并跳過接下來的迭代過濾器。例如,一個腳本可以創建一個上游HTTP認證調用,然后直接用403響應代碼進行響應。
### 配置
- [v1 API 參考](../../v1APIreference/HTTPfilters/Lua.md)
- [v2 API 參考](../../v2APIreference/Filters/HTTPfilters/Lua.md)
### 腳本示例
本節提供了一些Lua腳本的一些具體的例子,作為一個更簡單介紹和快速入門。有關支持的API的更多詳細信息,請參閱[流處理API](#流處理api)。
```
-- Called on the request path.
function envoy_on_request(request_handle)
-- Wait for the entire request body and add a request header with the body size.
request_handle:headers():add("request_body_size", request_handle:body():length())
end
-- Called on the response path.
function envoy_on_response(response_handle)
-- Wait for the entire response body and a response header with the the body size.
response_handle:headers():add("response_body_size", response_handle:body():length())
-- Remove a response header named 'foo'
response_handle:headers():remove("foo")
end
```
```
function envoy_on_request(request_handle)
-- Make an HTTP call to an upstream host with the following headers, body, and timeout.
local headers, body = request_handle:httpCall(
"lua_cluster",
{
[":method"] = "POST",
[":path"] = "/",
[":authority"] = "lua_cluster"
},
"hello world",
5000)
-- Add information from the HTTP call into the headers that are about to be sent to the next
-- filter in the filter chain.
request_handle:headers():add("upstream_foo", headers["foo"])
request_handle:headers():add("upstream_body_size", #body)
end
```
```
function envoy_on_request(request_handle)
-- Make an HTTP call.
local headers, body = request_handle:httpCall(
"lua_cluster",
{
[":method"] = "POST",
[":path"] = "/",
[":authority"] = "lua_cluster"
},
"hello world",
5000)
-- Response directly and set a header from the HTTP call. No further filter iteration
-- occurs.
request_handle:respond(
{[":status"] = "403",
["upstream_foo"] = headers["foo"]},
"nope")
end
```
### 流處理API
當Envoy在配置中加載腳本時,它會查找腳本中定義的兩個全局函數:
```
function envoy_on_request(request_handle)
end
function envoy_on_response(response_handle)
end
```
一個腳本可以定義這兩個函數中的一個或兩個。在請求路徑中,Envoy將運行`envoy_on_request`函數作為一個協程,傳遞一個API句柄。在響應路徑中,Envoy將運行`envoy_on_response`作為協程,傳遞一個API句柄。
**注意:與Envoy的所有交互,都是通過傳輸流來實現的。流句柄不應該被保存到任何全局變量,不應該在協程之外使用。如果句柄使用不當,Envoy將會失敗。**
支持以下流處理方法:
- **headers()**<br />
```
headers = handle:headers()
```
返回流的頭部對象。只要頭部還沒有被發送到下一個過濾器的頭部鏈中,該頭部就可以被修改。例如,可以在`httpCall()`之后或在`body()`調用返回之后修改它們。如果在任何其他情況下修改了頭部,腳本將會失敗。
返回一個[頭部對象](#頭部對象api)。
- **body()**<br />
```
body = handle:body()
```
返回流的主體(body)。這個調用將使的Envoy切換(yield)腳本,直到整個主體被緩沖。請注意,所有緩沖必須遵守流量控制政策。Envoy不會緩沖超過連接管理器所允許的數據范圍。
返回一個[緩沖對象](#緩存api)。
- **bodyChunks()**<br />
```
iterator = handle:bodyChunks()
```
返回一個迭代器,它可以用來迭代所有接收到的正文數據塊。Envoy將在處理大塊數據時,切換(yield)腳本,但不會緩沖它們。這可以用來檢查數據流。
```
for chunk in request_handle:bodyChunks() do
request_handle:log(0, chunk:length())
end
```
每次迭代器返回都是一個[緩沖對象](#緩存api)。
- **trailers()**<br />
```
trailers = handle:trailers()
```
返回流的尾部。如果沒有尾部,可能會返回零。尾部在發送到下一個過濾器之前可能會被修改。
返回一個[頭標對象](#頭部對象api)。
- **log*()**<br />
```
handle:logTrace(message)
handle:logDebug(message)
handle:logInfo(message)
handle:logWarn(message)
handle:logErr(message)
handle:logCritical(message)
```
使用Envoy的應用程序日志記錄消息。參數`message`是需要記錄的字符串。
- **httpCall()**<br />
```
headers, body = handle:httpCall(cluster, headers, body, timeout)
```
對上游主機進行HTTP調用。Envoy將切換腳本,直到調用完成或有錯誤。`cluster`是對應到群集管理器配置的群集字符串。`headers`是要發送的`key/value`鍵值對的列表。請注意,必須設置`:method`,`:path`和`:authority`頭部。`body`是可選字符串,需要發送的數據主體。`timeout`是一個整數,指定以毫秒為單位的調用超時。
返回是響應的`headers`,以及其`body`字符串。如果沒有主體可能是`null`。
- **respond()**<br />
```
handle:respond(headers, body)
```
立即作出響應,不要進行進一步的過濾器迭代。此調用僅在請求流中有效。此外,只有在請求頭還沒有傳遞給后續過濾器的情況下,響應才是可能的。意思是,下面的Lua代碼是錯誤的:
```
function envoy_on_request(request_handle)
for chunk in request_handle:bodyChunks() do
request_handle:respond(
{[":status"] = "100"},
"nope")
end
end
```
`headers`是要發送的鍵值對的列表。請注意,必須設置`:status`頭部。`body`是一個字符串,作為可選的響應主體,可能是`nil`。
### 頭部對象API
- **add()**<br />
```
headers:add(key, value)
```
為頭部對象添加一個頭部。`key`是提供頭部鍵的字符串。`value`是一個提供頭部值的字符串。
- **get()**<br />
```
headers:get(key)
```
獲取頭部對象頭部值,參數`key`為所對應的頭部鍵。返回一個字符串作為頭部值,如果沒有這樣的頭部則返回`nil`。
- **__pairs()**<br />
```
for key, value in pairs(headers) do
end
```
遍歷每個頭部鍵。返回的`key`是頭部鍵的字符串。返回的`value`是對應的頭部值字符串。
**注意:在當前的實現中,在迭代期間不能修改頭部。 另外,如果需要在迭代之后修改頭部,則必須完成迭代。意味著,不要使用break或其他機制提前退出循環。但這可能會在未來版本中解除這個限制。**
- **remove()**<br />
```
headers:remove(key)
```
刪除頭部鍵值對。入參`key`對應的頭部鍵值將會被刪除。
### 緩存API
- **length()**
```
size = buffer:length()
```
獲取緩沖區的大小(以字節為單位)。返回一個整數。
- **getBytes()**
```
buffer:getBytes(index, length)
```
從緩沖區獲取字節。默認情況下,Envoy不會將所有緩沖區字節復制到Lua中。這將導致一個緩沖區段被復制。`index`是一個整數,并提供要復制的緩沖區起始索引。`length`是一個整數并提供要復制的緩沖區長度。`index`+`length`必須小于緩沖區長度。
## 返回
- [上一級](../HTTPfilters.md)
- [首頁目錄](../../README.md)
- 首頁
- 簡介
- Envoy是什么
- 架構介紹
- 術語
- 線程模型
- 監聽器
- L3/L4網絡過濾器
- HTTP連接管理
- HTTP過濾器
- HTTP路由
- gRPC
- WebSocket支持
- 集群管理
- 服務發現
- 健康檢查
- 連接池
- 負載均衡
- 異常檢測
- 熔斷
- 全局限速
- TLS
- 統計
- 運行時配置
- 跟蹤
- TCP代理
- 訪問日志
- MongoDB
- DynamoDB
- Redis
- 熱重啟
- 動態配置
- 初始化
- 逐出
- 腳本
- 部署
- 業界對比
- 獲得幫助
- 歷史版本
- 編譯安裝
- 編譯
- 參考配置
- 演示沙箱
- 前端代理
- Zipkin跟蹤
- Jaeger跟蹤
- gRPC橋接
- 構建Envoy Docker鏡像
- 工具
- 配置參考
- V1 API 概述
- V2 API 概述
- 監聽器
- 網絡過濾器
- TLS客戶端身份認證
- Echo
- Mongo代理
- 速率限制
- Redis代理
- TCP代理
- HTTP連接管理器
- 路由匹配
- 流量轉移/分流
- HTTP頭部操作
- HTTP頭部清理
- 統計
- 運行時設置
- 路由發現服務
- HTTP過濾器
- 緩存
- CORS過濾器
- 故障注入
- DynamoDB
- gRPC HTTP/1.1 橋接
- gRPC-JSON 轉碼過濾器
- gRPC-Web 過濾器
- 健康檢查
- 速率限制
- 路由
- Lua
- 集群管理
- 統計
- 運行時設置
- 集群發現服務
- 健康檢查
- 熔斷
- 訪問日志
- 限速服務
- 運行時配置
- 路由表檢查工具
- 運維管理
- 命令行選項
- 熱重啟
- 管理接口
- 統計概述
- 運行時配置
- 文件系統
- 自定義擴展示例
- V1 API參考
- 監聽器
- 網絡過濾器
- TLS客戶端身份認證
- Echo
- HTTP連接管理
- Mongo代理
- 速率限制
- Redis代理
- TCP代理
- HTTP路由配置
- 虛擬主機
- 路由
- 虛擬集群
- 速率限制配置
- 路由發現服務
- HTTP過濾器
- 緩存
- CORS過濾器
- DynamoDB
- 故障注入
- gRPC HTTP/1.1 橋接
- gRPC-JSON 轉碼過濾器
- gRPC-Web 過濾器
- 健康檢查
- Lua
- 速率限制
- 路由
- 集群管理
- 集群
- 健康檢查
- 熔斷
- TLS上下文
- 異常值檢測
- HASH環負載均衡配置
- 異常檢測
- 集群發現服務
- 服務發現服務
- 訪問日志
- 管理接口
- 限速服務
- 運行時配置
- 跟蹤
- V2 API參考
- 啟動引導
- 監聽&監聽發現
- 集群&集群發現
- 服務發現
- 健康檢查
- HTTP路由管理&發現
- TLS配置
- 通用的類型
- 網絡地址
- 協議選項
- 發現API
- 限速組件
- 過濾器
- 網絡過濾器
- TLS客戶端身份認證
- HTTP連接管理
- Mongo代理
- 速率限制
- Redis代理
- TCP代理
- HTTP過濾器
- 緩存
- 故障注入
- 健康檢查
- Lua
- 速率限制
- 路由
- gRPC-JSON轉碼器
- 常見訪問日志類型
- 常見故障注入類型
- FAQ
- Envoy有多快?
- 我在哪里獲得二進制文件?
- 我如何設置SNI?
- 如何設置區域感知路由?
- 我如何設置Zipkin跟蹤?