mirror of
https://github.com/alibaba/higress.git
synced 2026-02-06 15:10:54 +08:00
180 lines
4.4 KiB
Markdown
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
|