create-react-app搭建代理(一)介绍了如何通过devServer.before自定义路由从而搭建代理,本文给出另外一种方法。经过npm run eject之后配置代理,create-react-app用的是webpack-dev-server实现一个简单的web服务器,webpack-dev-server是基于express实现的。webpack-dev-server相关配置可参考webpack中devServer。
在script文件夹下创建一个server.js文件搭建服务器,代码如下:
const path = require('path')
const express = require('express')
const axios = require('axios')
const app = express()
const apiRoutes = express.Router()
apiRoutes.get('/getDiscList', function (req, res) {
var url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg'
axios.get(url, {
headers: {
referer: 'https://c.y.qq.com/',
host: 'c.y.qq.com'
},
params: req.query
}).then((response) => {
res.json(response.data)
}).catch((e) => {
console.log(e)
})
})
app.use('/api', apiRoutes)
const server = app.listen(3111,function() {
console.log("Server running on port %s", server.address().port);
})
在package.json文件中添加如下代码:
"proxy": "http://localhost:3111"
目的是,当设置proxy的时候,根据create-react-app中start.js以及webpackDevServer.config.js来设置devServer.proxy start.js中相关代码如下
// Load proxy config
//没有配置packjson的时候proxyConfig为undefined
const proxySetting = require(paths.appPackageJson).proxy;
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
// Serve webpack assets generated by the compiler over a web server.
//urls.lanUrlForConfig是根据协议,host以及端口生成的,这里为本机的ip地址
const serverConfig = createDevServerConfig(
proxyConfig,
urls.lanUrlForConfig
);
//利用webpack-dev-server插件根据webpack生成的编译器以及自定义的服务器配置来生成devServer
const devServer = new WebpackDevServer(compiler, serverConfig);
首先拿到packjson中的proxy的值,然后通过prepareProxy函数获取一个proxyConfig对象,prepareProxy函数相关代码如下,由于package.json中proxy为字符串形式(proxy其实不允许是对象,prepareProxy函数部分代码有问题),所以只需要看处理字符串的相关代码。
// Support proxy as a string for those who are using the simple proxy option
if (typeof proxy === 'string') {
if (!/^http(s)?:\/\//.test(proxy)) {
console.log(
chalk.red(
'When "proxy" is specified in package.json it must start with either http:// or https://'
)
);
process.exit(1);
}
let target;
if (process.platform === 'win32') {
target = resolveLoopback(proxy);
} else {
target = proxy;
}
return [
{
target,
logLevel: 'silent',
context: function(pathname, req) {
return (
req.method !== 'GET' ||
(mayProxy(pathname) &&
req.headers.accept &&
req.headers.accept.indexOf('text/html') === -1)
);
},
onProxyReq: proxyReq => {
if (proxyReq.getHeader('origin')) {
proxyReq.setHeader('origin', target);
}
},
onError: onProxyError(target),
secure: false,
changeOrigin: true,
ws: true,
xfwd: true,
},
];
}
最终proxyConfig将会是一个数组: [ { target:"http://localhost:3111", logLevel: 'silent', ... secure: false, changeOrigin: true, ws: true, xfwd: true, }, ] 然后通过webpackDevServer.config.js中export的方法,将proxyConfig作为该函数参数赋值给返回对象的proxy:
{
proxy:[
{
target:"http://localhost:3111",
logLevel: 'silent',
...
secure: false,
changeOrigin: true,
ws: true,
xfwd: true,
},
]
}
该对象即为serverConfig,然后在start.js中执行如下代码,利用webpack-dev-server插件根据webpack生成的编译器以及自定义的服务器配置来生成devServer,因此webpac-dev-servr可以代理port(默认为3000端口)的所有请求。由于serverConfig中的端口为3111,此时只需要搭建一个服务器来监听3111端口即可,在3000端口的请求上如果没有匹配到webpack-dev-server服务器上的路由,那么webpack-dev-server服务器会将来自3000端口的请求代理到3111端口的服务器上。
devServer = new WebpackDevServer(compiler, serverConfig);
devServer.listen(port, HOST,errFunc)
首先需要安装concurrently依赖用于同时运行两个npm命令
npm install --save-dev concurrently
然后在package.json中修改scripts,如下所示:
"scripts": {
"dev": "node scripts/start.js",
"server": "node scripts/server.js &",
"start": "concurrently \"npm run server\" \"npm run dev\" ",
"build": "node scripts/build.js",
"test": "node scripts/test.js"
}
将上面操作保留,并增加create-react-app搭建代理(一)中所作的操作: 在start.js中修改为如下代码:
//增加的代码
const appRoute = require('../server/server.js')
//在before中增加代码
module.exports = function(proxy, allowedHost) {
return {
...
//增加的代码
before(app, server) {
...
appRoute(app)
...
}
}
}
server/server.js下的代码修改为,返回"NO":
apiRoutes.get('/getDiscList', function (req, res) {
var url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg'
axios.get(url, {
headers: {
referer: 'https://c.y.qq.com/',
host: 'c.y.qq.com'
},
params: req.query
}).then((response) => {
res.json("no")
}).catch((e) => {
console.log(e)
})
})