Error: ECONNREFUSED when making a POST request to an API
Error: ECONNREFUSED when making a POST request to an API
我的系统由一个 SPA、一个 Express.js 服务器和一个 ASP NET Core MVC API.
组成
我的服务器使用 Passport.js 以便将 OAuth 与外部提供商一起使用,这样我就可以在我的 SPA 中提供 SSO 选项,除了登录表单。它的工作方式是,在从提供商处获取用户信息后,它通过 POST 请求将此数据发送到 API 以验证用户身份。如果用户选择使用登录表单而不是 SSO 选项之一,它会使用用户的电子邮件和密码直接向 API 发出 POST 请求。
到目前为止,在本地工作我没有遇到任何问题。我被要求将系统容器化,所以我为每个组件创建了一个 Docker 文件,一个 docker-compose.yml 来聚合它们,运行 docker -compose build 和 docker-compose up 没有问题。
现在,运行 容器,如果我选择通过表单登录,我可以毫无问题地使用我的 SPA,但是如果我尝试使用 SSO,我在进行 POST 请求到 API,这很奇怪,因为我的 SPA 服务向同一个地址发出 HTTP 请求没有问题。
webportal.client_1 | Error: connect ECONNREFUSED 127.0.0.1:8443
webportal.client_1 | at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1142:16) {
webportal.client_1 | errno: -111,
webportal.client_1 | code: 'ECONNREFUSED',
webportal.client_1 | syscall: 'connect',
webportal.client_1 | address: '127.0.0.1',
webportal.client_1 | port: 8443,
webportal.client_1 | response: undefined
webportal.client_1 | }
这是我的 Server.ts
import bodyParser from "body-parser";
import express from "express";
import session from "express-session";
import passport from "passport";
import { initialiseAuthentication } from "./auth";
import path from "path";
import http from "http";
require("dotenv").config({
path: __dirname + `/./../.env.${process.env.NODE_ENV}`,
});
const app = express();
const port = process.env.PORT || 5000;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, "/../build")));
app.use(session({ secret: "The big secret" }));
app.get("/ping", (req, res) => {
res.send({ express: "Pong" });
});
app.use(passport.initialize());
initialiseAuthentication(app);
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname + "/../build/index.html"));
});
http.createServer(app).listen(port, '0.0.0.0');
console.log(`Listening on port ${port}`);
我的 Api.ts 服务器发出 HTTP 请求的地方
import request from "superagent";
async function verifyUser(
email: string,
name: string,
provider: string,
providerId: string
) {
return await request
.post(`${process.env.BACKEND_API_URL}/authentication/externalAuth`)
.send({
Email: email,
Name: name,
Provider: provider,
ProviderId: providerId,
})
.then((res) => {
return res;
})
.catch((err) => {
console.error(err);
});
}
async function getUserById(data) {
return await request
.get(`${process.env.BACKEND_API_URL}/user/${data.Id}`)
.auth(data, { type: "bearer" })
.then((res) => {
return res;
})
.catch((err) => {
console.error(err);
});
}
export { verifyUser, getUserById };
我的 AuthenticationService.ts 在 SPA
import request from "superagent";
import Cookies from "js-cookie";
export async function SignIn(email: string, password: string) {
return request
.post(
`${process.env.REACT_APP_API_BACKEND_URL}/authentication/internalAuth`
)
.send({ username: email, password: password });
}
export async function GetUserInfo(userId: number) {
const jwt = Cookies.get("jwt");
return request
.get(`${process.env.REACT_APP_API_BACKEND_URL}/user`)
.query({ id: userId })
.auth(jwt as string, { type: "bearer" })
.then((res) => {
return res.body;
})
.catch((err) => console.error(err));
}
如果有人能够为我澄清这个问题并可能解决它,我将不胜感激。谢谢。
编辑 1: 请求都在 HTTPS 中,是的,我启用了 CORS 允许一切。
编辑 2: 添加了 Docker-Compose 和 Docker 文件。
Docker-撰写
version: "3"
services:
db:
image: "mcr.microsoft.com/mssql/server"
ports:
- "1433:1433"
environment:
SA_PASSWORD: "VeryStrongPassword1234"
ACCEPT_EULA: "Y"
migrations:
build:
context: .
dockerfile: migrations.Dockerfile
depends_on:
- db
api:
ports:
- "8080:80"
- "8443:443"
environment:
- ASPNETCORE_URLS=https://+:443;http://+80
- ASPNETCORE_Kestrel__Certificates__Default__Password=VeryStrongPassword123
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
volumes:
- ../certs/:/https/
build:
context: .
dockerfile: api.Dockerfile
depends_on:
- migrations
spa_server:
ports:
- "5000:5000"
build:
context: ../client
dockerfile: client.Dockerfile
迁移Docker文件
#Get base SDK Image from Microsft
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 as build-env
WORKDIR /app
#Restore any dependecies
COPY ./Migrations ./Migrations
COPY ./Main/appsettings.json ./.Main/appsettings.json
COPY ./Main/appsettings.Development.json ./Main/appsettings.Development.json
COPY ./Roles.Persistence ./Roles.Persistence
COPY ./Users.Persistence ./Users.Persistence
RUN dotnet restore ./Migrations/Migrations.csproj
#Build our release
RUN dotnet publish ./Migrations/Migrations.csproj -c Release --no-restore
#Generate runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
COPY --from=build-env /app/Migrations/bin/Release/netcoreapp3.1/publish/ .
ENTRYPOINT ["dotnet","Migrations.dll"]
API Docker文件
#Get base SDK Image from Microsft
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 as build-env
WORKDIR /app
#Restore any dependecies
COPY . ./
RUN dotnet restore ./Main/Main.csproj
#Build our release
RUN dotnet publish ./Main/Main.csproj -c Release --no-restore
#Generate runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
EXPOSE 80 443
COPY --from=build-env /app/Main/bin/Release/netcoreapp3.1/publish/ .
ENTRYPOINT ["dotnet","Main.dll"]
SPA 和服务器 Docker文件
# Get base image from Node
FROM node:latest as build-env
WORKDIR /app
# Restore dependencies
COPY . ./
RUN npm i -g env-cmd
RUN npm i -g npm-run-all
RUN yarn
# Build client
RUN yarn build:container
# Generate image
EXPOSE 5000
ENTRYPOINT ["yarn", "start:container"]
我解决了
我使用的端口出了问题。
为了让 SPA 从浏览器发出请求,我需要使用外部端口,即 8443。因此容器中 运行 的服务器需要调用内部端口 443,现在它按预期工作。
谢谢大家
我的系统由一个 SPA、一个 Express.js 服务器和一个 ASP NET Core MVC API.
组成我的服务器使用 Passport.js 以便将 OAuth 与外部提供商一起使用,这样我就可以在我的 SPA 中提供 SSO 选项,除了登录表单。它的工作方式是,在从提供商处获取用户信息后,它通过 POST 请求将此数据发送到 API 以验证用户身份。如果用户选择使用登录表单而不是 SSO 选项之一,它会使用用户的电子邮件和密码直接向 API 发出 POST 请求。
到目前为止,在本地工作我没有遇到任何问题。我被要求将系统容器化,所以我为每个组件创建了一个 Docker 文件,一个 docker-compose.yml 来聚合它们,运行 docker -compose build 和 docker-compose up 没有问题。
现在,运行 容器,如果我选择通过表单登录,我可以毫无问题地使用我的 SPA,但是如果我尝试使用 SSO,我在进行 POST 请求到 API,这很奇怪,因为我的 SPA 服务向同一个地址发出 HTTP 请求没有问题。
webportal.client_1 | Error: connect ECONNREFUSED 127.0.0.1:8443
webportal.client_1 | at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1142:16) {
webportal.client_1 | errno: -111,
webportal.client_1 | code: 'ECONNREFUSED',
webportal.client_1 | syscall: 'connect',
webportal.client_1 | address: '127.0.0.1',
webportal.client_1 | port: 8443,
webportal.client_1 | response: undefined
webportal.client_1 | }
这是我的 Server.ts
import bodyParser from "body-parser";
import express from "express";
import session from "express-session";
import passport from "passport";
import { initialiseAuthentication } from "./auth";
import path from "path";
import http from "http";
require("dotenv").config({
path: __dirname + `/./../.env.${process.env.NODE_ENV}`,
});
const app = express();
const port = process.env.PORT || 5000;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, "/../build")));
app.use(session({ secret: "The big secret" }));
app.get("/ping", (req, res) => {
res.send({ express: "Pong" });
});
app.use(passport.initialize());
initialiseAuthentication(app);
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname + "/../build/index.html"));
});
http.createServer(app).listen(port, '0.0.0.0');
console.log(`Listening on port ${port}`);
我的 Api.ts 服务器发出 HTTP 请求的地方
import request from "superagent";
async function verifyUser(
email: string,
name: string,
provider: string,
providerId: string
) {
return await request
.post(`${process.env.BACKEND_API_URL}/authentication/externalAuth`)
.send({
Email: email,
Name: name,
Provider: provider,
ProviderId: providerId,
})
.then((res) => {
return res;
})
.catch((err) => {
console.error(err);
});
}
async function getUserById(data) {
return await request
.get(`${process.env.BACKEND_API_URL}/user/${data.Id}`)
.auth(data, { type: "bearer" })
.then((res) => {
return res;
})
.catch((err) => {
console.error(err);
});
}
export { verifyUser, getUserById };
我的 AuthenticationService.ts 在 SPA
import request from "superagent";
import Cookies from "js-cookie";
export async function SignIn(email: string, password: string) {
return request
.post(
`${process.env.REACT_APP_API_BACKEND_URL}/authentication/internalAuth`
)
.send({ username: email, password: password });
}
export async function GetUserInfo(userId: number) {
const jwt = Cookies.get("jwt");
return request
.get(`${process.env.REACT_APP_API_BACKEND_URL}/user`)
.query({ id: userId })
.auth(jwt as string, { type: "bearer" })
.then((res) => {
return res.body;
})
.catch((err) => console.error(err));
}
如果有人能够为我澄清这个问题并可能解决它,我将不胜感激。谢谢。
编辑 1: 请求都在 HTTPS 中,是的,我启用了 CORS 允许一切。
编辑 2: 添加了 Docker-Compose 和 Docker 文件。
Docker-撰写
version: "3"
services:
db:
image: "mcr.microsoft.com/mssql/server"
ports:
- "1433:1433"
environment:
SA_PASSWORD: "VeryStrongPassword1234"
ACCEPT_EULA: "Y"
migrations:
build:
context: .
dockerfile: migrations.Dockerfile
depends_on:
- db
api:
ports:
- "8080:80"
- "8443:443"
environment:
- ASPNETCORE_URLS=https://+:443;http://+80
- ASPNETCORE_Kestrel__Certificates__Default__Password=VeryStrongPassword123
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
volumes:
- ../certs/:/https/
build:
context: .
dockerfile: api.Dockerfile
depends_on:
- migrations
spa_server:
ports:
- "5000:5000"
build:
context: ../client
dockerfile: client.Dockerfile
迁移Docker文件
#Get base SDK Image from Microsft
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 as build-env
WORKDIR /app
#Restore any dependecies
COPY ./Migrations ./Migrations
COPY ./Main/appsettings.json ./.Main/appsettings.json
COPY ./Main/appsettings.Development.json ./Main/appsettings.Development.json
COPY ./Roles.Persistence ./Roles.Persistence
COPY ./Users.Persistence ./Users.Persistence
RUN dotnet restore ./Migrations/Migrations.csproj
#Build our release
RUN dotnet publish ./Migrations/Migrations.csproj -c Release --no-restore
#Generate runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
COPY --from=build-env /app/Migrations/bin/Release/netcoreapp3.1/publish/ .
ENTRYPOINT ["dotnet","Migrations.dll"]
API Docker文件
#Get base SDK Image from Microsft
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 as build-env
WORKDIR /app
#Restore any dependecies
COPY . ./
RUN dotnet restore ./Main/Main.csproj
#Build our release
RUN dotnet publish ./Main/Main.csproj -c Release --no-restore
#Generate runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
EXPOSE 80 443
COPY --from=build-env /app/Main/bin/Release/netcoreapp3.1/publish/ .
ENTRYPOINT ["dotnet","Main.dll"]
SPA 和服务器 Docker文件
# Get base image from Node
FROM node:latest as build-env
WORKDIR /app
# Restore dependencies
COPY . ./
RUN npm i -g env-cmd
RUN npm i -g npm-run-all
RUN yarn
# Build client
RUN yarn build:container
# Generate image
EXPOSE 5000
ENTRYPOINT ["yarn", "start:container"]
我解决了
我使用的端口出了问题。 为了让 SPA 从浏览器发出请求,我需要使用外部端口,即 8443。因此容器中 运行 的服务器需要调用内部端口 443,现在它按预期工作。
谢谢大家