Wasm

在HTTP管道中使用Wasm中间件

WebAssembly是一种安全执行由其他语言编译的代码的方法。运行时会执行WebAssembly模块(Wasm),这些模块通常是带有.wasm扩展名的二进制文件。

Wasm HTTP中间件允许您使用编译为Wasm二进制文件的自定义逻辑来处理传入请求或提供响应。换句话说,您可以使用未预编译到daprd二进制文件中的外部文件来扩展Dapr。Dapr嵌入了wazero以在不使用CGO的情况下实现这一点。

Wasm二进制文件可以从URL加载。例如,使用URL file://rewrite.wasm可以从进程的当前目录加载rewrite.wasm文件。在Kubernetes环境中,您可以参考如何:将Pod卷挂载到Dapr sidecar来配置可以包含Wasm模块的文件系统挂载。也可以从远程URL获取Wasm二进制文件。在这种情况下,URL必须精确指向一个Wasm二进制文件。例如:

  • http://example.com/rewrite.wasm,或
  • https://example.com/rewrite.wasm

组件格式

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: wasm
spec:
  type: middleware.http.wasm
  version: v1
  metadata:
  - name: url
    value: "file://router.wasm"
  - guestConfig
    value: {"environment":"production"}

规范元数据字段

用户至少需要指定一个实现http-handler的Wasm二进制文件。如何编译将在后面描述。

字段 详情 必需 示例
url 包含要实例化的Wasm二进制文件的资源URL。支持的方案包括file://http://https://file:// URL的路径相对于Dapr进程,除非它以/开头。 true file://hello.wasmhttps://example.com/hello.wasm
guestConfig 传递给Wasm来宾的可选配置。用户可以传递由Wasm代码解析的任意字符串。 false environment=production{"environment":"production"}

Dapr配置

要应用中间件,必须在configuration中引用它。请参阅中间件管道

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: appconfig
spec:
  httpPipeline:
    handlers:
    - name: wasm
      type: middleware.http.wasm

注意:WebAssembly中间件使用的资源比本地中间件多。这可能导致资源限制比在本地代码中更快达到。生产环境中应控制最大并发

生成Wasm

此组件允许您使用http-handler应用程序二进制接口(ABI)编译的自定义逻辑来处理传入请求或提供响应。handle_request函数接收传入请求,并可以根据需要对其进行处理或提供响应。

要编译您的Wasm,您需要使用符合http-handler的来宾SDK(如TinyGo)来编译源代码。

以下是TinyGo中的示例:

package main

import (
	"strings"

	"github.com/http-wasm/http-wasm-guest-tinygo/handler"
	"github.com/http-wasm/http-wasm-guest-tinygo/handler/api"
)

func main() {
	handler.HandleRequestFn = handleRequest
}

// handleRequest实现了一个简单的HTTP路由器。
func handleRequest(req api.Request, resp api.Response) (next bool, reqCtx uint32) {
	// 如果URI以/host开头,修剪它并分派到下一个处理程序。
	if uri := req.GetURI(); strings.HasPrefix(uri, "/host") {
		req.SetURI(uri[5:])
		next = true // 继续到主机上的下一个处理程序。
		return
	}

	// 提供静态响应
	resp.Headers().Set("Content-Type", "text/plain")
	resp.Body().WriteString("hello")
	return // 跳过下一个处理程序,因为我们已经写了一个响应。
}

如果使用TinyGo,按如下所示编译,并将名为"url"的规范元数据字段设置为输出的位置(例如,file://router.wasm):

tinygo build -o router.wasm -scheduler=none --no-debug -target=wasi router.go`

Wasm guestConfig 示例

以下是如何使用guestConfig将配置传递给Wasm的示例。在Wasm代码中,您可以使用来宾SDK中定义的函数handler.Host.GetConfig来获取配置。在以下示例中,Wasm中间件从组件中定义的JSON配置中解析执行的environment

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: wasm
spec:
  type: middleware.http.wasm
  version: v1
  metadata:
  - name: url
    value: "file://router.wasm"
  - guestConfig
    value: {"environment":"production"}

以下是TinyGo中的示例:

package main

import (
	"encoding/json"
	"github.com/http-wasm/http-wasm-guest-tinygo/handler"
	"github.com/http-wasm/http-wasm-guest-tinygo/handler/api"
)

type Config struct {
	Environment string `json:"environment"`
}

func main() {
	// 获取配置字节,这是组件中定义的guestConfig的值。
	configBytes := handler.Host.GetConfig()
	
	config := Config{}
	json.Unmarshal(configBytes, &config)
	handler.Host.Log(api.LogLevelInfo, "Config environment: "+config.Environment)
}

相关链接