前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >5-4 使用 webpack-dev-server 实现请求转发

5-4 使用 webpack-dev-server 实现请求转发

作者头像
love丁酥酥
发布2020-05-09 17:40:16
2.3K0
发布2020-05-09 17:40:16
举报
文章被收录于专栏:coding for lovecoding for love

1. 简介

请求转发,其实是使用 webpack-dev-server 的代理功能来实现的,本节为大家介绍 webpack-dev-server 的代理功能和主要使用场景。

2. 正向代理与反向代理

在进入正题之前,先简单地先介绍一下什么是代理,字面意义上理解就是委托第三方处理有关事务。网络代理分为正向代理和反向代理,所谓正向代理就是顺着请求的方向进行的代理,即代理服务器他是由你配置为你服务,去请求目标服务器地址。反向代理正好与正向代理相反,代理服务器是为目标服务器服务的。虽然整体的请求返回路线都是一样的都是 Client 到 Proxy 到 Server。 webpack-dev-server 的代理功能更偏向于正向代理,即是为前端开发者服务的。

3. 页面准备和接口请求

我们在项目中,新建如下文件:

代码语言:javascript
复制
// webpack.common.js
var HtmlWebpackPlugin = require('html-webpack-plugin');
var { CleanWebpackPlugin } = require('clean-webpack-plugin');
var path = require('path');

module.exports = {
    entry: {
        index: "./src/index.jsx",
    },
    output: {
        path: path.resolve(__dirname, '../dist'),
        filename: "[name].js"
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node-modules/,
                use: 'babel-loader'
            },
            {
                test: /\.(jpg|jpeg|png|gif)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        name: '[name].[ext]',
                        limit: 2048
                    }
                }
            },
            {
                test: /\.css$/,
                use: [ 'style-loader', 'css-loader' ]
            },
            {
                test: /\.scss$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'postcss-loader',
                    'sass-loader',
                ]
            },
            {
                test: /\.(eot|svg|ttf|woff)$/,
                use: 'file-loader'
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html"
        }),
        new CleanWebpackPlugin()
    ]
};
代码语言:javascript
复制
// webpack.dev.js
var path = require('path');
var webpack = require('webpack');
var merge = require('webpack-merge');
var commonConfig = require('./webpack.common');

var devConfig = {
    mode: 'development',
    devtool: "cheap-module-eval-source-map",
    devServer: {
        contentBase: path.resolve(__dirname, 'dist'),
        open: true,
        port: 3000,
        hot: true // 开启热更新
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ]
};

module.exports = merge(commonConfig, devConfig);
代码语言:javascript
复制
// webpack.prod.js
var merge = require('webpack-merge');
var commonConfig = require('./webpack.common');

var prodConfig = {
    mode: 'production',
    devtool: "cheap-module-source-map",
};

module.exports = merge(commonConfig, prodConfig);
代码语言:javascript
复制
// src/index.js
// src/index.js
import React, { Component } from 'react';
import ReactDom from 'react-dom';
import axios from 'axios';

class App extends Component {
  constructor() {
    super();
    this.state = {};
  }
  componentDidMount() {
    axios.get('http://127.0.0.1:3600/api/hello.json').then(res => {
      console.log(res)
      this.setState({
        msg: res.data.msg
      })
    }).catch(e => {
      console.error(e);
    })
  }

  render() {
    return <div>{this.state.msg}</div>
  }
}

ReactDom.render(<App />, document.getElementById('root'));
代码语言:javascript
复制
<!--src/index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>esmodule-oop</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>

.babelrc:

代码语言:javascript
复制
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "corejs": 2,
        "useBuiltIns": "usage"
      }
    ],
    "@babel/preset-react"
  ]
}
代码语言:javascript
复制
"scripts": {
    "dev": "webpack --config ./build/webpack.dev.js --watch",
    "dev-analyse": "webpack --config ./build/webpack.dev.js --profile --json > stas.json",
    "build-analyse": "webpack --config ./build/webpack.prod.js --profile --json > stas.json",
    "dev-server": "webpack-dev-server --config ./build/webpack.dev.js",
    "build": "webpack --config ./build/webpack.prod.js"
  },

3. 接口准备

这里就不用 node 写 server 了,直接 http-server 起一个简单的服务。运行 npm run build,然后在 dist 下新建如下文件: api/hello.json

代码语言:javascript
复制
{
  "msg": "hello world"
}

进入 dist,使用 http-server -p 3600 开启服务,访问 http://127.0.0.1:3600

image.png

4. 代理请求

但是我们部署的服务可能会改变地址(先上来讲是域名),另外,在开发环境的时候,我们的后台接口可能还没有开发完成,需要我们访问其他的开发地址或者测试地址。那该怎么做呢?一个最容易想到的方案就是将域名配置到统一的地方,一处更改,多处生效。比如我们封装一层请求,request,为其配置 host,每次请求的时候自动加上 host。我们的代码中只要写相对路径即可:

代码语言:javascript
复制
request.get('/api/hello.json')

但其实 webpack dev-server 为我们提供了方便地配置。一般为了防止跨域,我们会将静态资源和接口资源部署在同一个服务下,比如上面的 dist 下面加一个 api 目录,当然实际可能并不是这样,比如使用了反向代理等。在代码中我们写相对地址即可:

代码语言:javascript
复制
axios.get('/api/hello.json')

如果仅仅这样写,那么代码请求的始终是当前服务下的 api/hello,每次修改代码,需要部署之后才能生效。这显然是不可能的。我们关闭之前的服务,新建一个文件:server/api/hello.json,进入 server 使用 3000 端口重新开启服务。 然后我们使用 dev-server 开启服务:npm run dev-server

image.png

可以看到, 请求的是 3600 端口下的接口,但是我们这里的 dev-server 仅提供了页面资源,并没有接口资源,接口资源在线上(这里用 3000 端口代替)。 这时候就要使用上述我们提到的代理了:

代码语言:javascript
复制
    devServer: {
        contentBase: path.resolve(__dirname, 'dist'),
        open: true,
        port: 3000,
        hot: true,// 开启热更新
        proxy: {
            '/api': 'http://127.0.0.1:3000'
        }
    },

重新运行 npm run dev-server,如下:

image.png

4. 跨域

有的人会想,那这样做其实和在源码中通过配置去写也是一样的呀,只要最终达到以下效果就可以了:

代码语言:javascript
复制
axios.get('http://127.0.0.1:3600/api/hello.json').then(res => {
      console.log(res)
      this.setState({
        msg: res.data.msg
      })
    }).catch(e => {
      console.error(e);
    })

那么我们代码作如上改写,关闭代理后,npm run dev-server 看看:

image.png

打开 console:

image.png

可以看到,报了跨域。这是因为浏览器现代浏览器的同源安全策略,禁止跨域发送请求。而 proxy 是通过一个代理服务器帮我们转发请求,不受浏览器的跨域限制。但其实对于很多后端服务,出于安全考虑,我们也会做跨域限制,这时候接口就无法正常返回数据呢。对于这种情况,我们可以使用 changeOrigin 来解决:

我们把请求地址改回相对地址,然后修改 proxy 配置如下:

代码语言:javascript
复制
proxy: {
            '/api': {
                target: 'http://127.0.0.1:3600',
                changeOrigin: true
            }
        }

就可以帮我们解决接口跨域问题了。

5. 重写路径

有时候,我们会遇到路径不一致的场景,比如我们本来是请求 hello 接口的,但这个接口正在开发中,后端可能丢了一个 demo 接口让我们先用,还有的时候我们的生产接口可能放在 api 下面,但是测试接口并没有这一层路径,这时候我们就可以通过重写路径来保证访问地址的正确性:

代码语言:javascript
复制
module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:3600',
        pathRewrite: {'^/api' : ''}
      }
    }
  }
};

6. 过滤

有时你不想代理所有的请求。可以基于一个函数的返回值绕过代理。 在函数中你可以访问请求体、响应体和代理选项。必须返回 false 或路径,来跳过代理请求。 例如:对于浏览器请求,你想要提供一个 HTML 页面,但是对于 API 请求则保持代理。你可以这样做:

代码语言:javascript
复制
proxy: {
  "/api": {
    target: "http://localhost:3000",
    bypass: function(req, res, proxyOptions) {
      if (req.headers.accept.indexOf("html") !== -1) {
        console.log("Skipping proxy for browser request.");
        return "/index.html";
      }
    }
  }
}
  1. 代理多个路径 如果你想要代码多个路径代理到同一个target下, 你可以使用由一个或多个「具有 context 属性的对象」构成的数组:
代码语言:javascript
复制
proxy: [{
  context: ["/auth", "/api"],
  target: "http://localhost:3000",
}]

8. 使用 https

默认情况下,不接受运行在 HTTPS 上,且使用了无效证书的后端服务器。如果你想要接受,修改配置如下:

代码语言:javascript
复制
proxy: {
  "/api": {
    target: "https://other-server.example.com",
    secure: false
  }
}

9. 小结

proxy 的配置相当丰富,甚至还可以帮我们修改 header,携带 cookie 等。这些都让我们能在不修改源码的情况下通过简单的配置即可做到,远远优于直接手动在源码进行修改的方法,极大方便了我们的开发。

参考

正向代理与反向代理的区别 https://webpack.js.org/configuration/dev-server/#devserverproxy https://www.webpackjs.com/configuration/dev-server/#devserver-proxy Webpack-dev-server的proxy用法

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 简介
  • 2. 正向代理与反向代理
  • 3. 页面准备和接口请求
  • 3. 接口准备
  • 4. 代理请求
  • 4. 跨域
  • 5. 重写路径
  • 6. 过滤
  • 8. 使用 https
  • 9. 小结
  • 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档