Files
higress/.claude/skills/higress-wasm-go-plugin/references/http-client.md

4.4 KiB

HTTP Client Reference

Cluster Types

FQDNCluster (Most Common)

For services registered in Higress with FQDN:

wrapper.NewClusterClient(wrapper.FQDNCluster{
    FQDN: "my-service.dns",      // Service FQDN with suffix
    Port: 8080,
    Host: "optional-host-header", // Optional
})

Common FQDN suffixes:

  • .dns - DNS service
  • .static - Static IP service (port defaults to 80)
  • .nacos - Nacos service

K8sCluster

For Kubernetes services:

wrapper.NewClusterClient(wrapper.K8sCluster{
    ServiceName: "my-service",
    Namespace:   "default",
    Port:        8080,
    Version:     "",    // Optional subset version
})
// Generates: outbound|8080||my-service.default.svc.cluster.local

NacosCluster

For Nacos registry services:

wrapper.NewClusterClient(wrapper.NacosCluster{
    ServiceName: "my-service",
    Group:       "DEFAULT-GROUP",
    NamespaceID: "public",
    Port:        8080,
    IsExtRegistry: false, // true for EDAS/SAE
})

StaticIpCluster

For static IP services:

wrapper.NewClusterClient(wrapper.StaticIpCluster{
    ServiceName: "my-service",
    Port:        8080,
})
// Generates: outbound|8080||my-service.static

DnsCluster

For DNS-resolved services:

wrapper.NewClusterClient(wrapper.DnsCluster{
    ServiceName: "my-service",
    Domain:      "api.example.com",
    Port:        443,
})

RouteCluster

Use current route's upstream:

wrapper.NewClusterClient(wrapper.RouteCluster{
    Host: "optional-host-override",
})

TargetCluster

Direct cluster name specification:

wrapper.NewClusterClient(wrapper.TargetCluster{
    Cluster: "outbound|8080||my-service.dns",
    Host:    "api.example.com",
})

HTTP Methods

client.Get(path, headers, callback, timeout...)
client.Post(path, headers, body, callback, timeout...)
client.Put(path, headers, body, callback, timeout...)
client.Patch(path, headers, body, callback, timeout...)
client.Delete(path, headers, body, callback, timeout...)
client.Head(path, headers, callback, timeout...)
client.Options(path, headers, callback, timeout...)
client.Call(method, path, headers, body, callback, timeout...)

Callback Signature

func(statusCode int, responseHeaders http.Header, responseBody []byte)

Complete Example

type MyConfig struct {
    client      wrapper.HttpClient
    requestPath string
    tokenHeader string
}

func parseConfig(json gjson.Result, config *MyConfig) error {
    config.tokenHeader = json.Get("tokenHeader").String()
    if config.tokenHeader == "" {
        return errors.New("missing tokenHeader")
    }
    
    config.requestPath = json.Get("requestPath").String()
    if config.requestPath == "" {
        return errors.New("missing requestPath")
    }
    
    serviceName := json.Get("serviceName").String()
    servicePort := json.Get("servicePort").Int()
    if servicePort == 0 {
        if strings.HasSuffix(serviceName, ".static") {
            servicePort = 80
        }
    }
    
    config.client = wrapper.NewClusterClient(wrapper.FQDNCluster{
        FQDN: serviceName,
        Port: servicePort,
    })
    return nil
}

func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig) types.Action {
    err := config.client.Get(config.requestPath, nil,
        func(statusCode int, responseHeaders http.Header, responseBody []byte) {
            if statusCode != http.StatusOK {
                log.Errorf("http call failed, status: %d", statusCode)
                proxywasm.SendHttpResponse(http.StatusInternalServerError, nil,
                    []byte("http call failed"), -1)
                return
            }
            
            token := responseHeaders.Get(config.tokenHeader)
            if token != "" {
                proxywasm.AddHttpRequestHeader(config.tokenHeader, token)
            }
            proxywasm.ResumeHttpRequest()
        })

    if err != nil {
        log.Errorf("http call dispatch failed: %v", err)
        return types.HeaderContinue
    }
    return types.HeaderStopAllIterationAndWatermark
}

Important Notes

  1. Cannot use net/http - Must use wrapper's HTTP client
  2. Default timeout is 500ms - Pass explicit timeout for longer calls
  3. Callback is async - Must return HeaderStopAllIterationAndWatermark and call ResumeHttpRequest() in callback
  4. Error handling - If dispatch fails, return HeaderContinue to avoid blocking