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

180 lines
4.4 KiB
Markdown

# HTTP Client Reference
## Cluster Types
### FQDNCluster (Most Common)
For services registered in Higress with FQDN:
```go
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:
```go
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:
```go
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:
```go
wrapper.NewClusterClient(wrapper.StaticIpCluster{
ServiceName: "my-service",
Port: 8080,
})
// Generates: outbound|8080||my-service.static
```
### DnsCluster
For DNS-resolved services:
```go
wrapper.NewClusterClient(wrapper.DnsCluster{
ServiceName: "my-service",
Domain: "api.example.com",
Port: 443,
})
```
### RouteCluster
Use current route's upstream:
```go
wrapper.NewClusterClient(wrapper.RouteCluster{
Host: "optional-host-override",
})
```
### TargetCluster
Direct cluster name specification:
```go
wrapper.NewClusterClient(wrapper.TargetCluster{
Cluster: "outbound|8080||my-service.dns",
Host: "api.example.com",
})
```
## HTTP Methods
```go
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
```go
func(statusCode int, responseHeaders http.Header, responseBody []byte)
```
## Complete Example
```go
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