【问题标题】:nodejs hapi single pagenodejs hapi 单页
【发布时间】:2014-12-11 07:51:54
【问题描述】:

我有一个应用程序站点 (NodeJS),我想从 Express 迁移到 Hapi,我通常做的是提供静态文件并将其他所有内容路由到包含 angularjs 应用程序和 angular 路由配置的单个页面。

// 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'}}',那么我将有我的行为需要,但有一个问题,如果某些用户复制并粘贴特定的 url(比如“/account/login”)然后按回车,该路由将映射到 HapiJS 并且响应将是“未找到 (404)” ,角度路由将永远无法响应。

有人知道怎么解决吗?

问题的关键部分是:

  • 仅使用 HapiJS(不使用 express 或其他中间件)
  • 不要路由每条 Angular 路由(只需路由其他尚未路由到单页的所有内容,Angular 可以处理路由)

【问题讨论】:

    标签: node.js angularjs routing hapijs


    【解决方案1】:

    适用于使用 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.htmlindex.html 请求入口点 ./build/main.js/static/main.js。其余的脚本是相互关联的。

    【讨论】:

      【解决方案2】:

      确保你有惰性插件。

      在您的 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,然后它可以处理该路由(如果存在)。

      【讨论】:

      • 如果除此之外还有一个 API 路由会发生什么?我试过了,我认为现在每条路由,包括 API 路由,都会被重定向回来。
      • 这个配置只处理 404 + 错误,所以如果你有一个 api,它不应该重定向,除非你的服务器抛出 404 + 错误(这包括 500 + 错误)。
      • 您可以切换检查状态代码是否 >= 404 的行,以专门检查 404 错误,例如 if (response.isBoom && response.output.statusCode === 404)。希望这会有所帮助
      • 嗨,很遗憾,它不提供任何 api 路由。您可以在此处查看我的示例 github 代码:github.com/7seven7lst/hapi-inert-test 或此处的 stackoverflow 问题:stackoverflow.com/questions/44866806/…
      【解决方案3】:

      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();
      });
      

      【讨论】:

      • 这个对我有用。看起来像是一个非常常见的问题的解决方法,所以我不确定这是否是最干净的解决方案
      【解决方案4】:

      我在惰性方面取得了成功,如 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);
        });
      });
      

      【讨论】:

        【解决方案5】:

        此答案无效。正如@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');
            }
        });
        

        【讨论】:

        • 这实际上是完全错误的,HapiJS 而是通过它们的特异性来处理路由,定义顺序完全无关,不幸的是......
        • @Al jey,是的,你是对的。在我四处挖掘之后,我发现他们有自己的订单,如你所说。我现在正在编辑答案。
        【解决方案6】:

        不确定这是否会对您有所帮助,但您的起始代码对于 Hapi.js 来说有点“奇怪”。这是我用来建立一个简单的 hapi.js SPA 的。

        如果您希望使用特定的 URL,例如帐户/登录名,则必须将路径指向该特定部分。(路径:'/account/login')

        不同之处在于我指向整个目录,包括。不同的文件,您只需回复 index.html 文件。列表参数让您决定是否要在您的 url 中显示目录结构。默认为假。

        更多信息在这里: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');
        });

        【讨论】:

        • 不是真的(差不多一年后),每个404请求都必须在其内容中响应index.html,除了index.html之外的唯一响应应该是实际存在的文件 *处理页面的路由通过angularjs,如果angular中不存在路由,angular会显示404错误。
        • 这不处理客户端路由。刷新页面的意思是 404..
        猜你喜欢
        • 1970-01-01
        • 2018-06-30
        • 2016-01-09
        • 1970-01-01
        • 2014-03-16
        • 2023-04-08
        • 2017-07-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多