# 语言实现指引

> 本文件包含各语言调用 K3Cloud WebAPI 的实现示例。主 SKILL.md 描述语言无关的 HTTP 协议；需要具体语言代码时按本文件参考。

## Python

### 方式一：官方 SDK（推荐）

```python
from k3cloud_webapi_sdk.main import K3CloudApiSdk

sdk = K3CloudApiSdk(server_url)
sdk.InitConfig(acct_id, user_name, app_id, app_secret, server_url, lcid, org_num)
sdk.GetDataCenters()  # 初始化会话

# 查询
data = {"FormId": "BD_Material", "FieldKeys": "FNumber,FName", "FilterString": "FNumber = '{material_number}'"}
result = json.loads(sdk.ExecuteBillQuery(data))

# 保存
data = {"Model": {...}, "IsDeleteEntry": "True", ...}
result = json.loads(sdk.Save("SAL_SaleOrder", data))
```

**线程安全警告**：`K3CloudApiSdk` 非线程安全（共享 `cookiesStore`/`SID`）。并发场景建议使用单线程 executor 序列化：

```python
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(max_workers=1)

async def call_sdk(method_name, *args):
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(executor, lambda: getattr(sdk, method_name)(*args))
```

### 方式二：requests + Session（无 SDK）

```python
import requests, json

session = requests.Session()

# 登录（Cookie 自动保存）
resp = session.post(
    f"{server_url}Kingdee.BOS.WebApi.ServicesStub.AuthService.LoginByAppSecret.common.kdsvc",
    json=[acct_id, app_id, app_secret, lcid]
)

# 后续请求自动携带 Cookie
resp = session.post(
    f"{server_url}Kingdee.BOS.WebApi.ServicesStub.BusinessDataService.ExecuteBillQuery.common.kdsvc",
    json=[query_data]
)
result = json.loads(resp.text)
```

## C# / .NET

### 方式一：官方 SDK（Kingdee.BOS.WebApi.ClientSDK）

```csharp
using Kingdee.BOS.WebApi.Client;

var client = new K3CloudApiClient(serverUrl);
var loginResult = client.LoginByAppSecret(acctId, appId, appSecret, lcid);

// 查询
var queryResult = client.ExecuteBillQuery(jsonSerializer.Serialize(queryData));
```

### 方式二：HttpClient + CookieContainer（无 SDK）

```csharp
var handler = new HttpClientHandler { CookieContainer = new CookieContainer() };
var client = new HttpClient(handler);

// 登录（Cookie 自动保存到 CookieContainer）
var loginContent = new StringContent(
    JsonConvert.SerializeObject(new object[] { acctId, appId, appSecret, lcid }),
    Encoding.UTF8, "application/json");
await client.PostAsync(
    $"{serverUrl}Kingdee.BOS.WebApi.ServicesStub.AuthService.LoginByAppSecret.common.kdsvc",
    loginContent);

// 后续请求自动携带 Cookie
var queryContent = new StringContent(
    JsonConvert.SerializeObject(new object[] { queryData }),
    Encoding.UTF8, "application/json");
var resp = await client.PostAsync(
    $"{serverUrl}Kingdee.BOS.WebApi.ServicesStub.BusinessDataService.ExecuteBillQuery.common.kdsvc",
    queryContent);
```

## Java / Go / Rust / 其他语言

无官方 SDK 时，用 HTTP 客户端 + Cookie 容器直接调用。核心步骤：

1. 创建带 Cookie 管理的 HTTP 客户端
   - Java: `HttpClient` with `CookieManager`
   - Go: `http.Client` with `cookiejar.New`
   - Rust: `reqwest` with `cookie_store(true)`
2. POST 登录请求 → 会话 Cookie 自动保存
3. POST 业务请求（同一客户端实例，自动携带 Cookie）
4. 解析 JSON 响应

```java
// Java 示例
var cookieManager = new CookieManager();
var client = HttpClient.newBuilder().cookieHandler(cookieManager).build();

// 登录
var loginBody = BodyPublishers.ofString(
    new ObjectMapper().writeValueAsString(new Object[]{acctId, appId, appSecret, lcid}));
client.send(HttpRequest.newBuilder()
    .uri(URI.create(serverUrl + "Kingdee.BOS.WebApi.ServicesStub.AuthService.LoginByAppSecret.common.kdsvc"))
    .header("Content-Type", "application/json")
    .POST(loginBody).build(), BodyHandlers.ofString());

// 查询（Cookie 自动携带）
var queryBody = BodyPublishers.ofString(
    new ObjectMapper().writeValueAsString(new Object[]{queryData}));
var resp = client.send(HttpRequest.newBuilder()
    .uri(URI.create(serverUrl + "Kingdee.BOS.WebApi.ServicesStub.BusinessDataService.ExecuteBillQuery.common.kdsvc"))
    .header("Content-Type", "application/json")
    .POST(queryBody).build(), BodyHandlers.ofString());
```
