从托管在 Azure 中的 Asp.net Core MVC Web App 获取“响应状态代码不表示成功:502(错误网关)”

Posted

技术标签:

【中文标题】从托管在 Azure 中的 Asp.net Core MVC Web App 获取“响应状态代码不表示成功:502(错误网关)”【英文标题】:Getting "Response status code does not indicate success: 502 (Bad Gateway)" from Asp.net Core MVC Web App hosted in Azure 【发布时间】:2020-01-12 08:23:11 【问题描述】:

我有一个基于 Asp.net core MVC (V 1.1.1) 的客户端应用程序和一个基于 Asp.net core (v 2.1) 的 Web API。我都在 Azure 上托管过。

在发出一些请求时,Web 应用程序失败并给出 502 Bad Gateway 响应。

响应状态码不表示成功:502(网关错误)。

指定的 CGI 应用程序遇到错误,服务器终止了进程。

此问题是间歇性的,但是,当请求的处理时间超过 2 分钟时,似乎会发生此问题。我在 Web.config 文件中的客户端和 API 端都将 requestTimeout 设置为 20 分钟,但仍未解决。有时,相同的请求会在更短的时间内得到处理,而我会得到响应。

此外,Httpclient 的 5 分钟超时也已设置,但没有运气。

<aspNetCore requestTimeout="00:20:00"/>

_httpClient.Timeout = new TimeSpan(0, 5, 0);

我已经在本地测试了应用,无法面对这个问题,即使处理时间超过 3 分钟也能得到响应。

如果请求超过 2 分钟,Azure Web 应用似乎不会等待处理请求。但是,天蓝色会话超时指定 230 秒(3.8 分钟),但它仍然没有等待,并且应用程序不会将此情况视为错误并且不记录任何内容。

客户端代码:

public class ApiClientFactory

    private static Uri ApiUrl;
    private static Lazy<ApiClient> restClient = new Lazy<ApiClient>(
        () => new ApiClient(ApiUrl),
        LazyThreadSafetyMode.ExecutionAndPublication);

    static ApiClientFactory()
    
        ApiUrl = new Uri(Convert.ToString(ConfigurationManager.AppSettings["WebAPIUrl"]));
    

    public static ApiClient Instance
    
        get
        
            return restClient.Value;
        
    

public class ApiClient

   private readonly HttpClient _httpClient;
   private readonly Uri BaseEndPointUrl;

   public ApiClient(Uri baseEndPointUrl)
   
       if (baseEndPointUrl == null)
           throw new ArgumentNullException("baseEndPointUrl");

       BaseEndPointUrl = baseEndPointUrl;
       _httpClient = new HttpClient();
       _httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
       _httpClient.Timeout = new TimeSpan(0, 5, 0); //Timeout needed for few modules to get results from db.
   

   private HttpContent CreateHttpContent<T>(T content)
   
       var json = JsonConvert.SerializeObject(content, MicrosoftDateFormatSettings);
       return new StringContent(json, Encoding.UTF8, "application/json");
   

   private static JsonSerializerSettings MicrosoftDateFormatSettings
   
       get
       
           return new JsonSerializerSettings
           
               DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
           ;
       
   

   public async Task<T1> PostAsync<T1, T2>(string url, T2 content, string token)
   
       try
       
           _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
           var response = await _httpClient.PostAsync(url, CreateHttpContent<T2>(content));

           if (response.StatusCode == HttpStatusCode.InternalServerError)
               var exception = await response.Content.ReadAsStringAsync();
               throw new Exception(exception);
           
           response.EnsureSuccessStatusCode();
           var data = await response.Content.ReadAsStringAsync();

           return JsonConvert.DeserializeObject<T1>(data);
       
       catch (Exception ex)throw ex;
   

请协助解决问题。

【问题讨论】:

听起来您的代码中可能存在某种死锁?这可能发生在服务器上吗?通常,502 表示您收到 502 的服务器在尝试与另一台服务器通信时超时。 我不知道死锁,但是当我在本地运行 2 个应用程序时,没有发生上述问题。你的意思是托管客户端和API之间的通信有问题??? 是的。如果我对你的理解正确,你有WebBrowser&lt;---&gt;MVC&lt;---&gt;WebAPI。 502 对我来说意味着“MVC 客户端”在与“Web API”通信时超时,这很可能是网络问题或因为 WebAPI 陷入死锁。 我认为你是对的,似乎它只发生在托管的客户端应用程序中,现在我也在本地进行了测试,即使在 4.7 分钟的等待时间之后也能够接收到响应,但是这种等待在我的服务器中超时猜测。您认为我们需要在 Azure 设置中调整任何内容以应对此时间吗??此外,我确信它不会在 API 中发生,因为我在其中有一个自定义错误处理程序,并且我明确地将 HttpStatusCode 设置为 500 并将错误信息发送到客户端。当我们得到 502 时,它应该来自客户端应用程序。 我不知道,抱歉,我认为您需要将此指向 Azure 论坛。我建议你完成后删除这个问题,我认为它与 SO 无关。 【参考方案1】:

您可以实现一种方法来重试您的请求,或者简单地使用 .Net Polly 来处理此类错误。增加超时设置不是一个好习惯。

方法

    private async Task<bool> PostAsync()//Params you need
    
        HttpStatusCode[] httpStatusCodesWorthRetrying =
        
            HttpStatusCode.RequestTimeout,
            HttpStatusCode.InternalServerError,
            HttpStatusCode.BadGateway,
            HttpStatusCode.ServiceUnavailable,
            HttpStatusCode.GatewayTimeout
        ;

        var maxAttempts = 0;

        while (maxAttempts < 3)
        
            var response =  await _httpClient.PostAsync(requestUrl, CreateHttpContent<T2>(content));
            if (!httpStatusCodesWorthRetrying.Contains(response.StatusCode))
            
                return true;
            

            maxAttempts ++;
            await Task.Delay(300);
        
        return false;
    

波莉

    private async Task PostAsync()//Params you need
    
        HttpStatusCode[] httpStatusCodesWorthRetrying =
        
            HttpStatusCode.RequestTimeout,
            HttpStatusCode.InternalServerError,
            HttpStatusCode.BadGateway,
            HttpStatusCode.ServiceUnavailable,
            HttpStatusCode.GatewayTimeout
        ;


        _retryPolicy = Policy
            .Handle<HttpRequestException>()
            .OrResult<HttpResponseMessage>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
            .WaitAndRetry(4, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

        _retryPolicy.Execute(await _httpClient.PostAsync(requestUrl, CreateHttpContent<T2>(content)));

    

【讨论】:

【参考方案2】:

我们认为可能的原因如下。

    在测试时,两个托管应用程序之间的网络相关问题,同时处理给定 请求并提供响应。在 API 传递响应之前,Web 应用程序 可能会超时。 在 API 客户端类中进行了以下代码更改。 (已发布在问题中)。我不确定 等待 任务和从任务中获得 Result 之间的细微差别。但是在这个变化之后我们不再遇到这个问题,另外也做了一些负载测试,但后来仍然没有遇到。

来自

var response =  await _httpClient.PostAsync(requestUrl, CreateHttpContent<T2>(content));

var response =  _httpClient.PostAsync(requestUrl, CreateHttpContent<T2>(content)).Result;

注意:为 Azure 中的托管域启用分析选项将为我们提供很好的见解来缩小此类问题的范围。

【讨论】:

以上是关于从托管在 Azure 中的 Asp.net Core MVC Web App 获取“响应状态代码不表示成功:502(错误网关)”的主要内容,如果未能解决你的问题,请参考以下文章

从 Azure 中托管的 ASP.NET Core 5.0 MVC 站点调用 API/服务的间歇性套接字异常

在 Chrome 中托管在 Azure 中的 ASP.NET Core Web 应用程序上的异常 HTTP 响应

从 Asp.Net 网站外部访问 Azure Blob 存储

Azure 中托管的 ASP.Net Web API 高响应时间

从 asp.net mvc 网站到 azure 认知搜索的连接问题

ASP.NET Core API - 在 Azure 应用服务上获取 404,但在 Localhost 上工作正常