public static XmlDocument PostXmlTransaction(string url, XmlDocument xmlDoc)
{
if (string.IsNullOrEmpty(url)) throw new ArgumentException("URL 不可為空");
if (xmlDoc == null) throw new ArgumentException("XML 文件不可為空");
// 1. 設定連線池上限 (預設 2,高併發必調大)
ServicePointManager.DefaultConnectionLimit = 200;
ServicePointManager.Expect100Continue = false; // 減少 100-Continue 往返
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
byte[] bytes = Encoding.UTF8.GetBytes(xmlDoc.OuterXml); // 含 XML 宣告
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "text/xml; charset=utf-8"; // 關鍵:明確指定 charset
request.ContentLength = bytes.Length;
request.Timeout = 60000;
request.ReadWriteTimeout = 60000;
request.KeepAlive = false; // 短連線,避免連線池耗盡
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; // 自動解壓回應
request.ProtocolVersion = HttpVersion.Version11;
// 2. 寫入請求串流
using (var reqStream = request.GetRequestStream())
{
reqStream.Write(bytes, 0, bytes.Length);
}
// 3. 取得回應並解析 XML
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode != HttpStatusCode.OK)
throw new HttpRequestException($"HTTP {(int)response.StatusCode}: {response.StatusDescription}");
// 依回應 Header 偵測編碼
Encoding respEncoding = Encoding.UTF8;
string contentType = response.ContentType;
if (!string.IsNullOrEmpty(contentType))
{
var match = Regex.Match(contentType, @"charset\s*=\s*([\w-]+)", RegexOptions.IgnoreCase);
if (match.Success)
{
try { respEncoding = Encoding.GetEncoding(match.Groups[1].Value); }
catch { /* fallback UTF-8 */ }
}
}
using (var respStream = response.GetResponseStream())
using (var reader = new StreamReader(respStream, respEncoding))
using (var xmlReader = XmlReader.Create(reader))
{
var responseDoc = new XmlDocument();
responseDoc.Load(xmlReader);
return responseDoc;
}
}
}
| 原文問題 | 修正做法 |
|---|---|
| Encoding.Unicode/GetBytes 導致亂碼 | 統一使用 Encoding.UTF8,對應 XML `` |
| ContentType 缺少 charset | 設定 text/xml; charset=utf-8 |
| 回應編碼硬編碼 UTF-8 | 解析 `Content-Type` Header `charset` 參數動態決定 |
| 無連線池管理 | 設定 `DefaultConnectionLimit=200`、`KeepAlive=false` |
| 無自動解壓 | `AutomaticDecompression = GZip | Deflate` |
| 資源釋放不完整 | 全程 `using` 區塊,確保 Stream/Response 正確 Dispose |
request.Abort() 強制釋放,否則連線池洩漏。private static readonly HttpClient _client = new HttpClient
{
Timeout = TimeSpan.FromSeconds(60)
};
public async Task PostXmlAsync(string url, XmlDocument xmlDoc)
{
var content = new StringContent(xmlDoc.OuterXml, Encoding.UTF8, "text/xml");
var response = await _client.PostAsync(url, content);
response.EnsureSuccessStatusCode();
string respXml = await response.Content.ReadAsStringAsync();
var doc = new XmlDocument();
doc.LoadXml(respXml);
return doc;
}
HttpClient 內建連線池、自動解壓、非同步、可攜,除非維護 .NET Framework 4.0 以下舊專案,否則優先使用。
原文連結:https://www.bianceng.cn/Programming/csharp/201410/45571.htm