使用 Hapi 响应路由
React routing with Hapi
我需要将 Hapi 与 create-react-app
一起使用,其中 Hapi 充当 api 请求的代理并且还服务于 React 应用程序。
我正在尝试让路由正常工作,但它似乎不适用于当前的 Hapi 配置。
这是我的服务器代码:
const Path = require('path');
const Hapi = require('hapi');
const Inert = require('inert');
const init = async () => {
const server = new Hapi.Server({
port: process.env.PORT || 5000,
routes: {
files: {
relativeTo: Path.join(__dirname, '../build')
}
}
});
await server.register(Inert);
server.route({
method: 'GET',
path: '/{param*}',
handler: {
directory: {
path: '.'
}
}
});
const options = {
ops: {
interval: 1000
},
reporters: {
myConsoleReporter: [
{
module: 'good-console',
args: [{ request: '*', response: '*' }]
},
'stdout'
]
}
};
await server.register({
plugin: require('good'),
options,
});
await server.start();
console.log('Server running at:', server.info.uri);
};
init();
index.html 文件在 localhost:5000
打开时加载正常。我在 react-router
部分配置了路由 /dashboard
。点击 localhost:5000/dashboard
给出 404。
问题:
- 如何配置 Hapi 中的路由,以便 React 在 index.html 渲染后接管路由?
- 当前服务器代码在构建应用程序后从构建文件夹提供应用程序。如何将其配置为热重载 而无需从
create-react-app
中弹出
注意:当 运行 带有 npm start
的 React 应用程序时路由有效。但这是没有 Hapi 服务器 运行.
我是使用 Hapi 的新手,因此不胜感激。
所以我尝试了各种 hapi+inert 组合,这就是最终对我有用的东西。
server.js
const Path = require('path');
const Hapi = require('hapi');
const Inert = require('inert');
const routes = require('./routes');
const init = async () => {
console.log('Routes are', routes);
const server = new Hapi.Server({
port: process.env.PORT || 5000,
routes: {
files: {
relativeTo: Path.join(__dirname, '../build')
}
}
});
await server.register(Inert);
server.route(routes);
/**
* This is required here because there are references to *.js and *.css in index.html,
* which will not be resolved if we don't match all remaining paths.
* To test it out, comment the code below and try hitting /login.
* Now that you know it doesn't work without the piece of code below,
* uncomment it.
*/
server.route({
method: 'GET',
path: '/{path*}',
handler: {
directory: {
path: '.',
redirectToSlash: true,
index: true,
}
}
});
const options = {
ops: {
interval: 1000
},
reporters: {
myConsoleReporter: [
{
module: 'good-console',
args: [{ request: '*', response: '*' }]
},
'stdout'
]
}
};
await server.register({
plugin: require('good'),
options,
});
await server.start();
console.log('Server running at:', server.info.uri);
};
init();
/routes/index.js
/**
* Use this for all paths since we just need to resolve index.html for any given path.
* react-router will take over and show the relevant component.
*
* TODO: add a 404 handler for paths not defined in react-router
*/
const fileHandler = {
handler: (req, res) => {
console.log(res.file('index.html'));
return res.file('index.html');
}
}
const routes = [
{ method: 'GET', path: '/login', config: fileHandler },
]
module.exports = routes;
这里要注意的关键是,对于任何命名路径(在本例中为 /login
),我们总是 return index.html
文件。对于所有其他路径,我们告诉 hapi 从我们的 build
目录到 return 文件,这样我们 index.hml
中对 *.css
或 *.js
文件的任何引用都将是已解决,我们不会遇到 404。
我不确定 react-router
如何在加载 index.html 后接管路径解析,但这超出了这个问题的范围,可能是另一个讨论的话题。
关于hot-reload的第二个问题,我还在摸索中。现在我 运行 hapi 服务器和 react-app 都是独立的,因为我需要 /api
在 react-app 中使用。欢迎任何建议或答案。
这是我的做法。测试了它。版本 "@hapi/hapi": "^20.0.1"
.
const path = require("path")
const Hapi = require('@hapi/hapi')
const Boom = require('@hapi/boom');
const server = Hapi.server({
port: 3000,
host: '0.0.0.0',
routes: {
files: {
relativeTo: path.join(__dirname, 'YOU BUILD REACT DIR')
}
}
});
(async () => {
await server.register([
require('vision'),
require('inert')
]);
server.route(
[{
method: 'GET',
path: '/{path*}',
options: {
ext: {
onPreResponse: {
method(req, h) {
//for other path prefix /Api
const isApi = req.path.substr(1)
.toLowerCase()
.trim()
.split('/')[0]
.replace(/\//g, "") === "api"
const response = req.response
if (response && req.response.output && req.response.output.statusCode === 404) {
if (isApi)
return Boom.notFound("Not Found")
return h.file('index.html');
}
return h.continue
},
}
}
},
handler: {
directory: {
path: ".",
listing: false,
index: true
}
}
},
{
method: 'GET',
path: '/Api/test',
handler: () => "OK"
}
])
await server.start();
console.log('Server running on %s', server.info.uri)
})()
我需要将 Hapi 与 create-react-app
一起使用,其中 Hapi 充当 api 请求的代理并且还服务于 React 应用程序。
我正在尝试让路由正常工作,但它似乎不适用于当前的 Hapi 配置。
这是我的服务器代码:
const Path = require('path');
const Hapi = require('hapi');
const Inert = require('inert');
const init = async () => {
const server = new Hapi.Server({
port: process.env.PORT || 5000,
routes: {
files: {
relativeTo: Path.join(__dirname, '../build')
}
}
});
await server.register(Inert);
server.route({
method: 'GET',
path: '/{param*}',
handler: {
directory: {
path: '.'
}
}
});
const options = {
ops: {
interval: 1000
},
reporters: {
myConsoleReporter: [
{
module: 'good-console',
args: [{ request: '*', response: '*' }]
},
'stdout'
]
}
};
await server.register({
plugin: require('good'),
options,
});
await server.start();
console.log('Server running at:', server.info.uri);
};
init();
index.html 文件在 localhost:5000
打开时加载正常。我在 react-router
部分配置了路由 /dashboard
。点击 localhost:5000/dashboard
给出 404。
问题:
- 如何配置 Hapi 中的路由,以便 React 在 index.html 渲染后接管路由?
- 当前服务器代码在构建应用程序后从构建文件夹提供应用程序。如何将其配置为热重载 而无需从
create-react-app
中弹出
注意:当 运行 带有 npm start
的 React 应用程序时路由有效。但这是没有 Hapi 服务器 运行.
我是使用 Hapi 的新手,因此不胜感激。
所以我尝试了各种 hapi+inert 组合,这就是最终对我有用的东西。
server.js
const Path = require('path');
const Hapi = require('hapi');
const Inert = require('inert');
const routes = require('./routes');
const init = async () => {
console.log('Routes are', routes);
const server = new Hapi.Server({
port: process.env.PORT || 5000,
routes: {
files: {
relativeTo: Path.join(__dirname, '../build')
}
}
});
await server.register(Inert);
server.route(routes);
/**
* This is required here because there are references to *.js and *.css in index.html,
* which will not be resolved if we don't match all remaining paths.
* To test it out, comment the code below and try hitting /login.
* Now that you know it doesn't work without the piece of code below,
* uncomment it.
*/
server.route({
method: 'GET',
path: '/{path*}',
handler: {
directory: {
path: '.',
redirectToSlash: true,
index: true,
}
}
});
const options = {
ops: {
interval: 1000
},
reporters: {
myConsoleReporter: [
{
module: 'good-console',
args: [{ request: '*', response: '*' }]
},
'stdout'
]
}
};
await server.register({
plugin: require('good'),
options,
});
await server.start();
console.log('Server running at:', server.info.uri);
};
init();
/routes/index.js
/**
* Use this for all paths since we just need to resolve index.html for any given path.
* react-router will take over and show the relevant component.
*
* TODO: add a 404 handler for paths not defined in react-router
*/
const fileHandler = {
handler: (req, res) => {
console.log(res.file('index.html'));
return res.file('index.html');
}
}
const routes = [
{ method: 'GET', path: '/login', config: fileHandler },
]
module.exports = routes;
这里要注意的关键是,对于任何命名路径(在本例中为 /login
),我们总是 return index.html
文件。对于所有其他路径,我们告诉 hapi 从我们的 build
目录到 return 文件,这样我们 index.hml
中对 *.css
或 *.js
文件的任何引用都将是已解决,我们不会遇到 404。
我不确定 react-router
如何在加载 index.html 后接管路径解析,但这超出了这个问题的范围,可能是另一个讨论的话题。
关于hot-reload的第二个问题,我还在摸索中。现在我 运行 hapi 服务器和 react-app 都是独立的,因为我需要 /api
在 react-app 中使用。欢迎任何建议或答案。
这是我的做法。测试了它。版本 "@hapi/hapi": "^20.0.1"
.
const path = require("path")
const Hapi = require('@hapi/hapi')
const Boom = require('@hapi/boom');
const server = Hapi.server({
port: 3000,
host: '0.0.0.0',
routes: {
files: {
relativeTo: path.join(__dirname, 'YOU BUILD REACT DIR')
}
}
});
(async () => {
await server.register([
require('vision'),
require('inert')
]);
server.route(
[{
method: 'GET',
path: '/{path*}',
options: {
ext: {
onPreResponse: {
method(req, h) {
//for other path prefix /Api
const isApi = req.path.substr(1)
.toLowerCase()
.trim()
.split('/')[0]
.replace(/\//g, "") === "api"
const response = req.response
if (response && req.response.output && req.response.output.statusCode === 404) {
if (isApi)
return Boom.notFound("Not Found")
return h.file('index.html');
}
return h.continue
},
}
}
},
handler: {
directory: {
path: ".",
listing: false,
index: true
}
}
},
{
method: 'GET',
path: '/Api/test',
handler: () => "OK"
}
])
await server.start();
console.log('Server running on %s', server.info.uri)
})()