我有一个应用程序站点(NodeJS),我想从Express迁移到Hapi,我通常做的是提供静态文件并将其他所有内容路由到包含angularjs应用程序和角度路由配置的单个页面。 / p>
// Express routing, first the static files
app.use( express.static(__dirname + '/public') );
// Second the api routes
app.get('/api', function(req, res){
res.send( {api: 'response' } )
});
// Finally everything else maps to the single page app:
app.get('*', function(req, res){
res.sendfile('./public/html/controllers.index.html')
});
在HapiJS中,我不知道如何复制相同的代码(不使用express.static中间件),因为:
Hapi = require('hapi');
var server = new Hapi.Server('localhost', 84);
server.route({
method: 'GET',
path: '/{p*}',
handler: function (request, reply) {
reply.file('public/html/index.html');
}
});
在上面的代码中,每个请求无论将映射到我的单个页面('public / html / index.html'),但如果我这样做,那么js,css,jpg&文件将映射到同一个文件而不是脚本,样式和图像(请求'/images/bg.png'将下载单页而不是图像文件)。
我知道如果我将路径'/'设置为我的单页,然后'{p *}'设置为'{directory:{path:'/ public'}}',那么我将拥有我的行为需要,但有一个问题,如果一些用户复制并粘贴一个特定的网址(比如'/ account / login'),然后按回车键,那条路线将被映射到HapiJS,响应将是'未找到(404)' ,角度路由永远无法响应。
有人知道如何解决这个问题吗?
问题的关键部分是:
答案 0 :(得分:7)
不确定这是否会帮助你,但你的起始代码对于Hapi.js来说有点“奇怪”。这就是我用来设置一个简单的hapi.js SPA。
如果您希望使用特定的URL(如帐户/登录),则必须将路径指向该特定部分。(路径:'/ account / login')
不同之处在于我指向整个目录,包括。不同的文件,您只需回复index.html文件。使用listing参数可以决定是否要在网址中显示目录结构。默认为false。
此处有更多信息:http://hapijs.com/tutorials/serving-files#directory-handler
var Hapi = require('hapi');
var Path = require('path');
var server = new Hapi.Server(8080, 'localhost');
server.route({
method: 'GET',
path: '/{path*}',
handler: {
directory: {
path: './public',
listing: false,
index: true
}
}
});
server.start(function(){
console.log('server started');
});
答案 1 :(得分:5)
受inert documentation的启发,我通过提供静态目录中的所有内容解决了这个问题。然后我添加了一个onPostHandler来在每次返回404时返回索引文件。然后,客户端路由器可以将重定向发送到静态文件目录中的现有404.html文件。
// Static Assets
server.route({
method: 'GET',
path: '/{param*}',
handler: {
directory: {
path: ['app/static'],
listing: false,
index: ['index.html']
}
}
});
// return index.html for everything else
server.ext('onPostHandler', (request, reply) => {
console.log('WORD');
const response = request.response;
if (response.isBoom && response.output.statusCode === 404) {
return reply.file('app/static/index.html');
}
return reply.continue();
});
答案 2 :(得分:2)
此答案无效。正如@Al jey在评论中所说。 Hapi有自己的算法来排序路线,请不要按照这个答案。
与expressJS类似,Hapi按顺序处理路线。只需按优先级定义路线顺序:
server.route(
{ // Angular/API Route
method: 'GET',
path: '/api',
handler: function (request, reply) {
reply( {api: 'response' } )
}
});
server.route({ // Other assets If you have
method: 'GET',
path: '/assets/{param*}',
handler: {
directory: {
path: './assets',
listing: false,
index: true
}
});
server.route({ // Everything else
method: 'GET',
path: '/{p*}',
handler: function (request, reply) {
reply.file('public/html/index.html');
}
});
答案 3 :(得分:1)
我在惰性方面取得了成功,如here所述。如果向下滚动,可以找到"目录处理程序"。
部分我的解决方案看起来像这样:
var Hapi = require('hapi');
var Path = require('path');
var server = new Hapi.Server();
server.connection({
host: 'localhost',
port: 8001
});
server.register(require('inert'), (err) => {
if (err) {
throw err;
}
server.route({
method: 'GET',
path: '/{param*}',
handler: {
directory: {
path: 'public'
}
}
});
server.start((err) => {
if (err) {
throw err;
}
console.log('Server running at:', server.info.uri);
});
});
答案 4 :(得分:1)
确保你有一个惰性的插件。
在您的server.js(或您命名的任何内容)中,配置提供静态文件的相对路径,见下文
const server = new Hapi.Server({
connections: {
routes: {
cors: true,
files: {
relativeTo: Path.join(__dirname, 'public')
}
},
router: {
stripTrailingSlash: true
}
}
})

然后为您的路线注册一个新的路线插件,如下所示。这假设您输入index.html(对于React或Angular)位于上面配置的公共目录中
exports.register = (server, options, next) => {
server.route([{
method: 'GET',
path: '/{param*}',
handler: {
directory: {
path: '.',
redirectToSlash: true,
listing: false,
index: true
}
}
}])
server.ext('onPostHandler', (req, res) => {
const response = req.response
if (response.isBoom && response.output.statusCode >= 404) {
return res.file('index.html')
}
return res.continue()
})
next()
}
exports.register.attributes = {
name: 'static-route',
version: '1.0.0'
}

现在,每当HapiJS抛出404错误时,路由就会被转发到您的React / Angular App,然后它可以处理路径(如果存在)。
答案 5 :(得分:0)
适用于使用Hapi @ 18和Inert的人。
const server = Hapi.server({
port: 3000,
routes: {
files: {
relativeTo: Path.join(__dirname, 'build'),
}
}
});
server.route({
method: 'GET',
path: '/static/{param?}',
handler: {
directory: {
path: '.',
redirectToSlash: true,
}
}
});
server.route({
method: 'GET',
path: '/{any*}',
handler: {
file: 'index.html'
}
});
我的./build
包含所有JS资产和index.html
。 index.html
请求入口点./build/main.js
作为/static/main.js
。其余脚本是相对的。