You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Framework 4.8调用API遇WebException问题求助

问题分析与解决方案

核心问题定位

从异常栈和代码来看,导致连接被远程主机强制关闭的原因涉及以下几点:

  • URL配置读取错误,导致请求地址无效
  • URL拼接方式错误,未正确替换模板占位符
  • TLS版本不兼容(第三方API可能要求TLS 1.2+/禁用旧协议)
  • HttpClient频繁创建导致连接池耗尽
  • 同步调用异步方法的潜在死锁风险

分步修复

1. 修正URL配置读取错误

代码中读取的配置项是QueryTransactionUrl,但实际配置的key是GetTransactionUrl,这会导致请求地址为空或错误,先修正配置读取:

private string apiBaseSingleStatusUrl = ConfigurationManager.AppSettings["GetTransactionUrl"];

2. 正确拼接请求URL

原代码直接将TransRef拼接到URL末尾,未替换模板中的{trans_ref}占位符,会生成无效地址,改为占位符替换:

// 替换模板中的占位符,生成正确的API地址
string apiUrl = apiBaseSingleStatusUrl.Replace("{trans_ref}", TransRef);

3. 配置兼容的TLS版本

第三方API通常要求使用TLS 1.2或更高版本,在.NET Framework 4.8中显式启用对应协议:
在服务类的静态构造函数或请求发起前添加:

// 启用TLS 1.2和1.3,根据第三方API要求调整
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;
// 禁用旧协议(可选)
ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11);

4. 优化HttpClient复用

频繁创建HttpClient会导致TCP连接耗尽,应复用静态实例:

public class Service : System.Web.Services.WebService
{
    // 静态HttpClient实例,全局复用
    private static readonly HttpClient _httpClient = new HttpClient();
    private string apiBaseSingleStatusUrl = ConfigurationManager.AppSettings["GetTransactionUrl"];

    static Service()
    {
        // 初始化默认请求头
        _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        // 配置TLS版本
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;
    }

    // ... 其他代码
}

5. 避免同步调用异步方法的死锁风险

原代码使用.Result同步等待异步操作,在ASP.NET环境下可能引发死锁,推荐改为异步WebMethod:

[WebMethod]
public async Task<TransferResponse> TransferStatusService(String TransRef)
{
    TransRef = Server.HtmlEncode(TransRef).AlphaNumeric();
    TransferResponse resp = new TransferResponse();
    try
    {
        string apiUrl = apiBaseSingleStatusUrl.Replace("{trans_ref}", TransRef);
        
        HttpResponseMessage response = await _httpClient.GetAsync(apiUrl);
        if (response.IsSuccessStatusCode)
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            var responseData = JsonConvert.DeserializeObject<ApiTransferResponseDto>(apiResponse);
            
            if (responseData.payload != null && responseData.payload.responseStatus == "SUCCESS")
            {
                // 填充resp的逻辑
                resp.TransRef = responseData.payload.extTnxReference;
                resp.ResponseCode = responseData.payload.responseStatusCode;
                resp.ResponseText = responseData.payload.responseStatusDesc;
                // 其他字段赋值...
            }
            else
            {
                resp.ResponseText = "INVALID";
            }
        }
        else
        {
            resp.ResponseText = $"API Request Failed: {response.StatusCode}";
        }
    }
    catch (Exception ex)
    {
        Logger.WriteLog(ex.ToString()); // 记录完整异常栈而非仅消息
        resp.ResponseCode = "8003";
        resp.ResponseText = "请求处理异常";
        return resp;
    }
    return resp;
}

6. 网络层面排查

  • 用Postman/curl测试API地址是否能正常访问,确认地址、参数、请求头正确性
  • 检查服务器防火墙/代理是否允许出站访问该第三方API域名
  • 确认第三方API是否要求IP白名单、Authorization等额外请求头
  • 查看第三方API文档,确认请求格式是否符合要求

修复后完整代码示例

public class TransferResponse
{
    public string TransRef { get; set; }
    public string TransactionDate { get; set; }
    public string ResponseCode { get; set; }
    public string ResponseText { get; set; }
    public decimal Amount { get; set; }
}

public class ApiTransferResponseDto
{
    public int statusCode { get; set; }
    public Payload payload { get; set; }
    public string message { get; set; }
    public bool hasError { get; set; }
    
    public class Payload
    {
        public string responseStatus { get; set; }
        public string msgId { get; set; }
        public string batch { get; set; }
        public string extTnxReference { get; set; }
        public object isReversed { get; set; }
        public string postingReference { get; set; }
        public string responseStatusDesc { get; set; }
        public string responseStatusCode { get; set; }
    }
}

public class Service : System.Web.Services.WebService
{
    private static readonly HttpClient _httpClient = new HttpClient();
    private string apiBaseSingleStatusUrl = ConfigurationManager.AppSettings["GetTransactionUrl"];

    static Service()
    {
        _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;
        ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11);
    }

    [WebMethod]
    public async Task<TransferResponse> TransferStatusService(string TransRef)
    {
        TransRef = Server.HtmlEncode(TransRef).AlphaNumeric();
        TransferResponse resp = new TransferResponse();
        try
        {
            string apiUrl = apiBaseSingleStatusUrl.Replace("{trans_ref}", TransRef);
            
            HttpResponseMessage response = await _httpClient.GetAsync(apiUrl);
            if (response.IsSuccessStatusCode)
            {
                string apiResponse = await response.Content.ReadAsStringAsync();
                var responseData = JsonConvert.DeserializeObject<ApiTransferResponseDto>(apiResponse);
                
                if (responseData.payload != null && responseData.payload.responseStatus == "SUCCESS")
                {
                    resp.TransRef = responseData.payload.extTnxReference;
                    resp.ResponseCode = responseData.payload.responseStatusCode;
                    resp.ResponseText = responseData.payload.responseStatusDesc;
                    // 补充其他字段赋值逻辑
                }
                else
                {
                    resp.ResponseText = "INVALID";
                }
            }
            else
            {
                resp.ResponseText = $"API请求失败: {response.StatusCode}";
            }
        }
        catch (Exception ex)
        {
            Logger.WriteLog(ex.ToString());
            resp.ResponseCode = "8003";
            resp.ResponseText = "请求处理异常";
            return resp;
        }
        return resp;
    }
}

内容的提问来源于stack exchange,提问作者Ayobamilaye

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 03:50:43