使用webpack-dev-server设置反向代理解决前端跨域问题

webpack-dev-server是一个小型的Node.js Express服务器,它使用webpack-dev-middleware来服务于webpack的包,除此自外,它还有一个通过Sock.js来连接到服务器的微型运行时.

我们来看一下下面的配置文件(webpack.config.js)

var path = require("path");
module.exports = {
    entry:{
    app:["./app/main.js"]
    },
    output:{
    path:path.resolve(__dirname,"build"),
    publicPath:"/assets/",
    filename:"bundle.js"
}
}

  

这里你将你的源文件放在app文件夹下,并通过webpack将其打包到build文件夹下的bundle.js中.

注意:webpack-dev-server是一个独立的NPM包,你可以通过npm install webpack-dev-server来安装它.

基本目录

webpack-dev-server默认会以当前目录为基本目录,除非你制定它.

webpack-dev-server --content-base build/

  

上述命令是在命令行中执行的,它将build目录作为根目录.有一点需要注意的是:webpack-dev-server生成的包并没有放在你的真实目录中,而是放在了内存中.

我们在基本目录下新建一个index.html文件,然后在浏览器中输入http://localhost:8080访问.

<!DOCTYPE html>
<html >
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <script src="assets/bundle.js"></script>
</body>
</html>

  

webpack-dev-server启动proxy代理

代理配置

webpack-dev-server使用http-proxy-middleware去把请求代理到一个外部的服务器,配置的样例如下:

//配置服务器
    devServer: {
        historyApiFallback: true,
        hot: true,
        inline: true,
        contentBase: "./app",
        port: 8090,
        proxy: {
            "/api": {
              target: 'http://localhost:8888',
              pathRewrite: {'^/api' : ''},
              changeOrigin: true
            }
        },
       
    },

  

这种代理在很多情况下是很重要的,比如你可以把一些静态文件通过本地的服务器加载,而一些API请求全部通过一个远程的服务器来完成。还有一个情景就是在两个独立的服务器之间进行请求分割,如一个服务器负责授权而另外一个服务应用本身。

pathRewrite: 对于代理的请求可以通过提供一个函数来重写,这个函数可以查看或者改变http请求。下面的例子就会重写HTTP请求,其主要作用就是移除URL前面的/api部分。

绕开代理

通过一个函数的返回值可以视情况的绕开一个代理。这个函数可以查看http请求和响应以及一些代理的选项。它必须返回要么是false要么是一个URL的path,这个path将会用于处理请求而不是使用原来代理的方式完成。下面的例子的配置将会忽略来自于浏览器的HTTP请求,他和historyApiFallback配置类似。浏览器请求可以像往常一样接收到HTML文件,但是API请求将会被代理到另外的服务器:

proxy: {
  '/some/path': {
    target: 'https://other-server.example.com',
    secure: false,
    bypass: function(req, res, proxyOptions) {
      if (req.headers.accept.indexOf('html') !== -1) {
        console.log('Skipping proxy for browser request.');
        return '/index.html';
    }
  }
 }
}

 

代理本地虚拟主机

http-proxy-middleware会预解析本地hostname成为localhost,你可以使用下面的配置来修改这种默认行为:

var server = new webpackDevServer(compiler, {
  quiet: false,
  stats: { colors: true },
  proxy: {
    "/api": {
      "target": {
        "host": "action-js.dev",
        "protocol": 'http:',
        "port": 80
      },
      ignorePath: true,
      changeOrigin: true,
      secure: false
    }
  }
});
server.listen(8080);

  

贴入我自己项目的webpack.config.js配置:

var webpack = require('webpack');
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin'); //抽取CSS文件插件
var OpenBrowserPlugin = require('open-browser-webpack-plugin'); //自动打开浏览器插件
var ROOT_PATH = path.resolve(__dirname);
var BUILD_PATH = path.resolve(ROOT_PATH, 'build');
var APP_PATH = path.resolve(ROOT_PATH, 'app');

module.exports = {
    //配置服务器
    devServer: {
        historyApiFallback: true,
        hot: true,
        inline: true,
        contentBase: "./app",
        port: 8090,
        proxy: {
            "/api": {
              target: 'http://localhost:8888',
              pathRewrite: {'^/api' : ''},
              changeOrigin: true
            }
        },
       
    },

    //配置入口, 支持多入口
    entry: {
        page: ROOT_PATH + '/app/src/router/router.jsx',
        vendors: ['react', 'react-dom', 'react-router', 'mobx']  //第三方库和框架
    },

    output: {
        // path: "dist",
        publicPath: 'dist',
        filename: 'js/bundle.js'
    },

    module: {
        loaders: [
            {
                test: /\.css$/,
                loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' })//此处不用loader,改为use
            },
            {
                test: /\.less$/,
                loader: ExtractTextPlugin.extract('css-loader!less-loader')
            },
            {
                test: /\.js[x]?$/,
                exclude: /node_modules/,
                loader: 'babel-loader'
            },
            { 
                test: /\.(png|jpg)$/,
                loader: 'url-loader?limit=8192&name=img/[name].[ext]'
            },
            { 
                test: /\.(woff|woff2|eot|ttf|svg)(\?.*$|$)/,
                loader: 'url-loader'
            }
        ]
    },

    resolve: {
        extensions: [' ', '.js', '.jsx']
    },

    plugins: [
        new webpack.optimize.CommonsChunkPlugin({ 'name': 'vendors', 'filename': 'js/vendors.js' }),
        new ExtractTextPlugin("css/bundle.css"),
        // 如需jquery请解锁
        // new webpack.ProvidePlugin({ $: "jquery" }),
        new webpack.HotModuleReplacementPlugin(),
        new OpenBrowserPlugin({ url: 'http://localhost:8090/gallery' })
    ]
}

  

总结: 如有疑问请参考官方文档 https://doc.webpack-china.org/concepts/