You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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服务器,同时托管静态文件并处理代理:

  1. 安装依赖:
npm install express http-proxy-middleware --save
  1. 创建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}`);
});
  1. 构建后启动服务器:
ng build --prod
node server.js

这种方案适合需要用Node.js部署的场景,代理逻辑和前端部署在一起,无需额外配置Web服务器。


内容的提问来源于stack exchange,提问作者Abderrahmane BECHIKH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 12:57:24