如何在Angular生产服务器配置代理?本地生效生产无效求解
我正在测试基于Angular构建的前端应用新方案,希望隐藏浏览器Network中的API地址。例如:调用api.url.dz/login时,先请求front.url.dz/login再转发至目标API。
本地通过ng serve --proxy-config proxy.config.json启动项目时,代理可正常工作,但生产环境执行ng build后代理失效。
本地proxy.config.json配置:
{ "http://localhost:4200":{ "target":"http://localhost:9999/", "secure":false, "changeOrigin": true, "logLevel":"debug", "pathRewrite": { "^/authenticate": "authenticate", "^/authenticate-refresh": "authenticate-refresh", "^/refresh-token": "refresh-token", "^/auth-logout": "auth-logout" } } }
生产服务器proxy.config.json配置:
{ "https://front.domaine.dz":{ "target":"https://back.domaine.dz:9999", "secure":false, "changeOrigin": true, "logLevel":"debug", "pathRewrite": { "^/authenticate": "authenticate", "^/authenticate-refresh": "authenticate-refresh", "^/refresh-token": "refresh-token", "^/auth-logout": "auth-logout" } } }
项目angular.json配置:
{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "argon-dashboard-angular": { "root": "", "sourceRoot": "src", "projectType": "application", "prefix": "app", "schematics": { "@schematics/angular:component": { "styleext": "scss" } }, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "outputPath": "dist", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.app.json", "assets": [ "src/favicon.ico", "src/assets" ], "styles": [ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", "src/styles.scss", "src/assets/scss/argon.scss" ], "scripts": [ "node_modules/chart.js/dist/Chart.min.js", "node_modules/clipboard/dist/clipboard.min.js" ] }, "configurations": { "production": { "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ], "optimization": true, "outputHashing": "all", "sourceMap": false, "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true } } }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "argon-dashboard-angular:build" }, "configurations": { "production": { "browserTarget": "argon-dashboard-angular:build:production" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "argon-dashboard-angular:build" } }, "test": { "builder": "@angular-devkit/build-angular:karma", "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.spec.json", "karmaConfig": "src/karma.conf.js", "styles": [ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", "src/styles.css" ], "scripts": [], "assets": [ "src/favicon.ico", "src/assets" ] } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": [ "src/tsconfig.app.json", "src/tsconfig.spec.json" ], "exclude": [ "**/node_modules/**" ] } } } }, "argon-dashboard-angular-e2e": { "root": "e2e/", "projectType": "application", "architect": { "e2e": { "builder": "@angular-devkit/build-angular:protractor", "options": { "protractorConfig": "e2e/protractor.conf.js", "devServerTarget": "argon-dashboard-angular:serve" }, "configurations": { "production": { "devServerTarget": "argon-dashboard-angular:serve:production" } } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": "e2e/tsconfig.e2e.json", "exclude": [ "**/node_modules/**" ] } } } } }, "defaultProject": "argon-dashboard-angular", "schematics": { "@schematics/angular:component": { "styleext": "scss" } }, "cli": { "analytics": false } }
核心疑问:是否有替代方案,能在执行ng build命令时实现代理配置?
Angular CLI的proxy.config.json仅在ng serve的开发服务器中生效,生产构建后不会包含代理逻辑——最终产物是静态文件,需要依赖服务器端代理或其他方案实现需求。以下是几种可行方案:
1. 生产服务器配置反向代理
这是最常用的方案,直接在部署前端的Web服务器(如Nginx、Apache)中配置反向代理,将前端请求转发到后端API。
示例:Nginx配置
在Nginx的站点配置中添加如下规则:
server { listen 443 ssl; server_name front.domaine.dz; # 静态文件指向Angular构建后的dist目录 root /path/to/your/angular/dist; index index.html; # 处理API请求转发 location ~ ^/(authenticate|authenticate-refresh|refresh-token|auth-logout) { proxy_pass https://back.domaine.dz:9999; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # Angular单页应用路由 fallback location / { try_files $uri $uri/ /index.html; } # SSL配置(根据实际情况添加) ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; }
配置完成后重启Nginx,前端请求front.domaine.dz/authenticate会被自动转发到back.domaine.dz:9999/authenticate,浏览器Network中只会显示前端域名的请求。
2. 使用Angular环境变量统一API前缀
结合环境变量配置API前缀,生产环境下前缀设为前端域名的路径,配合服务器代理使用:
- 在
src/environments/environment.ts(开发环境):
export const environment = { production: false, apiPrefix: 'http://localhost:9999' };
- 在
src/environments/environment.prod.ts(生产环境):
export const environment = { production: true, apiPrefix: '' // 空字符串表示使用当前域名 };
- 封装HTTP服务时使用该前缀:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { environment } from '../environments/environment'; @Injectable({ providedIn: 'root' }) export class ApiService { private baseUrl = environment.apiPrefix; constructor(private http: HttpClient) {} login(credentials: any) { return this.http.post(`${this.baseUrl}/authenticate`, credentials); } // 其他API方法... }
这样开发环境直接请求后端,生产环境请求当前域名,再通过服务器代理转发,既统一了代码逻辑,又实现了地址隐藏。
3. 使用Node.js中间件作为代理服务器
如果需要用Node.js部署前端,可以搭建一个简单的Express服务器,同时托管静态文件并处理代理:
- 安装依赖:
npm install express http-proxy-middleware --save
- 创建
server.js文件:
const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); const path = require('path'); const app = express(); // 托管Angular静态文件 app.use(express.static(path.join(__dirname, 'dist'))); // 配置代理 const apiProxy = createProxyMiddleware(['/authenticate', '/authenticate-refresh', '/refresh-token', '/auth-logout'], { target: 'https://back.domaine.dz:9999', changeOrigin: true, secure: false }); app.use(apiProxy); // 处理SPA路由 app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'dist/index.html')); }); // 启动服务器 const port = process.env.PORT || 80; app.listen(port, () => { console.log(`Server running on port ${port}`); });
- 构建后启动服务器:
ng build --prod node server.js
这种方案适合需要用Node.js部署的场景,代理逻辑和前端部署在一起,无需额外配置Web服务器。
内容的提问来源于stack exchange,提问作者Abderrahmane BECHIKH

