refactor: SimApiHttpClient 改用 stdx.net.http——不再依赖 soulsoft_net_http
- query<T> 用 stdx.net.http ClientBuilder/HttpRequestBuilder/Client.send (等价 .NET HttpClient,替代 soulsoft_net_http.HttpClient) - TLS 配置用 stdx TlsClientConfig(TrustAll + SNI 域名) - 响应读取:status(UInt16) 2xx 判断 + InputStream 读 body - 去掉 import soulsoft_net_http - 端到端验证:stdx client 请求本机服务读响应正常
This commit is contained in:
@@ -1,20 +1,20 @@
|
|||||||
version = 0
|
version = 0
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
soulsoft_web_http = {version = "1.0.20260528"}
|
|
||||||
soulsoft_web_cors = {version = "1.0.20260528"}
|
|
||||||
soulsoft_extensions_options_configuration = {version = "1.0.20260528"}
|
|
||||||
soulsoft_extensions_logging = {version = "1.0.20260528"}
|
|
||||||
soulsoft_web_routing = {version = "1.0.20260528"}
|
|
||||||
soulsoft_extensions_logging_console = {version = "1.0.20260528"}
|
|
||||||
soulsoft_extensions_hosting = {version = "1.0.20260528"}
|
soulsoft_extensions_hosting = {version = "1.0.20260528"}
|
||||||
soulsoft_extensions_configuration = {version = "1.0.20260528"}
|
soulsoft_web_http = {version = "1.0.20260528"}
|
||||||
soulsoft_extensions_logging_configuration = {version = "1.0.20260528"}
|
soulsoft_extensions_options_configuration = {version = "1.0.20260528"}
|
||||||
|
soulsoft_web_routing = {version = "1.0.20260528"}
|
||||||
soulsoft_web_hosting = {version = "1.0.20260528"}
|
soulsoft_web_hosting = {version = "1.0.20260528"}
|
||||||
soulsoft_extensions_injection = {version = "1.0.20260528"}
|
soulsoft_extensions_logging = {version = "1.0.20260528"}
|
||||||
soulsoft_net_http = {version = "1.0.20260528"}
|
|
||||||
soulsoft_extensions_options = {version = "1.0.20260528"}
|
|
||||||
soulsoft_web_mvc = {version = "1.0.20260528"}
|
soulsoft_web_mvc = {version = "1.0.20260528"}
|
||||||
|
soulsoft_serialization = {version = "1.0.20260528"}
|
||||||
|
soulsoft_net_http = {version = "1.0.20260528"}
|
||||||
|
soulsoft_extensions_logging_console = {version = "1.0.20260528"}
|
||||||
soulsoft_identity_claims = {version = "1.0.20260528"}
|
soulsoft_identity_claims = {version = "1.0.20260528"}
|
||||||
redis = {version = "1.0.20260627"}
|
redis = {version = "1.0.20260627"}
|
||||||
soulsoft_serialization = {version = "1.0.20260528"}
|
soulsoft_extensions_logging_configuration = {version = "1.0.20260528"}
|
||||||
|
soulsoft_extensions_configuration = {version = "1.0.20260528"}
|
||||||
|
soulsoft_extensions_options = {version = "1.0.20260528"}
|
||||||
|
soulsoft_web_cors = {version = "1.0.20260528"}
|
||||||
|
soulsoft_extensions_injection = {version = "1.0.20260528"}
|
||||||
|
|||||||
@@ -7,10 +7,9 @@ package simapi.helpers
|
|||||||
|
|
||||||
import std.collection.*
|
import std.collection.*
|
||||||
import std.io.*
|
import std.io.*
|
||||||
|
import stdx.net.http.*
|
||||||
import stdx.net.tls.*
|
import stdx.net.tls.*
|
||||||
import stdx.net.tls.common.*
|
import stdx.net.tls.common.*
|
||||||
import soulsoft_net_http.{HttpClient, HttpRequestMessage, JsonContent}
|
|
||||||
import soulsoft_net_http.{HttpMethod as NetHttpMethod}
|
|
||||||
import simapi_serialization.*
|
import simapi_serialization.*
|
||||||
import simapi.communications.*
|
import simapi.communications.*
|
||||||
import simapi.configurations.*
|
import simapi.configurations.*
|
||||||
@@ -19,7 +18,7 @@ import simapi.exceptions.*
|
|||||||
/**
|
/**
|
||||||
* HTTP 客户端:用于调用其他带签名/AES 的 SimApi 服务。
|
* HTTP 客户端:用于调用其他带签名/AES 的 SimApi 服务。
|
||||||
* 对齐 C# 的 SimApi.Helpers.SimApiHttpClient:
|
* 对齐 C# 的 SimApi.Helpers.SimApiHttpClient:
|
||||||
* - 内部使用 soulsoft_net_http 的 HttpClient(等价 .NET 的 System.Net.Http.HttpClient)
|
* - 内部使用 stdx.net.http 的 HttpClient(等价 .NET 的 System.Net.Http.HttpClient)
|
||||||
* - 返回泛型 T(反序列化响应 body 的 data 字段),不再返回 String
|
* - 返回泛型 T(反序列化响应 body 的 data 字段),不再返回 String
|
||||||
* @param T 响应 data 的数据类型(任意类,simapi_serialization 反射反序列化)。
|
* @param T 响应 data 的数据类型(任意类,simapi_serialization 反射反序列化)。
|
||||||
*/
|
*/
|
||||||
@@ -112,24 +111,23 @@ public open class SimApiHttpClient {
|
|||||||
* 反序列化使用 simapi_serialization(Deserialize<T> 免约束)。
|
* 反序列化使用 simapi_serialization(Deserialize<T> 免约束)。
|
||||||
*/
|
*/
|
||||||
private func query<T>(url: String, body: String): T {
|
private func query<T>(url: String, body: String): T {
|
||||||
let client = HttpClient.create { builder =>
|
let client = ClientBuilder().
|
||||||
builder.noProxy()
|
noProxy().
|
||||||
// 支持 https:配置 TLS(信任所有证书 + SNI 域名)
|
tlsConfig(buildTlsConfig(url)).
|
||||||
var tls = TlsClientConfig()
|
readTimeout(Duration.second * 30).
|
||||||
tls.verifyMode = CertificateVerifyMode.TrustAll
|
build()
|
||||||
let host = extractHost(url)
|
|
||||||
if (!host.isEmpty()) {
|
|
||||||
tls.serverName = Some(host)
|
|
||||||
}
|
|
||||||
builder.tlsConfig(tls)
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
let request = HttpRequestMessage(NetHttpMethod.Post, url)
|
let request = HttpRequestBuilder().
|
||||||
request.content = JsonContent.create(body)
|
post().
|
||||||
|
url(url).
|
||||||
|
header("Content-Type", "application/json").
|
||||||
|
body(body).
|
||||||
|
build()
|
||||||
let response = client.send(request)
|
let response = client.send(request)
|
||||||
try {
|
try {
|
||||||
SimApiError.errorWhenFalse(response.isSuccessStatusCode, code: response.statusCode, message: "HTTP ERROR: ${response.statusCode}")
|
SimApiError.errorWhenFalse(isSuccess(response.status), code: Int64(response.status),
|
||||||
let json = response.content.readAsString()
|
message: "HTTP ERROR: ${response.status}")
|
||||||
|
let json = readBodyText(response.body)
|
||||||
let result = JsonSerializer.Deserialize<SimApiResponse<T>>(json)
|
let result = JsonSerializer.Deserialize<SimApiResponse<T>>(json)
|
||||||
SimApiError.errorWhen(result.code != 200, code: result.code, message: result.message)
|
SimApiError.errorWhen(result.code != 200, code: result.code, message: result.message)
|
||||||
return result.data.getOrThrow()
|
return result.data.getOrThrow()
|
||||||
@@ -141,6 +139,34 @@ public open class SimApiHttpClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 2xx 视为成功
|
||||||
|
private static func isSuccess(status: UInt16): Bool {
|
||||||
|
status >= 200 && status < 300
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 读取响应体 InputStream 为字符串
|
||||||
|
private static func readBodyText(body: InputStream): String {
|
||||||
|
var buffer = Array<Byte>(4096, repeat: 0)
|
||||||
|
var sb = StringBuilder()
|
||||||
|
var read = body.read(buffer)
|
||||||
|
while (read > 0) {
|
||||||
|
sb.appendFromUtf8(buffer.slice(0, read))
|
||||||
|
read = body.read(buffer)
|
||||||
|
}
|
||||||
|
sb.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 构建 TLS 配置:信任所有证书 + SNI 域名
|
||||||
|
private static func buildTlsConfig(url: String): TlsClientConfig {
|
||||||
|
var tls = TlsClientConfig()
|
||||||
|
tls.verifyMode = CertificateVerifyMode.TrustAll
|
||||||
|
let host = extractHost(url)
|
||||||
|
if (!host.isEmpty()) {
|
||||||
|
tls.serverName = Some(host)
|
||||||
|
}
|
||||||
|
tls
|
||||||
|
}
|
||||||
|
|
||||||
private func aesEncrypt(plain: String): String {
|
private func aesEncrypt(plain: String): String {
|
||||||
// 对齐 C#:SimApiAesUtil.Encrypt(plain, AppKey)(AES-256-CBC + PKCS7,Base64(IV + 密文))
|
// 对齐 C#:SimApiAesUtil.Encrypt(plain, AppKey)(AES-256-CBC + PKCS7,Base64(IV + 密文))
|
||||||
SimApiAesUtil.encrypt(plain, appKey)
|
SimApiAesUtil.encrypt(plain, appKey)
|
||||||
|
|||||||
Reference in New Issue
Block a user