From 1e170793b3aabc6652f4598db48a99872d60f854 Mon Sep 17 00:00:00 2001 From: cn-kali-team Date: Wed, 29 Apr 2026 18:57:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E7=A7=9F=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/README.md | 22 +++++++++++++++++- client/README_EN.md | 22 +++++++++++++++++- client/client.go | 54 +++++++++++++++++++++++++++++++++++++++++++++ client/example.go | 7 ++++++ 4 files changed, 103 insertions(+), 2 deletions(-) diff --git a/client/README.md b/client/README.md index e4119aa7..a264a4b5 100644 --- a/client/README.md +++ b/client/README.md @@ -23,7 +23,7 @@ ```go import ( "context" - "github.com/Tencent/WeKnora/internal/client" + "github.com/Tencent/WeKnora/client" "time" ) @@ -35,6 +35,26 @@ apiClient := client.NewClient( ) ``` +### 租户配置 + +客户端支持通过 `WithTenantID` 设置默认租户,请求时会自动携带 `X-Tenant-ID` 请求头: + +```go +tenantID := uint64(10000) +apiClient := client.NewClient( + "http://api.example.com", + client.WithToken("your-auth-token"), + client.WithTenantID(tenantID), +) +``` + +如果某个请求需要临时切换租户,可以在 `context` 中设置 `TenantID`,值可以是 `uint64`、`*uint64` 或字符串形式的数字,客户端会优先使用该值: + +```go +ctx := context.WithValue(context.Background(), "TenantID", uint64(10000)) +// 调用任意客户端方法时传入 ctx,即可切换到租户 10000 +``` + ### 示例:创建知识库并上传文件 ```go diff --git a/client/README_EN.md b/client/README_EN.md index 99ff39dc..a7422d71 100644 --- a/client/README_EN.md +++ b/client/README_EN.md @@ -23,7 +23,7 @@ The client includes the following main functional modules: ```go import ( "context" - "github.com/Tencent/WeKnora/internal/client" + "github.com/Tencent/WeKnora/client" "time" ) @@ -35,6 +35,26 @@ apiClient := client.NewClient( ) ``` +### Tenant Configuration + +You can set a default tenant with `WithTenantID`; the client will automatically send the `X-Tenant-ID` header: + +```go +tenantID := uint64(10000) +apiClient := client.NewClient( + "http://api.example.com", + client.WithToken("your-auth-token"), + client.WithTenantID(tenantID), +) +``` + +If a single request needs a different tenant, set `TenantID` in the request context. The value can be a `uint64`, `*uint64`, or a numeric string, and it will take precedence over the client default: + +```go +ctx := context.WithValue(context.Background(), "TenantID", uint64(10000)) +// Pass ctx into any client method to switch to tenant 10000 for that request +``` + ### Example: Create Knowledge Base and Upload File ```go diff --git a/client/client.go b/client/client.go index c92a2761..3fb3e961 100644 --- a/client/client.go +++ b/client/client.go @@ -10,6 +10,7 @@ import ( "io" "net/http" "net/url" + "strconv" "time" ) @@ -18,6 +19,7 @@ type Client struct { baseURL string httpClient *http.Client token string + tenantID *uint64 } // ClientOption defines client configuration options @@ -37,6 +39,14 @@ func WithToken(token string) ClientOption { } } +// WithTenantID sets the tenant ID that will be included in requests as the X-Tenant-ID header. +// It can be overridden per-request by setting the "TenantID" value in the request context. +func WithTenantID(tenantID uint64) ClientOption { + return func(c *Client) { + c.tenantID = &tenantID + } +} + // NewClient creates a new client instance func NewClient(baseURL string, options ...ClientOption) *Client { client := &Client{ @@ -84,6 +94,50 @@ func (c *Client) doRequest(ctx context.Context, req.Header.Set("X-Request-ID", requestID.(string)) } + // Tenant header: prefer per-request context value, fall back to client-level tenantID + tenantID := c.tenantID + + if ctxTenant := ctx.Value("TenantID"); ctxTenant != nil { + switch v := ctxTenant.(type) { + case *uint64: + if v != nil { + tenantID = v + } + case uint64: + tmp := v + tenantID = &tmp + case string: + if parsed, err := strconv.ParseUint(v, 10, 64); err == nil { + tmp := parsed + tenantID = &tmp + } + } + } + + // 2) Fallback: plain string key "TenantID" (some callers may use this) + if tenantID == nil { + if ctxTenant := ctx.Value("TenantID"); ctxTenant != nil { + switch v := ctxTenant.(type) { + case *uint64: + if v != nil { + tenantID = v + } + case uint64: + tmp := v + tenantID = &tmp + case string: + if parsed, err := strconv.ParseUint(v, 10, 64); err == nil { + tmp := parsed + tenantID = &tmp + } + } + } + } + + if tenantID != nil { + req.Header.Set("X-Tenant-ID", strconv.FormatUint(*tenantID, 10)) + } + return c.httpClient.Do(req) } diff --git a/client/example.go b/client/example.go index ffbf8cd7..fec087d6 100644 --- a/client/example.go +++ b/client/example.go @@ -21,12 +21,19 @@ import ( // - Cleaning up resources func ExampleUsage() { // Create a client instance + tenantID := uint64(10000) // default tenant for all requests from this client apiClient := NewClient( "http://localhost:8080", WithToken("your-auth-token"), WithTimeout(30*time.Second), + WithTenantID(tenantID), // default tenant for all requests from this client ) + // Per-request tenant override example: + // You can override the tenant for a single request by setting the "TenantID" value in the context. + // e.g. ctx := context.WithValue(context.Background(), "TenantID", &tenantID) + // then pass `ctx` to any client method to use tenant 2 for that request only. + // 1. Create a knowledge base fmt.Println("1. Creating knowledge base...") kb := &KnowledgeBase{