gpt4 book ai didi

c# - 使用 docker compose 的容器之间的 API 请求连接被拒绝

转载 作者:行者123 更新时间:2023-11-30 17:26:26 25 4
gpt4 key购买 nike

我正在开发一个多容器 Docker 应用程序,我希望一个容器使用 Docker Compose 向其他容器的 API 发出 HTTP 请求。我遇到连接被拒绝的错误。

两个容器都运行 ASP.NET Core 2.2。我使用的 IDE 是 Visual Studio 2017。我正在使用 Postman 测试 API 调用。

我尝试过的事情:
✔️ 端口在 Dockerfiles 中公开
✔️ 端口在 Docker Compose 配置中声明
✔️ 网络在 Docker Compose 中声明,容器连接到它
✔️ Http 请求 URI 使用服务名称而不是 localhost 或本地 IP 地址
✔️ Http 请求 URI 使用容器端口 (80) 而不是主机端口
✔️ 防火墙已禁用
✔️ 带有自定义子网的自定义网络
✔️ 服务的自定义 IPv4 地址
✔️ Docker Compose 降级到 v2.4(以在自定义网络上指定网关)
✔️ 删除并重新创建 serviceB 项目
✔️ 从 HttpClient 的基本用法切换到类型化客户端(自定义服务)
✔️ 从 GetAsync(Uri) 切换到 GetAsync(Uri,HttpCompletionOption,CancellationToken)

Docker 文件

FROM microsoft/dotnet:2.2-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
...

Docker 组合配置:

version: '3.4'

services:
servicea:
...
ports:
- "51841:80"
- "44364:443"
networks:
- local

serviceb:
...
ports:
- "65112:80"
- "44359:443"
networks:
- local

networks:
local:
driver: bridge

serviceA Controller Action :

[Route("[action]")]
[HttpGet]
public IActionResult foo()
{
HttpClient client = _clientFactory.CreateClient();

var result = client.GetAsync("http://serviceb:80/api/bar").Result;
var response = result.Content.ReadAsStringAsync().Result;

return new OkObjectResult(response);
}

如果我使用 Postman 在 http://localhost:51841/api/foo 向 serviceA(主机端口 51841)发出 Http Get 请求,我想获得 serviceB 的 Bar 的响应行动。

但是我收到拒绝连接

原始异常详细信息:

System.Net.Http.HttpRequestException: Connection refused ---> System.Net.Sockets.SocketException: Connection refused
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
at System.Threading.Tasks.ValueTask`1.get_Result()
at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Threading.Tasks.ValueTask`1.get_Result()
at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask`1 creationTask)
at System.Threading.Tasks.ValueTask`1.get_Result()
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)

如果我访问 serviceA 的 bash 并对 serviceB(特别是 serviceB 的 :80 端口)执行 ping 操作:

root@serviceA_id:/app# ping -p 80 serviceb
PATTERN: 0x80
PING serviceb(10.168.0.3) 56(84) bytes of data.
64 bytes from ... (10.168.0.3): icmp_seq=1 ttl=64 time=0.117 ms
64 bytes from ... (10.168.0.3): icmp_seq=2 ttl=64 time=0.101 ms
64 bytes from ... (10.168.0.3): icmp_seq=3 ttl=64 time=0.083 ms
--- serviceb ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2057ms rtt min/avg/max/mdev = 0.083/0.100/0.117/0.016 ms

curl

我还可以使用 CURL 与 API REST 端点建立连接,但收到的 Content-Length 为 0

root@serviceA_id:/app# curl -v http://serviceb/api/bar
* Trying 10.168.0.3...
* TCP_NODELAY set
* Connected to serviceb (10.168.0.3) port 80 (#0)
> GET /api/bar/ HTTP/1.1
> Host: serviceb
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 307 Temporary Redirect
< Date: Mon, 17 Jun 2019 07:11:31 GMT
< Server: Kestrel
< Content-Length: 0
< Location: https://serviceb:44359/api/bar/
<
* Curl_http_done: called premature == 0
* Connection #0 to host serviceb left intact

所以我们可以看到 serviceB 告诉 serviceA 它的请求将被重定向到 https://serviceb:44359/api/bar/ 但所需的连接端口是 80(容器端口),而不是44359(主机端口)

如果我让 curl 跟随重定向,则会出现 Connection Refused(重定向的端口已关闭)

root@serviceA_id:/app# curl -v -L http://serviceb/api/bar
* Trying 10.168.0.3...
* TCP_NODELAY set
* Connected to serviceb (10.168.0.3) port 80 (#0)
> GET /api/bar HTTP/1.1
> Host: serviceb
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 307 Temporary Redirect
< Date: Wed, 19 Jun 2019 08:48:33 GMT
< Server: Kestrel
< Content-Length: 0
< Location: https://serviceb:44359/api/bar
<
* Curl_http_done: called premature == 0
* Connection #0 to host serviceb left intact
* Issue another request to this URL: 'https://serviceb:44359/api/bar'
* Trying 10.168.0.3...
* TCP_NODELAY set
* connect to 10.168.0.3 port 44359 failed: Connection refused
* Failed to connect to serviceb port 44359: Connection refused
* Closing connection 1
curl: (7) Failed to connect to serviceb port 44359: Connection refused

为什么我被重定向到主机端口?

Startup.cs 中,我的服务正在使用 app.UseHttpsRedirection(); 因此删除该行解决了问题

如果我仍然需要使用 HTTPS 怎么办?添加选项以使用容器端口。更多信息在回答中

最佳答案

ServiceA 的 HTTP 请求被重定向(HTTP 307 状态代码)到 https://serviceb:44359/api/bar:44359 HTTPS 的主机端口。容器之间无法访问主机端口,但容器端口可以。因此,如果我访问 serviceA 的终端并发送一个带有 curl 详细 -v 的 HTTP 请求,然后将 -L 重定向到 URI http://serviceb/api/bar 我收到拒绝连接错误:

root@serviceA_id:/app# curl -v -L http://serviceb/api/bar
* Trying 10.168.0.3...
* TCP_NODELAY set
* Connected to serviceb (10.168.0.3) port 80 (#0)
> GET /api/bar HTTP/1.1
> Host: serviceb
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 307 Temporary Redirect
< Date: Wed, 19 Jun 2019 08:48:33 GMT
< Server: Kestrel
< Content-Length: 0
< Location: https://serviceb:44359/api/bar
<
* Curl_http_done: called premature == 0
* Connection #0 to host serviceb left intact
* Issue another request to this URL: 'https://serviceb:44359/api/bar'
* Trying 10.168.0.3...
* TCP_NODELAY set
* connect to 10.168.0.3 port 44359 failed: Connection refused
* Failed to connect to serviceb port 44359: Connection refused
* Closing connection 1
curl: (7) Failed to connect to serviceb port 44359: Connection refused

为什么我被重定向到主机端口?

Startup.cs 中,我的服务正在使用 app.UseHttpsRedirection();,那条线导致了问题。

HttpsPolicyBuilderExtensions.UseHttpsRedirection(IApplicationBuilder) method的默认配置默认重定向到 HTTPS 主机端口。如果您想使用不同的端口进行重定向,您需要添加该选项,这样 Startup.cs 将如下所示:

public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{

...

services.AddHttpsRedirection(options =>
{
options.HttpsPort = 443;
});

...

}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{

...

app.UseHttpsRedirection();

...

}
}

关于c# - 使用 docker compose 的容器之间的 API 请求连接被拒绝,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56562956/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com