如何在.Net Core中启用nginx反向代理与gRPC配合使用?

2023-12-27

我遇到了一个问题,无法让 nginx 与 gRPC 一起正常工作。我正在使用 .Net core 3.1 来提供支持 REST 和 gRPC 的 API。

我正在使用下面的 docker 镜像:

  • .Net Core 3.1(aspnet:3.1-alpine)
  • Nginx(nginx:最新)

客户端在本地运行,因为我只是通过 nginx 连接到 docker 容器(端口 8080 和 443 映射到主机)

我已经在 docker 容器中构建了 API 映像,并使用 docker compose 来启动一切。

当涉及到 gRPC 时,我的 API 相当简单:

app.UseEndpoints(endpoints =>
{
   endpoints.MapGrpcService<CartService>();
   endpoints.MapControllers();
});

我在 API 前面使用 nginx 作为反向代理,下面是我的 nginx 配置。但 rpc 调用不起作用。我无法通过客户端连接到 gRPC 服务,它返回 502 请求。 我得到了2020/06/29 18:33:30 [error] 27#27: *3 upstream sent too large http2 frame: 4740180 while reading response header from upstream, client: 172.20.0.1.罢工>。添加单独的 kestral 端点后(请参阅下面的 Edit1),我收到*1 upstream prematurely closed connection while reading response header from upstream当我查看 Nginx 日志时。

服务器甚至从未收到实际的请求,因为当我查看 Docker 日志时,服务器端没有记录任何内容。

关于如何通过 .Net 上的 docker 支持 gRPC 的文档很少甚至没有,因此不确定如何继续。为了使其正常工作,除了我必须做的之外,还需要配置/启用什么?请注意,API 的 REST 部分工作正常,没有任何问题。不确定 SSL 是否需要一直传送到上游服务器(即 API 级别的 SSL)。

我在 Nginx for gRPC 上看到的文档与我下面的内容完全相同。 http_v2_module 在 Nginx 中启用,我可以通过响应协议验证它是否适用于 API 的非 gRPC 部分。

http {
    upstream api {
        server apiserver:5001;
    }
    upstream function {
        server funcserver:5002;
    }

    # redirect all http requests to https
    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        return 301 https://$host$request_uri;
    }
    server {
        server_name api.localhost;
        listen 443 http2 ssl ipv6only=on;
        ssl_certificate /etc/certs/api.crt;
        ssl_certificate_key /etc/certs/api.key;
        location /CartCheckoutService/ValidateCartCheckout {
            grpc_pass grpc://api;
            proxy_buffer_size          512k;
            proxy_buffers              4 256k;
            proxy_busy_buffers_size    512k;
            grpc_set_header Upgrade $http_upgrade;
            grpc_set_header Connection "Upgrade";
            grpc_set_header Connection keep-alive;
            grpc_set_header Host $host:$server_port;
            grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            grpc_set_header X-Forwarded-Proto $scheme;
        }
        location / {
            proxy_pass http://api;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Connection keep-alive;
            proxy_set_header Host $host:$server_port;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_cache_bypass $http_upgrade;
        }
    }
    server {
        server_name func.localhost;
        listen 443 ssl;
        ssl_certificate /etc/certs/func.crt;
        ssl_certificate_key /etc/certs/func.key;
        location / {
            proxy_pass http://function;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection keep-alive;
            proxy_set_header Host $host:$server_port;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_cache_bypass $http_upgrade;
        }
    }
    gzip on;
    gzip_vary on;
    gzip_proxied no-cache no-store private expired auth;
    gzip_types text/plain text/css application/json application/xml;
}

Edit1:我还尝试为 REST/gRPC 启动单独的端点。由此根据文档,当不安全的请求进来时,它会自动假定为 Http1 请求。我手动将 kestrel 配置为具有 2 个独立的端点、两个端口 - 一个用于 http1+http2,另一个用于 http2 请求。

services.Configure<KestrelServerOptions>(y =>
{
    y.ListenAnyIP(5010, o =>
    {
        o.Protocols = HttpProtocols.Http2;
        //o.UseHttps("./certs/backend.pfx", "password1");
    });

    y.ListenAnyIP(5001, o =>
    {
        o.Protocols = HttpProtocols.Http1AndHttp2;
    });
 });

在 Nginx 中,我还创建了一个单独的条目:

upstream api {
        server apiserver:5001;
    }
    upstream grpcservice {
        server apiserver:5010;
    }
    upstream function {
        server funcserver:5002;
    }

这也行不通。我什至尝试通过使 htt2 端点仅接受 ssl 连接而不接受骰子来尝试上游 SSL。


Edit2

我也尝试过以下:

  • Nginx 中的上游 SSL - 即后端和反向代理之间的 SSL
  • 使用基于 Debian/Ubuntu 的镜像而不是 Alpine

它们都不起作用。


Edit 3:我终于能够完成这项工作:

location /CartCheckoutService/ValidateCartCheckout {
                grpc_pass grpc://api;
            }

无论出于何种原因,nginx 唯一有效的配置是使用grpc_pass仅有的。它与代理通行证不同,并且不需要其他配置。我终于能够让它工作,而无需执行上游 SSL,只需使用代理,就像我的意思一样 - 在代理处终止 SSL。

我仍在寻找正式的解释,否则我会将我自己的解决方案标记为答案,因为我已经成功测试了它。


以下是有效的解决方案:

location /CartCheckoutService/ValidateCartCheckout {
                grpc_pass grpc://api;
            }

使用 grpc 时唯一有效的 nginx 配置是使用grpc_pass仅有的。它与代理传递不同,不需要其他配置(即从请求传递标头/协议/等)。我终于能够让它工作,而无需执行上游 SSL,只需使用代理,就像我的意思一样 - 在代理处终止 SSL。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在.Net Core中启用nginx反向代理与gRPC配合使用? 的相关文章

随机推荐

  • Spark:测试 RDD 是否为空的有效方法

    没有一个isEmptyRDD 上的方法 那么测试 RDD 是否为空的最有效方法是什么 RDD isEmpty https issues apache org jira browse SPARK 5270将成为 Spark 1 3 0 的一部
  • 与PHP在同一页面显示结果

    我基本上是从 PHP 开始学习的 我想做的事情很简单 我想在同一页面显示计算结果 这是项目的结构 https i stack imgur com XGPVr png Code 索引 php header php
  • WAMP、Laravel 5:路由不起作用 - NotFoundHttpException

    我在本地计算机上使用 Laravel 5 和 WAMP 没有虚拟化 使用 Composer 创建一个名为 LaravelProject 的新项目后 我似乎根本无法让我的路线正常工作 我已经做了什么 Edited httpd conf to
  • 查找:显示模板速度

    我在新的 MVC4 站点上安装了 Mini Profiler 并注意到某些功能的等待时间很长Find DisplayTemplates包括字符串和日期时间 下面是一个例子 在另一个问题中 Sam Saffron 谈到了查找步骤 在随后的运行
  • 理解c++20中的convertible_to概念

    我对 C 20 概念仍然很陌生 我想知道为什么这不起作用 我想创建一个将数字连接为字符串的函数模板 所以我想尝试一些概念 我用了std convertible to检查输入的数据类型 即int在这种情况下 可以转换为std string 但
  • UICollectionView 标题宽度

    在我的 UICollectionViewFlowLayout 子类中 我有这个 self headerReferenceSize CGSizeMake 280 44 但是 标题的显示宽度为 320 这是集合视图的宽度 根据文档 这是正确的
  • 处理 Express 表单中的输入数组?

    假设我必须在同一页面上编辑一批相同类型的对象 jade form action method POST for each message id in messages ids input type text name message id
  • 如何删除Android searchview左侧的空间(不属于actionbar的一部分)?

    我在 android 应用程序中使用 searchview searchview 不是操作栏的一部分 我想删除搜索图标 搜索视图左侧的空格 我搜索了很多并收到了适用于作为操作栏一部分的搜索视图的答案 我尝试使用机器人 布局重力 机器人 重力
  • 为什么 const char* const & = "hello" 可以编译?

    我正在阅读一本书中的代码片段并发现 const char const a hello can compile const char a hello cannot 我所知道的是 在初始化引用时 数组到指针的转换不会发生 const char
  • graphstudio 中可用的引脚在代码中不存在

    我正在使用网络摄像头的源过滤器 当我在 graphstudio 中使用过滤器时 它有两个输出引脚 然而 在代码中 对 IEnumPins gt next 的调用始终返回 S FALSE 我还寻找了另一个可以创建引脚的接口 但没有找到这样的东
  • PHP S3上传进度

    这种情况已经发生过很多次了 但我仍然有点困惑 很多答案只关注谈论上传进度条 而不是从 S3 上传获取实际的上传进度 我已经阅读了很多问题并找到了很多软件 但我仍然没有更深入地理解 S3 上传的基本问题 有没有一种方法可以上传到 S3 同时了
  • “TypeError:item.getAttachmentsAsync 不是函数”Outlook 加载项 office-js 与 Vue

    我一直在关注此链接中的教程 https learn microsoft com en us javascript api outlook office messageread view outlook js preview getAttac
  • 如何删除jquery添加的样式属性

    我正在使用具有一些自定义要求的 devExpress 表 更新 休息了一天 然后回去并使用 React Styling 正确完成了它 感谢您的建议 在屏幕截图中 我禁用了某些单元格 但是 用户希望除所选行之外的所有单元格看起来均已禁用 使用
  • 跟随 NavigationLink 并返回后 SwiftUI .toolbar 消失

    我已将 toolbar 添加到 NavigationView 的顶层 最终将用于选择列表中的项目 而无需使用滑动手势 向上按钮 向下按钮等 我还有一个 navigationBar 正在进行 用于访问帐户和设置的其他视图 在大多数情况下 它看
  • D3.js:结合缩放/画笔

    我目前在 Mike Bostock 的工作画笔和缩放 https bl ocks org mbostock 34f08d5e11952a80609169b7917d4172例如 尽管我没有在 svg 上覆盖矩形对象 而是将其附加到我的图表上
  • 在文本文件中求和整数的最快方法

    Question 假设您有一个大型 ASCII 文本文件 每行都有一个随机非负整数 每个整数的范围从 0 到 1 000 000 000 文件中有 100 000 000 行 读取文件并计算所有整数之和的最快方法是什么 限制 我们有 10M
  • 如何通过在最近使用的文本框中单击光标按钮来插入文本?

    我有一个带有多个文本框和一组按钮的表单 使用下面的 Javascript 我可以单击一个按钮并将文本插入到指定的框中之一 单击按钮时是否可以将文本插入到最近 活动的文本框中 目前我有这个 但它使用的是文本框的特定 ID 而不是最近使用 活动
  • 是否可以仅使用免费软件在 C# 中将文档转换为 PDF 或编辑 PDF?

    我有一个愚蠢的想法 即创建一个 docx 或 rtf 或 pdf 格式的模板 然后替换该文档中的文本以生成报告 这似乎是比使用付费报告软件更好的方法 嗯 我相信我现在已经尝试了几乎所有的方法 但我很惊讶用 pdf 做任何事都是不可能的 Tr
  • 可通过 Jetpack Compose 中输入的文本 OutlinedTextField 进行调整

    我有一个 OutlinedTextField 里面有 DropdownMenu 我希望在按下 DropdownMenu 列表内的项目后 该项目的值开始位于 OutlinedTextField 内 并根据文本的长度根据宽度进行调整 我怎样才能
  • 如何在.Net Core中启用nginx反向代理与gRPC配合使用?

    我遇到了一个问题 无法让 nginx 与 gRPC 一起正常工作 我正在使用 Net core 3 1 来提供支持 REST 和 gRPC 的 API 我正在使用下面的 docker 镜像 Net Core 3 1 aspnet 3 1 a