您的位置 首页 > 腾讯云社区

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

1. 简介

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

2. 正向代理与反向代理

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

3. 页面准备和接口请求

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

// 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() ] };// 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);// 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);// 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'));<!--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:

{ "presets": [ [ "@babel/preset-env", { "corejs": 2, "useBuiltIns": "usage" } ], "@babel/preset-react" ] }"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

{ "msg": "hello world" }

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

image.png

4. 代理请求

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

request.get('/api/hello.json')

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

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 端口代替)。 这时候就要使用上述我们提到的代理了:

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. 跨域

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

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 配置如下:

proxy: { '/api': { target: 'http://127.0.0.1:3600', changeOrigin: true } }

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

5. 重写路径

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

module.exports = { //... devServer: { proxy: { '/api': { target: 'http://localhost:3600', pathRewrite: {'^/api' : ''} } } } };6. 过滤

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

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"; } } } }代理多个路径 如果你想要代码多个路径代理到同一个target下, 你可以使用由一个或多个「具有 context 属性的对象」构成的数组:proxy: [{ context: ["/auth", "/api"], target: "http://localhost:3000", }]8. 使用 https

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

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用法

---来自腾讯云社区的---love丁酥酥

关于作者: 瞎采新闻

这里可以显示个人介绍!这里可以显示个人介绍!

热门文章

留言与评论(共有 0 条评论)
   
验证码: