前端项目在本地开发时,会启动 webpack-dev-server 本地服务(默认 http://localhost:3000); 如果需要请求后端接口(比如 http://localhost:8080/api),浏览器会因为同源策略阻止请求,报跨域错误。
webpack-dev-server 内置了代理服务器功能: 本地请求 → 代理服务器转发 → 后端接口 代理服务器是服务端请求,不受浏览器同源策略限制,完美解决开发环境跨域问题。
代理配置属于开发服务器配置,直接追加在配置文件的 devServer 对象中即可,无需安装新依赖!
找到原配置中的 devServer 节点,我们只需要在这个对象里新增 proxy 代理配置
在 devServer 中追加以下代理配置
proxy: [
{
// 所有以 /api 开头的接口请求,都会走这个代理
context: '/api',
// 后端接口的根地址(根据你的实际后端地址修改)
target: 'http://localhost:8080',
// 开启跨域允许(必须写,否则代理失效)
changeOrigin: true,
// 路径重写(可选):移除请求中的 /api 前缀
// 例:前端请求 /api/user → 转发给后端的 /user
pathRewrite: { '^/api': '' } // 可选:重写路径(移除 /api 前缀)
}
]import path from 'path';
import { fileURLToPath } from 'url';
// ESM 模式导入 HTML 插件
import HtmlWebpackPlugin from 'html-webpack-plugin';
// 手动定义 __dirname(兼容 ESM 模式)
const __filename = fileURLToPath(import.meta.url); // 获取当前文件的绝对路径
const __dirname = path.dirname(__filename); // 获取当前文件所在目录的绝对路径
// Webpack 配置导出(ESM 模式)
export default {
// 区分开发和生产环境
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
// 入口文件
entry: './src/index.ts',
// 输出配置
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
// 在开发环境中不强制输出ES模块,以确保样式加载正常
...(process.env.NODE_ENV === 'production'
? {
module: true, // 生产环境输出 ES Module 格式产物
clean: true // Webpack5 内置:打包前自动清空 dist 目录
}
: {}
)
},
// 开发环境下不需要实验性特性
experiments: process.env.NODE_ENV === 'production'
? {
outputModule: true
}
: {},
// 模块解析
resolve: {
// 自动识别文件后缀,引入模块时可省略对应后缀名
extensions: ['.js', '.ts', '.css', '.less', '.vue']
},
// TS 文件加载器
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
// 匹配所有以 .css 结尾的文件
test: /\.css$/,
// Loader 执行顺序:从右向左 执行
// 1. css-loader 解析 CSS 文件
// 2. style-loader 将样式注入 DOM
use: ["style-loader", "css-loader"]
},
{
// 匹配所有以 .less 结尾的文件
test: /\.less$/,
// 执行顺序:less-loader → css-loader → style-loader
// 1. less-loader 编译 Less 为 CSS
// 2. css-loader 解析 CSS 模块
// 3. style-loader 将样式注入页面 DOM
use: ["style-loader", "css-loader", "less-loader"]
},
{
// 匹配所有图片格式文件,i 表示不区分大小写
test: /\.(png|jpg|gif|jpeg)$/i,
// Webpack 5 内置资源类型,自动判断资源处理方式
type: 'asset',
// 自定义打包输出规则
generator: {
// 输出到 dist/images 目录
// [name]:原文件名
// [hash:4]:4 位哈希值,防止缓存
// [ext]:文件后缀名
filename: 'images/[name].[hash:4][ext]'
}
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/i,
// 固定输出资源文件:不做 base64 转换,直接复制到打包目录
type: 'asset/resource',
generator: {
// 输出到 dist/fonts 目录
// [name] 原文件名,[hash:4] 4 位哈希值,[ext] 文件后缀
filename: 'fonts/[name].[hash:4][ext]'
}
}
]
},
// 插件配置:生成 HTML 并自动注入打包资源
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html', // HTML 模板路径
filename: 'index.html', // 输出的 HTML 文件名
inject: true // 自动注入 JS/CSS 资源
})
],
// 开发服务器配置
devServer: {
port: 3000, // 服务监听端口 3000
open: true, // 自动打开浏览器
hot: true, // 启用热更新
static: {
directory: path.join(__dirname, 'public'), // 静态资源目录
},
client: {
overlay: false, // 是否显示编译错误在浏览器中
},
proxy: [
{
context: '/api', // 指定要代理的接口前缀
target: 'http://localhost:8080', // 后端服务地址
changeOrigin: true, // 解决跨域
pathRewrite: { '^/api': '' } // 可选:重写路径(移除 /api 前缀)
}
]
},
// 开发环境启用source map,便于调试
devtool: process.env.NODE_ENV === 'production' ? false : 'eval-source-map'
};前端请求地址:/api/user/list
代理转发逻辑:
匹配 /api → 启用代理
拼接 target:http://localhost:8080/api/user/list
路径重写:移除 /api → 最终请求后端:http://localhost:8080/user/list
修改后端地址:将 target 改为你的真实后端接口地址(如 http://192.168.1.100:8080)
前端发起请求:
// 前端代码中直接请求 /api 开头的接口即可
fetch('/api/user/list')
.then(res => res.json())
.then(data => console.log(data));启动项目:npm run serve 代理自动生效
代理不生效:检查 changeOrigin: true 是否开启
404 错误:检查 target 地址是否正确、pathRewrite 是否配置错误
跨域依然报错:确认请求路径以 /api 开头,匹配代理规则
代理作用:解决开发环境跨域,无需后端配合
配置位置:devServer.proxy
核心参数:target(后端地址)+ changeOrigin: true(必开)