【问题标题】:Angular: Reloading/URL navigation reverts to default routeAngular:重新加载/URL导航恢复到默认路由
【发布时间】:2016-12-05 08:45:53
【问题描述】:

我将 Angular 1.3.10、ui-router 0.2.10 和 Express 4.14.0 用于基本的 Reddit 克隆,但在路由方面遇到了问题。

我的(缩写)特快路线:

router.get('/api/home', function (req, res, next) {
  res.render('index', {
    title: 'Meanit'
  });
});

router.get('*', function (req, res, next) {
  res.redirect('/api/home');
});

我的 Angular 状态配置:

app.config([
  '$stateProvider',
  '$urlRouterProvider',
  '$locationProvider',
  function ($stateProvider, $urlRouterProvider, $locationProvider) {
    $stateProvider
      .state('home', {
        url: '/home',
        templateUrl: '/views/home.html',
        controller: 'MainCtrl',
        resolve: {
          postPromise: [
            'posts',
            function (posts) {
              return posts.getAllPosts();
            }
          ]
        }                      
      })
      .state('posts', {
        url: '/posts/{id}',
        templateUrl: '/views/posts.html',
        controller: 'PostsCtrl',
        resolve: {
          post: [
            '$stateParams',
            'posts',
            function ($stateParams, posts) {
              return posts.getPost($stateParams.id);
            }
          ]
        }
      })
      .state('register', {
        url: '/register',
        templateUrl: '/views/register.html',
        controller: 'AuthCtrl',
        onEnter: [
          '$state',
          'auth',
          function ($state, auth) {
            if (auth.isLoggedIn())
              $state.go('home')
          }
        ]
      })
      .state('login', {
        url: '/login',
        templateUrl: '/views/login.html',
        controller: 'AuthCtrl',
        onEnter: [
          '$state',
          'auth',
          function ($state, auth) {
            if (auth.isLoggedIn())
              $state.go('home')
          }
        ]
      });

    $locationProvider.html5Mode(true);
    $urlRouterProvider.otherwise('home');
  }
]);

我的文件夹层次结构如下所示:

meanit
  public
    js
      app.js (Angular)
  routes
    index.js (Express routes)
  views (Angular templates)
    index.html
    home.html
    posts.html
    register.html
    login.html
  server.js

所有路由都按预期工作,但是当我在其中一个路由上重新加载页面或直接导航到路由 URL (/posts/579d17934b0f5f6b2ff5c72c) 时,我首先通过 Express 重定向到 /api/home(预期,我认为),然后通过 Angular 而不是 /posts/579d17934b0f5f6b2ff5c72c 路线(不打算)到达 /home。

如何强制 URL 导航/重新加载停留在子路由上?

(我查看了AngularJS. Retain state after page reload,但我不明白如何设置 URL 解析/如何根据接受的答案调整代码以适合我的项目。)

【问题讨论】:

  • 您如何处理静态资源(javascript、css、html、图像等)? express 是否为他们提供服务,还是您使用其他网络服务器(如 nginx)?
  • 对express不太熟悉,但在我看来你不希望express重定向URL。当 express 将您发送到 /api/home 时,angular 无法识别它,因为它不是您列出的状态,所以您最终会到达 /home
  • @kennasoft:我正在使用 Express(公共和视图文件夹)提供静态数据。
  • @ChrisNewman:抱歉,我已将 Express 路线添加到主帖中。 /api/home 应该呈现 index.html,其中包含我的 Angular 应用程序。
  • 是否有特殊原因需要 express 来进行路由?而不是只使用 ui-router 和 angular?我建议您尝试使用其中一种。否则,每次刷新页面或粘贴 URL 时,您基本上都会被重定向两次(一次用于 express,一次用于 ui-router)。

标签: javascript angularjs node.js express angular-ui-router


【解决方案1】:

当我开始我的一个 angularjs 项目时,我遇到了类似的问题。就我而言,我运行了 2 个不同的服务器;一个用于 API,另一个专用于提供静态文件。这是我的快速静态服务器的样子:

server.js

//server.js

var express = require('express');

var app = express();

//use very specific paths to the different resource folders
app.use('/js', express.static('public/js'));
app.use('/css', express.static('public/css'));
app.use('/img', express.static('public/img'));
app.use('/views', express.static('public/views'));
app.use('/bower_components', express.static('public/bower_components'));

var port = process.env.PORT || 80;
var staticExtensions = ['css','js','png','gif','jpg','woff','woff2','ttf','map'];
var deeperPaths = ['/posts']; //an array of deeper paths that need special treatment

//cater specifically for post, since it's deeper than other paths (relative to the other assets /css, /js etc)
app.get('/posts/:postId', function(req,res){
    console.log('fetching matched request: '+ req.path + '...');
    res.sendFile(__dirname +'/public/index.html');
});

//any other request returns the index.html file, where angularjs routing takes over
app.get('*', function(req, res) {
    console.log('fetching '+ req.path + '...');
    var filePath = __dirname +'/public/index.html';

    var requestPath = req.path.split('?')[0];
    var fileExtension = requestPath.split('.').pop();
    //if it's a static resource make relative to /public
    if(staticExtensions.lastIndexOf(fileExtension)>-1){
        deeperPaths.forEach(function(path, index){   
           //this is not a very reliable test, but it works for now  
           if(req.path.indexOf(path)===0){
               filePath = __dirname + '/public' + req.path.replace(path, '');
            }
        });
    }
    res.sendFile(filePath); // load our public/index.html file
});

// START THE SERVER
app.listen(port);
console.log('Website started on port ' + port);

希望这会有所帮助...

【讨论】:

  • 不幸的是,我的应用程序具有相同的包罗万象(使用快速路由器),但无法解决问题。我很确定这是不保存路由状态的 Angular 问题?
  • 重新加载整个页面后,状态不可能仍然存在。您可能需要使用 chrome 开发工具的网络选项卡进行检查,以查看服务器没有返回错误的内容。我注意到在我自己的情况下,当请求的 url 比索引文件的位置深一步时(例如 /posts/{id}),我所有的静态资源都开始返回 index.html 文件内容,这是后备。这就是为什么有必要将特定路径映射到每种类型的资源。
  • 请看上面修改后的答案。我知道应该有一个更好、更标准的解决方案来解决这个问题,但这对我有用,直到我切换到使用 nginx 提供静态服务。我刚刚在我的仓库中找到了这段代码。当我意识到处理这样的角度网址会变得混乱时,我切换到了 nginx。
  • 抱歉,我无法理解此修复程序。假设我请求 /posts/somePostId - 它遵循第一条规则并发送 Angular 应用程序,但除非请求 /posts/ 下的静态,否则包罗万象也发送 Angular 应用程序。该修复如何影响直接导航到 /posts/somePostId 的行为?
  • 除了/posts路由,还有其他路由有这个问题吗?完全刷新页面/register 是否会带您回到/home 路线?
【解决方案2】:

看来您的问题与快递有关。您的全部内容正在执行 res.redirect(),我认为它会更新浏览器 url。我建议你只做一个简单的 sendfile() 或 render(),而不是 redirect()。

您的快速服务器总括路由应更改为:

//This is assuming the index.html file exists on the same directory the server is launched from
router.get('*', function (req, res, next) {
    res.render('index', {
        title: 'Meanit'
    });
});

【讨论】:

  • 你完全正确!我将 Express 路由更改为直接使用 res.render 而不是重定向回 /api/home 路由,现在它可以完美运行了。感谢您的所有帮助!
  • 很高兴我们终于找到了问题所在,您可以继续构建您的应用程序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-27
  • 1970-01-01
  • 2019-10-02
  • 2016-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多