部署在Azure App Service的ASP.NET Core双向流式gRPC调用失败
双向流式gRPC在Azure App Service中5秒后中断的解决方案
问题根源
你的问题核心是Azure App Service的网关/容器空闲超时限制,加上代码未处理连接取消信号,导致流式连接被强制断开后服务端报错。本地测试正常是因为没有云环境的反向代理超时约束。
解决步骤
1. 调整Azure App Service的超时配置
Azure App Service针对容器部署的默认空闲超时为5秒,这会直接断开长时间无数据的流式连接。在Azure Portal中修改以下应用设置:
- 进入App Service → 配置 → 应用程序设置
- 添加/更新:
WEBSITES_CONTAINER_START_TIME_LIMIT:设为1800(30分钟,避免启动超时)WEBSITES_PORT:明确设置为你的应用监听端口(如8080)ARR_IDLE_TIMEOUT:设为1200(20分钟,调整反向代理空闲超时)
2. 修正gRPC服务代码
你的代码未监听连接取消令牌,也没有心跳机制保持连接。修改代码如下:
public override async Task StreamCommands(IAsyncStreamReader<State> requestStream, IServerStreamWriter<Command> responseStream, ServerCallContext context) { try { // 绑定取消令牌,连接断开时会触发OperationCanceledException await foreach (var message in requestStream.ReadAllAsync(context.CancellationToken)) { _logger.LogInformation("Client sent state {}", message); // 定期发送心跳消息,避免网关因空闲断开连接 await responseStream.WriteAsync(new Command { /* 填充心跳字段,比如IsHeartbeat = true */ }, context.CancellationToken); } } catch (OperationCanceledException) { _logger.LogInformation("Stream connection closed normally"); } catch (Exception ex) { _logger.LogError(ex, "Stream processing failed"); throw; } }
3. 确认Easy Auth排除规则
即使你已排除gRPC路径,仍需验证规则准确性:
- 在App Service → 认证 → 认证设置中,确保「排除路径」包含gRPC服务的完整路径(如
/YourGrpcServiceName/StreamCommands),路径区分大小写,需与proto定义完全匹配 - 检查是否有其他ASP.NET Core认证中间件意外拦截gRPC请求
4. 优化Kestrel HTTP/2配置
在Program.cs中配置Kestrel以支持长连接和多路复用:
builder.WebHost.ConfigureKestrel(options => { options.ListenAnyIP(8080, listenOptions => { listenOptions.Protocols = HttpProtocols.Http1AndHttp2; // 调整HTTP/2参数以适配流式传输 listenOptions.Http2.MaxStreamsPerConnection = 100; listenOptions.Http2.InitialStreamWindowSize = 64 * 1024; }); });
5. 检查App Service SKU层级
Free/Shared层级不支持HTTP/2长连接和流式传输,必须使用Basic及以上层级的App Service。
验证
部署修改后的代码和配置后,用gRPC客户端发起流式调用,观察连接是否能稳定保持;同时查看App Service日志,确认无转发超时错误。
内容的提问来源于stack exchange,提问作者Robert Schmid
相关产品推荐
相关产品推荐

