Java程序员学习Go开发Higress的WASM插件

news2024/11/25 2:36:30

Java程序员学习Go开发Higress的WASM插件

契机

⚙ 今年天池大赛有higress相关挑战,研究一下。之前没搞过go,踩了很多坑,最主要的就是tinygo打包,多方寻求解决无果,结论是tinygo@0.32+go@1.19无法在macos arm架构下打包。升级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

环境布置

  • 包安装等可能需要依赖魔法,实在不行再配置代理仓库吧
  • 下载GoLand
  • 使用GoLand拷贝代码https://github.com/alibaba/higress
  • 定位到higress/plugins/wasm-go/extensions目录
  • 安装Golang1.19,推荐直接在IDE中安装
    • 访问这个地方https://go.dev/dl/找安装包
    • macos下载好的安装文件直接安装,默认会安装到/usr/local/go目录
  • TinyGo(要求 0.28.1 版本以上)安装
    • 官方指引链接:https://tinygo.org/getting-started/install/
    • macos直接brew install
      • brew tap tinygo-org/tools
      • brew install tinygo
      • 报错You are using macOS 15…(刚升级15系统
    • 下载安装https://tinygo.org/getting-started/install/macos/
      • tar xvzf tinygo0.32.0.darwin-amd64.tar.gz
      • 添加环境变量
        • vim ~/.bash_profile
        • 添加一行export PATH=<extract location>/tinygo/bin:$PATH
        • source ~/.bash_profile

官方Demo

  • 用GoLand打开higress,找到/plugins/wasm-go/extensions/hello-world
  • 使用master分支
  • 当前24年6月25日19点,我使用的Revision版本:ef4a0243aceb59ad0e630c40683c429a4f1198a0
  • 参考https://higress.io/zh-cn/docs/user/wasm-go/#2-编写-maingo-文件,把hello-world改造下顺便学习下语法
package main

import (
	"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",
		// 为解析插件配置,设置自定义函数
		wrapper.ParseConfigBy(parseConfig),
		// 为处理请求头,设置自定义函数
		wrapper.ProcessRequestHeadersBy(onHttpRequestHeaders),
	)
}

// MyConfig /*
type MyConfig struct {
	mockEnable bool
}

/*
在控制台插件配置中填写的yaml配置会自动转换为json,此处直接从json这个参数里解析配置即可
@note:
  - 星号表示指针
  - 传递一个指针给函数时,函数可以直接修改指针所指向的变量的值
*/
func parseConfig(json gjson.Result, config *MyConfig, log wrapper.Log) error {
	// 解析出配置,更新到config中
	config.mockEnable = json.Get("mockEnable").Bool()
	log.Info("yml配置此时为:" + json.Raw)
	return nil
}

/*
HTTP 请求头处理阶段,网关接收到客户端发送来的请求头数据时,触发wrapper.ProcessRequestHeadersBy
@note
  - 没有星号,表示副本,对副本的任意修改都不会影响到原来的变脸
*/
func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig, log wrapper.Log) types.Action {
	log.Info("开始拦截header")
	//proxywasm工具类直接增加header
	err := proxywasm.AddHttpRequestHeader("hello", "world")
	if err != nil {
		return 0
	}
	//如果配置为的true,直接返回hello-world
	if config.mockEnable {
		//proxywasm工具类直接拦截返回response
		err := proxywasm.SendHttpResponse(200, nil, []byte("hello world"), -1)
		if err != nil {
			return 0
		}
	}
	return types.ActionContinue
}

在GoLand中,直接在方法中使用json gjson,会自动在go.mod和main.go的require中增加相关的依赖

higress插件可以实现的4个钩子

  • HTTP 请求头处理阶段:wrapper.ProcessRequestHeadersBy
  • HTTP 请求 Body 处理阶段:wrapper.ProcessRequestBodyBy
  • HTTP 应答头处理阶段:wrapper.ProcessResponseHeadersBy
  • HTTP 应答 Body 处理阶段:wrapper.ProcessResponseBodyBy

proxywasm工具类可以实现的方法如下

分类方法名称用途可以生效的HTTP 处理阶段
请求头处理GetHttpRequestHeaders获取客户端请求的全部请求头HTTP 请求头处理阶段
ReplaceHttpRequestHeaders替换客户端请求的全部请求头HTTP 请求头处理阶段
GetHttpRequestHeader获取客户端请求的指定请求头HTTP 请求头处理阶段
RemoveHttpRequestHeader移除客户端请求的指定请求头HTTP 请求头处理阶段
ReplaceHttpRequestHeader替换客户端请求的指定请求头HTTP 请求头处理阶段
AddHttpRequestHeader新增一个客户端请求头HTTP 请求头处理阶段
请求 Body 处理GetHttpRequestBody获取客户端请求 BodyHTTP 请求 Body 处理阶段
AppendHttpRequestBody将指定的字节串附加到客户端请求 Body 末尾HTTP 请求 Body 处理阶段
PrependHttpRequestBody将指定的字节串附加到客户端请求 Body 的开头HTTP 请求 Body 处理阶段
ReplaceHttpRequestBody替换客户端请求 BodyHTTP 请求 Body 处理阶段
应答头处理GetHttpResponseHeaders获取后端响应的全部应答头HTTP 应答头处理阶段
ReplaceHttpResponseHeaders替换后端响应的全部应答头HTTP 应答头处理阶段
GetHttpResponseHeader获取后端响应的指定应答头HTTP 应答头处理阶段
RemoveHttpResponseHeader移除后端响应的指定应答头HTTP 应答头处理阶段
ReplaceHttpResponseHeader替换后端响应的指定应答头HTTP 应答头处理阶段
AddHttpResponseHeader新增一个后端响应头HTTP 应答头处理阶段
应答 Body 处理GetHttpResponseBody获取客户端请求 BodyHTTP 应答 Body 处理阶段
AppendHttpResponseBody将指定的字节串附加到后端响应 Body 末尾HTTP 应答 Body 处理阶段
PrependHttpResponseBody将指定的字节串附加到后端响应 Body 的开头HTTP 应答 Body 处理阶段
ReplaceHttpResponseBody替换后端响应 BodyHTTP 应答 Body 处理阶段
HTTP 调用DispatchHttpCall发送一个 HTTP 请求-
GetHttpCallResponseHeaders获取 DispatchHttpCall 请求响应的应答头-
GetHttpCallResponseBody获取 DispatchHttpCall 请求响应的应答 Body-
GetHttpCallResponseTrailers获取 DispatchHttpCall 请求响应的应答 Trailer-
直接响应SendHttpResponse直接返回一个特定的 HTTP 应答-
流程恢复ResumeHttpRequest恢复先前被暂停的请求处理流程-
ResumeHttpResponse恢复先前被暂停的应答处理流程-

编译生成WASM文件

#整理下代码依赖啥的
go mod tidy
#进入插件目录
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
#升级到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 多方寻求解决无果,结论是无法在macos arm架构下打包
#todo tinygo只有31版本后才支持darwin,但是插件打包必须是28.1的tinygo

#找了ubuntu打包
#必须是这个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
#找个profile放入下面环境变量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
#代码复制上去
#整理依赖
go mod tidy
#再打包
tinygo build -o main.wasm -scheduler=none -target=wasi -gc=custom -tags="custommalloc nottinygc_finalizer" ./
#输出main.wasm,下载到本地

本地调试

#创建目录
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.1
    entrypoint: /usr/local/bin/envoy
    # 注意这里对wasm开启了debug级别日志,正式部署时则默认info级别
    command: -c /etc/envoy/envoy.yaml --component-log-level wasm:debug
    depends_on:
    - httpbin
    networks:
    - wasmtest
    ports:
    - "10000:10000"
    volumes:
    - ./envoy.yaml:/etc/envoy/envoy.yaml
    - ./main.wasm:/etc/envoy/main.wasm

  httpbin:
    image: kennethreitz/httpbin:latest
    networks:
    - wasmtest
    ports:
    - "12345:80"

networks:
  wasmtest: {}

admin:
  address:
    socket_address:
      protocol: TCP
      address: 0.0.0.0
      port_value: 9901
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          scheme_header_transformation:
            scheme_to_overwrite: https
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: httpbin
          http_filters:
          - name: wasmdemo
            typed_config:
              "@type": type.googleapis.com/udpa.type.v1.TypedStruct
              type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
              value:
                config:
                  name: wasmdemo
                  vm_config:
                    runtime: envoy.wasm.runtime.v8
                    code:
                      local:
                        filename: /etc/envoy/main.wasm
                  configuration:
                    "@type": "type.googleapis.com/google.protobuf.StringValue"
                    value: |
                      {
                        "mockEnable": false
                      }
          - name: envoy.filters.http.router
  clusters:
  - name: httpbin
    connect_timeout: 30s
    type: LOGICAL_DNS
    # Comment out the following line to test on v6 networks
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: httpbin
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: httpbin
                port_value: 80

验证

#10000为网关端口

#发送请求
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

#日志也没问题
[2024-06-26 04:49:29.857][29][info][wasm] [external/envoy/source/extensions/common/wasm/context.cc:1311] wasm log wasmdemo: [hello-world] 开始拦截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配置此时为:{
   "mockEnable": true
 }

总结

tinygo@0.32+go@1.19无法在macos arm架构下打包。升级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

写到最后

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1876318.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一键掌控,文件格式转换无忧!轻松驾驭各种文件格式,高效管理您的数字世界

信息爆炸的时代&#xff0c;我们每天都会接触到各种各样的文件格式。无论是工作文档、图片、视频还是音频文件&#xff0c;它们都以不同的格式存在于我们的电脑和移动设备中。然而&#xff0c;不同的软件和应用往往只支持特定的文件格式&#xff0c;这给我们的工作和生活带来了…

Petal-X :心血管疾病临床风险可视化工具

心血管疾病&#xff08;Cardiovascular diseases, CVDs&#xff09;是全球致死的首要原因&#xff0c;但在大多数情况下&#xff0c;它们是可以通过行为干预来预防的。因此&#xff0c;在个体层面上&#xff0c;有效地传达心血管疾病的风险以及通过风险因素的修改来预计风险降低…

无线WiFi毫米波雷达传感器成品,智能照明人体感应开关,飞睿智能点亮智慧生活

在智能科技飞速发展的今天&#xff0c;我们的生活正被各种智能设备所包围&#xff0c;其中智能照明作为智能家居的重要组成部分&#xff0c;正逐渐改变着我们的生活方式。而在这背后&#xff0c;有一个默默工作的“小助手”——飞睿智能毫米波雷达传感器&#xff0c;它就像智能…

周边美食小程序系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;美食店铺管理&#xff0c;菜品分类管理&#xff0c;标签管理&#xff0c;菜品信息管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;美食店铺&#…

网页用事件监听器播放声音

一、什么是监听器&#xff1a; 在前端页面中&#xff0c;事件监听器&#xff08;Event Listener&#xff09;是一种编程机制&#xff0c;它允许开发者指定当特定事件&#xff08;如用户点击按钮、鼠标悬停、页面加载完成等&#xff09;发生时执行特定的代码块。简而言之&#x…

css 滚动词云

css javascript 实现滚动词云效果 // 163css.js var radius 120; var dtr Math.PI / 180; var d 300; var mcList []; var active false; var lasta 1; var lastb 1; var distr true; var tspeed 10; var size 250; var mouseX 0; var mouseY 0; var howElliptic…

使用面向对象方式编写ROS2节点

1.使用c方式创建节点 在d2lros2/chapt2/chapt2_ws/src/example_cpp/src下新建node_03.cpp&#xff0c;接着输入下面的代码。 #include "rclcpp/rclcpp.hpp" /* 创建一个类节点&#xff0c;名字叫做Node03,继承自Node. */ class Node03 : public rclcpp::Node {…

数据脱敏学习

数据脱敏是一种保护敏感信息的方法&#xff0c;它通过修改或删除数据中的敏感部分&#xff0c;使得数据在保持一定可用性的同时&#xff0c;不再直接关联到个人隐私或重要信息。 自然人指可以直接或间接标识 直接标识&#xff1a;如姓名、身份证号码、家庭住址、电话号码、电…

权威认可 | Smartbi连续5年入选“Gartner增强数据分析代表厂商”

近日&#xff0c;全球权威技术研究与咨询公司Gartner最新发布《2024 年中国数据、分析和人工智能技术成熟度曲线》&#xff0c;Smartbi以其卓越的增强数据分析及自助分析能力&#xff0c;再次入选代表厂商&#xff0c;这也是Smartbi连续5年入选增强数据分析及自助分析代表厂商&…

统计信号处理基础 习题解答11-4

题目 观测到数据&#xff1a;, 假定未知参数A具有先验 PDF 其中&#xff0c;, 是方差为的WGN&#xff0c;且与A独立&#xff0c;求A的MAP估计量。 解答 根据题目条件&#xff0c;得到条件概率&#xff1a; 那么对于N个观察的独立数据&#xff0c;有&#xff1a; 因此&#xf…

云计算 | 期末梳理(下)

1.模运算 2. 拓展欧几里得算法 3.扩散和混淆、攻击的分类 香农的贡献:定义了理论安全性,提出扩散和混淆原则,奠定了密码学的理论基础。扩散:将每一位明文尽可能地散布到多个输出密文中去,以更隐蔽明文数字的统计特性。混淆:使密文的统计特性与明文密钥之间的关系尽量复杂…

Springboot下使用Redis管道(pipeline)进行批量操作

之前有业务场景需要批量插入数据到Redis中&#xff0c;做的过程中也有一些感悟&#xff0c;因此记录下来&#xff0c;以防忘记。下面的内容会涉及到 分别使用for、管道处理批量操作&#xff0c;比较其所花费时间。 分别使用RedisCallback、SessionCallback进行Redis pipeline …

期末考试结束,成绩如何快速发布?

随着期末考试的落幕&#xff0c;老师们又迎来了一项繁琐的任务将成绩单私信给学生家长。这项工作耗时耗力&#xff0c;而且极易出错&#xff0c;期末老师的工作已经足够繁重还要私发成绩&#xff0c;简直是雪上加霜。 好消息是&#xff0c;现在有了易查分小程序&#xff0c;只需…

第5章_Modbus通讯协议

文章目录 5.1 学习Modbus的快速方法5.1.1 寄存器速记5.1.2 协议速记 5.2 初识Modbus5.2.1 背景5.2.2 什么是Modbus&#xff1f;1. Modbus简介2. Modbus特点3. Modbus常用术语4. Modbus事务处理 5.3 Modbus软件与使用5.3.1 Modbus软件简介5.3.2 Modbus Poll&#xff08;主站设备…

c语言中extern定义和引用其他文件的变量,(sublime text)单独一个文件编译不会成功

关键字extern的作用 这个很常见的都知道是定义一个外部变量或函数&#xff0c;但并不是简单的建立两个文件&#xff0c;然后在用extern 定义在另一个非最初定义变量的文件里 区分文件和编译运行的文件 例如&#xff0c;一个文件夹里有文件a.c和文件b.c,在sublime text中直接…

【ES】--Elasticsearch的翻页详解

目录 一、前言二、from+size浅分页1、from+size导致深度分页问题三、scroll深分页1、scroll原理2、scroll可以返回总计数量四、search_after深分页1、search_after避免深度分页问题一、前言 ES的分页常见的主要有三种方式:from+size浅分页、scroll深分页、search_after分页。…

IDM(Internet Download Manager)下载器的安装激活与换机方法 IDM怎么用

很多人都知道 Internet Download Manager(以下简称 IDM)是一款非常优秀的下载提速软件。它功能强大&#xff0c;几乎能下载网页中的所有数据&#xff08;包括视频、音频、图片等&#xff09;&#xff0c;且适用于现在市面上几乎所有的浏览器&#xff0c;非常受大家欢迎。IDM 是…

TensorRt(6)yolov3.weight转换、onnx_graphsurgeon和c++ api实现添加NMS

前面博文 【opencv dnn模块 示例(3) 目标检测 object_detection (2) YOLO object detection】 介绍了 使用opencv dnn模块加载yolo weights格式模型的详细说明。 又在博文 【TensorRt&#xff08;4&#xff09;yolov3加载测试】 说明了如何将onnx编译为tensorrt格式并使用的方式…

墨刀原型--多tab切换显示对应页面场景交互步骤

一般我们画原型页面&#xff0c;PC端或者APP端或小程序端&#xff0c;都会有页面会切换多个tab或状态&#xff0c;同时对应页面显示对应的页面数据。 设计思路如下&#xff1a; 以订单列表页面为例&#xff1a; 可以将订单列表页面分为3部分&#xff0c;固定的头部、状态栏、…

驾校预约小程序系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学员管理&#xff0c;教练管理&#xff0c;驾校信息管理&#xff0c;驾校车辆管理&#xff0c;教练预约管理&#xff0c;考试信息管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;驾校信息&am…