國(guó)內(nèi)做網(wǎng)站建設(shè)知名的公司品牌推廣的步驟和技巧
Java程序員學(xué)習(xí)Go開(kāi)發(fā)Higress的WASM插件
契機(jī)
? 今年天池大賽有higress相關(guān)挑戰(zhàn),研究一下。之前沒(méi)搞過(guò)go,踩了很多坑,最主要的就是tinygo打包,多方尋求解決無(wú)果,結(jié)論是tinygo@0.32+go@1.19無(wú)法在macos arm架構(gòu)下打包。升級(jí)go@1.21再次打包提示unsafe.SliceData requires go1.20 or later。后放棄macos+arm,采用ubuntu+amd64打包,ubuntu打包也必須使用tinygo@0.28.1。0.32.0在ubuntu仍然提示unsupported GOOS/GOARCH pair wasip1/wasm
環(huán)境布置
- 包安裝等可能需要依賴魔法,實(shí)在不行再配置代理倉(cāng)庫(kù)吧
- 下載GoLand
- 使用GoLand拷貝代碼https://github.com/alibaba/higress
- 定位到higress/plugins/wasm-go/extensions目錄
- 安裝Golang1.19,推薦直接在IDE中安裝
- 訪問(wèn)這個(gè)地方https://go.dev/dl/找安裝包
- macos下載好的安裝文件直接安裝,默認(rèn)會(huì)安裝到
/usr/local/go
目錄
- TinyGo(要求 0.28.1 版本以上)安裝
- 官方指引鏈接:https://tinygo.org/getting-started/install/
- macos直接brew install
- brew tap tinygo-org/tools
- brew install tinygo
- 報(bào)錯(cuò)You are using macOS 15…(剛升級(jí)15系統(tǒng)
- 下載安裝https://tinygo.org/getting-started/install/macos/
- tar xvzf tinygo0.32.0.darwin-amd64.tar.gz
- 添加環(huán)境變量
- vim ~/.bash_profile
- 添加一行
export PATH=<extract location>/tinygo/bin:$PATH
- source ~/.bash_profile
官方Demo
- 用GoLand打開(kāi)higress,找到/plugins/wasm-go/extensions/hello-world
- 使用master分支
- 當(dāng)前24年6月25日19點(diǎn),我使用的Revision版本:ef4a0243aceb59ad0e630c40683c429a4f1198a0
- 參考https://higress.io/zh-cn/docs/user/wasm-go/#2-編寫(xiě)-maingo-文件,把hello-world改造下順便學(xué)習(xí)下語(yǔ)法
package mainimport ("github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper""github.com/higress-group/proxy-wasm-go-sdk/proxywasm""github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types""github.com/tidwall/gjson"
)func main() {wrapper.SetCtx(// 插件名稱"hello-world",// 為解析插件配置,設(shè)置自定義函數(shù)wrapper.ParseConfigBy(parseConfig),// 為處理請(qǐng)求頭,設(shè)置自定義函數(shù)wrapper.ProcessRequestHeadersBy(onHttpRequestHeaders),)
}// MyConfig /*
type MyConfig struct {mockEnable bool
}/*
在控制臺(tái)插件配置中填寫(xiě)的yaml配置會(huì)自動(dòng)轉(zhuǎn)換為json,此處直接從json這個(gè)參數(shù)里解析配置即可
@note:- 星號(hào)表示指針- 傳遞一個(gè)指針給函數(shù)時(shí),函數(shù)可以直接修改指針?biāo)赶虻淖兞康闹?*/
func parseConfig(json gjson.Result, config *MyConfig, log wrapper.Log) error {// 解析出配置,更新到config中config.mockEnable = json.Get("mockEnable").Bool()log.Info("yml配置此時(shí)為:" + json.Raw)return nil
}/*
HTTP 請(qǐng)求頭處理階段,網(wǎng)關(guān)接收到客戶端發(fā)送來(lái)的請(qǐng)求頭數(shù)據(jù)時(shí),觸發(fā)wrapper.ProcessRequestHeadersBy
@note- 沒(méi)有星號(hào),表示副本,對(duì)副本的任意修改都不會(huì)影響到原來(lái)的變臉
*/
func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig, log wrapper.Log) types.Action {log.Info("開(kāi)始攔截header")//proxywasm工具類(lèi)直接增加headererr := proxywasm.AddHttpRequestHeader("hello", "world")if err != nil {return 0}//如果配置為的true,直接返回hello-worldif config.mockEnable {//proxywasm工具類(lèi)直接攔截返回responseerr := proxywasm.SendHttpResponse(200, nil, []byte("hello world"), -1)if err != nil {return 0}}return types.ActionContinue
}
在GoLand中,直接在方法中使用json gjson,會(huì)自動(dòng)在go.mod和main.go的require中增加相關(guān)的依賴
higress插件可以實(shí)現(xiàn)的4個(gè)鉤子:
- HTTP 請(qǐng)求頭處理階段:wrapper.ProcessRequestHeadersBy
- HTTP 請(qǐng)求 Body 處理階段:wrapper.ProcessRequestBodyBy
- HTTP 應(yīng)答頭處理階段:wrapper.ProcessResponseHeadersBy
- HTTP 應(yīng)答 Body 處理階段:wrapper.ProcessResponseBodyBy
proxywasm工具類(lèi)可以實(shí)現(xiàn)的方法如下
分類(lèi) | 方法名稱 | 用途 | 可以生效的HTTP 處理階段 |
---|---|---|---|
請(qǐng)求頭處理 | GetHttpRequestHeaders | 獲取客戶端請(qǐng)求的全部請(qǐng)求頭 | HTTP 請(qǐng)求頭處理階段 |
ReplaceHttpRequestHeaders | 替換客戶端請(qǐng)求的全部請(qǐng)求頭 | HTTP 請(qǐng)求頭處理階段 | |
GetHttpRequestHeader | 獲取客戶端請(qǐng)求的指定請(qǐng)求頭 | HTTP 請(qǐng)求頭處理階段 | |
RemoveHttpRequestHeader | 移除客戶端請(qǐng)求的指定請(qǐng)求頭 | HTTP 請(qǐng)求頭處理階段 | |
ReplaceHttpRequestHeader | 替換客戶端請(qǐng)求的指定請(qǐng)求頭 | HTTP 請(qǐng)求頭處理階段 | |
AddHttpRequestHeader | 新增一個(gè)客戶端請(qǐng)求頭 | HTTP 請(qǐng)求頭處理階段 | |
請(qǐng)求 Body 處理 | GetHttpRequestBody | 獲取客戶端請(qǐng)求 Body | HTTP 請(qǐng)求 Body 處理階段 |
AppendHttpRequestBody | 將指定的字節(jié)串附加到客戶端請(qǐng)求 Body 末尾 | HTTP 請(qǐng)求 Body 處理階段 | |
PrependHttpRequestBody | 將指定的字節(jié)串附加到客戶端請(qǐng)求 Body 的開(kāi)頭 | HTTP 請(qǐng)求 Body 處理階段 | |
ReplaceHttpRequestBody | 替換客戶端請(qǐng)求 Body | HTTP 請(qǐng)求 Body 處理階段 | |
應(yīng)答頭處理 | GetHttpResponseHeaders | 獲取后端響應(yīng)的全部應(yīng)答頭 | HTTP 應(yīng)答頭處理階段 |
ReplaceHttpResponseHeaders | 替換后端響應(yīng)的全部應(yīng)答頭 | HTTP 應(yīng)答頭處理階段 | |
GetHttpResponseHeader | 獲取后端響應(yīng)的指定應(yīng)答頭 | HTTP 應(yīng)答頭處理階段 | |
RemoveHttpResponseHeader | 移除后端響應(yīng)的指定應(yīng)答頭 | HTTP 應(yīng)答頭處理階段 | |
ReplaceHttpResponseHeader | 替換后端響應(yīng)的指定應(yīng)答頭 | HTTP 應(yīng)答頭處理階段 | |
AddHttpResponseHeader | 新增一個(gè)后端響應(yīng)頭 | HTTP 應(yīng)答頭處理階段 | |
應(yīng)答 Body 處理 | GetHttpResponseBody | 獲取客戶端請(qǐng)求 Body | HTTP 應(yīng)答 Body 處理階段 |
AppendHttpResponseBody | 將指定的字節(jié)串附加到后端響應(yīng) Body 末尾 | HTTP 應(yīng)答 Body 處理階段 | |
PrependHttpResponseBody | 將指定的字節(jié)串附加到后端響應(yīng) Body 的開(kāi)頭 | HTTP 應(yīng)答 Body 處理階段 | |
ReplaceHttpResponseBody | 替換后端響應(yīng) Body | HTTP 應(yīng)答 Body 處理階段 | |
HTTP 調(diào)用 | DispatchHttpCall | 發(fā)送一個(gè) HTTP 請(qǐng)求 | - |
GetHttpCallResponseHeaders | 獲取 DispatchHttpCall 請(qǐng)求響應(yīng)的應(yīng)答頭 | - | |
GetHttpCallResponseBody | 獲取 DispatchHttpCall 請(qǐng)求響應(yīng)的應(yīng)答 Body | - | |
GetHttpCallResponseTrailers | 獲取 DispatchHttpCall 請(qǐng)求響應(yīng)的應(yīng)答 Trailer | - | |
直接響應(yīng) | SendHttpResponse | 直接返回一個(gè)特定的 HTTP 應(yīng)答 | - |
流程恢復(fù) | ResumeHttpRequest | 恢復(fù)先前被暫停的請(qǐng)求處理流程 | - |
ResumeHttpResponse | 恢復(fù)先前被暫停的應(yīng)答處理流程 | - |
編譯生成WASM文件
#整理下代碼依賴啥的
go mod tidy
#進(jìn)入插件目錄
cd /higress/plugins/wasm-go/extensions/hello-world#macos打包
/Users/y/GolandProjects/higress/plugins/wasm-go/extensions/hello-world
tinygo build -o main.wasm -scheduler=none -target=wasi -gc=custom -tags="custommalloc nottinygc_finalizer" ./
#提示異常
go: unsupported GOOS/GOARCH pair wasip1/wasm
#升級(jí)到go version go1.21.10 darwin/arm64
#打包提示:/Users/y/go/go1.21.10/src/strings/builder.go:49:23: unsafe.SliceData requires go1.20 or later
#todo 多方尋求解決無(wú)果,結(jié)論是無(wú)法在macos arm架構(gòu)下打包
#todo tinygo只有31版本后才支持darwin,但是插件打包必須是28.1的tinygo#找了ubuntu打包
#必須是這個(gè)tinygo版本,31版本任然提示go1.21.10
wget https://github.com/tinygo-org/tinygo/releases/download/v0.28.1/tinygo_0.28.1_amd64.deb
sudo dpkg -i tinygo_0.28.1_amd64.deb
wget https://go.dev/dl/go1.19.linux-amd64.tar.gz
tar -xzf go1.19.linux-amd64.tar.gz
#找個(gè)profile放入下面環(huán)境變量source一下
export PATH=/home/go/bin:$PATH#unbuntu初始化工程
mkdir /home/go_project_4_compile
cd /home/go_project_4_compile
go mod init wasm-demo-go
#代碼復(fù)制上去
#整理依賴
go mod tidy
#再打包
tinygo build -o main.wasm -scheduler=none -target=wasi -gc=custom -tags="custommalloc nottinygc_finalizer" ./
#輸出main.wasm,下載到本地
本地調(diào)試
#創(chuàng)建目錄
mkdir ~/higress-plugin-hello
vim docker-compose.yaml
vim envoy.yaml
docker compose up
docker-compose.yaml
version: '3.7'
services:envoy:image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/gateway:v1.4.0-rc.1entrypoint: /usr/local/bin/envoy# 注意這里對(duì)wasm開(kāi)啟了debug級(jí)別日志,正式部署時(shí)則默認(rèn)info級(jí)別command: -c /etc/envoy/envoy.yaml --component-log-level wasm:debugdepends_on:- httpbinnetworks:- wasmtestports:- "10000:10000"volumes:- ./envoy.yaml:/etc/envoy/envoy.yaml- ./main.wasm:/etc/envoy/main.wasmhttpbin:image: kennethreitz/httpbin:latestnetworks:- wasmtestports:- "12345:80"networks:wasmtest: {}
admin:address:socket_address:protocol: TCPaddress: 0.0.0.0port_value: 9901
static_resources:listeners:- name: listener_0address:socket_address:protocol: TCPaddress: 0.0.0.0port_value: 10000filter_chains:- filters:- name: envoy.filters.network.http_connection_managertyped_config:"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManagerscheme_header_transformation:scheme_to_overwrite: httpsstat_prefix: ingress_httproute_config:name: local_routevirtual_hosts:- name: local_servicedomains: ["*"]routes:- match:prefix: "/"route:cluster: httpbinhttp_filters:- name: wasmdemotyped_config:"@type": type.googleapis.com/udpa.type.v1.TypedStructtype_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasmvalue:config:name: wasmdemovm_config:runtime: envoy.wasm.runtime.v8code:local:filename: /etc/envoy/main.wasmconfiguration:"@type": "type.googleapis.com/google.protobuf.StringValue"value: |{"mockEnable": false}- name: envoy.filters.http.routerclusters:- name: httpbinconnect_timeout: 30stype: LOGICAL_DNS# Comment out the following line to test on v6 networksdns_lookup_family: V4_ONLYlb_policy: ROUND_ROBINload_assignment:cluster_name: httpbinendpoints:- lb_endpoints:- endpoint:address:socket_address:address: httpbinport_value: 80
驗(yàn)證
#10000為網(wǎng)關(guān)端口#發(fā)送請(qǐng)求
curl -X GET -d '{"args":{},"headers":{"Accept":"*/*","Hello":"world","Host":"127.0.0.1:10000","Original-Host":"127.0.0.1:10000","Req-Start-Time":"1681269273896","User-Agent":"curl/7.79.1","X-Envoy-Expected-Rq-Timeout-Ms":"15000"},"origin":"172.18.0.3","url":"https://127.0.0.1:10000/get"}' http://127.0.0.1:10000/get 返回
{"args": {},"headers": {"Accept": "*/*","Content-Length": "272","Content-Type": "application/x-www-form-urlencoded","Hello": "world","Host": "127.0.0.1:10000","Original-Host": "127.0.0.1:10000","Req-Start-Time": "1719377044522","User-Agent": "curl/8.7.1","X-Envoy-Expected-Rq-Timeout-Ms": "15000"},"origin": "172.22.0.3","url": "https://127.0.0.1:10000/get"
}#修改本地的envoy.yaml
#將mockEnable配置修改為true#重啟下higress容器
curl -X GET -d '{"args":{},"headers":{"Accept":"*/*","Hello":"world","Host":"127.0.0.1:10000","Original-Host":"127.0.0.1:10000","Req-Start-Time":"1681269273896","User-Agent":"curl/7.79.1","X-Envoy-Expected-Rq-Timeout-Ms":"15000"},"origin":"172.18.0.3","url":"https://127.0.0.1:10000/get"}' http://127.0.0.1:10000/get返回的
hello world#日志也沒(méi)問(wèn)題
[2024-06-26 04:49:29.857][29][info][wasm] [external/envoy/source/extensions/common/wasm/context.cc:1311] wasm log wasmdemo: [hello-world] 開(kāi)始攔截header
[2024-06-26 04:49:18.080][29][info][wasm] [external/envoy/source/extensions/common/wasm/context.cc:1311] wasm log: [hello-world] yml配置此時(shí)為:{"mockEnable": true}
總結(jié)
tinygo@0.32+go@1.19無(wú)法在macos arm架構(gòu)下打包。升級(jí)go@1.21再次打包提示unsafe.SliceData requires go1.20 or later。后放棄macos+arm,采用ubuntu+amd64打包,ubuntu打包也必須使用tinygo@0.28.1。0.32.0在ubuntu仍然提示unsupported GOOS/GOARCH pair wasip1/wasm