【问题标题】:AngularJS html5Mode fallback in IE. Express server needs to know routeAngularJS html5Mode 在 IE 中的后备。 Express 服务器需要知道路由
【发布时间】:2014-10-05 13:22:47
【问题描述】:

我在 AngularJS 路由中使用 html5Mode=true。工作正常。当我使用 IE 访问该站点时,Angular 路由会退回到像 http://example.com/#!/route-name 这样的 Hashbang URI。没关系。除了在 Express 中,我需要知道路线,因为它告诉我要从 Express 提供哪个 html 文件。 url的#部分不发送到服务器。

我的问题是,如何让我的服务器知道在 IE 中使用 hashbang 路由请求哪个 AngularJS 路由?我正在考虑以某种方式配置 Angular 以将路由作为我可以快速读取的 http 标头发送,但我不知道该怎么做。有什么想法吗?

更新:根据我得到的反馈,让我告诉你该网站有模板。一个用于主页,一个用于所有其他页面。他们都非常不同。根据路由,服务器需要知道何时为首页提供文件,何时为其他页面提供文件。

【问题讨论】:

  • 你不是用$routeProvider来处理路由吗?
  • @RahilWazir 是的,我是。

标签: angularjs internet-explorer angularjs-routing hashbang


【解决方案1】:

要明确一点:这不会在主页请求上发送 hashbang。 基于HTTP specifications,没有办法这样做。

您可以在随后的 AJAX 请求中发送它,但这并不能真正帮助您解决这个问题。除了不支持不支持html5mode的浏览器,没有其他解决办法。

浏览器不会自动将 hashbang 发送到服务器,所以是的,您需要手动发送。使用标题是一个不错的选择。

看看$httpProvider.interceptors中的docs。

您可以为 $http 注册一个请求拦截器(AngularJS 在内部使用它来处理任何 AJAX 请求,您也应该如此)附加一个自定义标头。然后,您可以使用 $location.path() 将该标头值设置为实际的 hashbang:

var app = angular.module('MyApp',[]);

app.factory('httpInterceptor', function($q, $location) {
    return {
        'request': function(config) {
            if(config.url.indexOf('product')) {
                config.headers.Hashbang = $location.path();
            }
            return config;
        }
    };
});

app.config(function($httpProvider) {
    $httpProvider.interceptors.push('httpInterceptor');
});

app.controller('Ctrl', function($scope, $http) {
    $http({method: 'GET', url: '/echo/json/'}).
    success(function(data, status, headers, config) {
        console.log(data);
    });
});

这里是the fiddle。你可以test it like so。在开发者工具中查看发送的标头。

请注意,我没有使用真正的 hashbang (#!) 进行测试,而只是使用哈希,因为小提琴不允许这样做。

【讨论】:

  • 这看起来很有帮助。那确实只向 AJAX 请求添加标头,对吗?我需要将标头添加到实际页面请求中。像这样写出来让我觉得这甚至是不可能的。另一种解决方案是使用查询而不是哈希进行角度路由?所以example.com/?route=route-name
  • 不,抱歉,您将无法在初始请求中发送它。那是浏览器发送的请求,HTTP 规范说它不应该发送散列。我知道我的回答在这方面可能对你没有帮助。这就是为什么 AngularJS 不支持 IE7 和更早版本并且 v1.3 也将放弃 IE8 支持的原因之一。
  • 还有另一种使用 Angular 进行路由的方法,比如使用查询而不是哈希?如:example.com/?route=route-name
  • 不,那也行不通。在任何浏览器中更改 URL(hashbang 之前的内容,或者如果您不使用 hashbang 的任何内容)都会使用新的 URL 触发对服务器的 GET 请求。 HTML5 模式基本上允许您在不触发自动 GET 的情况下更改 URL。这就是 AngularJS 的 html5mode 仅适用于实现此 HTML5 API 的较新浏览器的原因。
  • 感谢您的帮助。不也是一个答案,你已经非常彻底。所有客户端选项在这里似乎都用尽了。我在服务器端实现了一些东西,我利用了这样一个事实,即当 html5Mode 在 IE 中不起作用时,Angular 会将所有 /xxxxx 重定向到 /#!/xxxxx。在 express 这使得 url / 和引用 /xxxxx。这是我可以检查和使用的东西。
【解决方案2】:

我有一个类似的问题,我需要 URL 的参数,然后才能被重定向删除。由于 URL 是从原始 URL 以角度重定向的,因此前一个 URL 位于引用标头中。

所以我使用这个 express 3.x 中间件将原始参数从引用者重写为对根 URL 的请求的查询:

var _ = require('lodash');
var url = require('url');
var qs = require('querystring');

app.use(function(req, res, next) {    
    if (req.url === '/' && req.headers && req.headers.referer) {
        var referer = url.parse(req.headers.referer);

        // rewrite original parameters
        _.forEach(qs.parse(referer.query), function(value, key) {
            req.query[key] = value;
        });

        // do something with pathname
        console.log(referer.pathname);
    }
});

您可以对路径执行相同的操作,即referer.pathname。

【讨论】:

    【解决方案3】:

    根据 Sergiu Paraschiv 的回答,似乎没有客户端回答。所以我研究了一个服务器端解决方案,它只需要客户端上的一件事。确保您始终像在链接到 /xxxxx 而不是 /#!/xxxxx 的 html5Mode 中那样链接。

    然后在html5Mode and IE9 and lower 中发生的事情是 AngularJS 将所​​有 /xxxxx 重定向到 /#!/xxxxx。在 Express 中,这使 url / 和referer /xxxxx。您可以很容易地检查到这一点。

    如果你想满足 IE8 及更低版本的需求,不幸的是 Angular 在这个重定向到 /#!/xxxxx 的回退场景中使用了 window.location.href。请参阅github / angular.js / src / ng / browser.js 第 169 行。 使用 window.location.href 会导致 IE8 及更低级别为 not send 的referer。

    这是一个服务器端 (Express 3.x) 解决方案,它从引用者值或 IE8 及更低版本的 previousUrl 会话变量解析 Angular hashbang 路由。

    app.use(function(req, res, next) {
      if (req.url.match(/\/api/))
        return next(); // /api/something should proceed to next in middleware
      console.log(req.url, req.headers)
      //IE does not support html5Mode so /xxxxx is redirected to /#!/xxxxx
      //effectively making the url / and the referer /xxxxx
      //I check for that here and if xxxxx is not home I present page.html
    
      if (req.headers['user-agent'] &&
        req.headers['user-agent'].match(/MSIE ([7-8]{1}[.0-9]*)/) &&
        req.url.match(/^\/[\w-]+$/)
      ) {
        //However IE8 does not report the referer when doing a redirect using window.locarion.href
        //so I store the initially requested url /xxxxx in session...
        req.session.previousUrl = req.url;
        //console.log('IE8 saving the url here', req.session.previousUrl);
      }
      if (req.headers['user-agent'] &&
        req.headers['user-agent'].match(/MSIE ([7-8]{1}[.0-9]*)/) &&
        !req.headers['referer'] &&
        req.url === '/' &&
        req.session.previousUrl &&
        req.session.previousUrl !== '/home'
      ) {
        //continuation on the IE* referer story (aka the next redirected request)...
        //... and checked for the url stored in session here ;)
        return res.sendfile('public\\page.html'); 
      }
      if (req.headers['user-agent'] &&
        req.headers['user-agent'].match(/MSIE ([7-9]{1}[.0-9]*)/) &&
        req.url === '/' &&
        req.headers['referer'] &&
        req.headers['referer'].match(/^https?:\/\/(?:www)?\.example\.com\/(?!home$)([\w-]+)$/)
      ) {
        return res.sendfile('public\\page.html'); 
      }
      if (req.url.match(/\/home|\/$/))
        return res.sendfile('public\\home.html'); //for the home pages we're going to use home.html
    
      res.sendfile('public\\page.html'); //for everything else we're going to use page.html
    });
    

    我确信在某些情况下会失败,但它在我的测试中对我有用,如果失败,那只会在 IE9 浏览器上失败(根据正则表达式)。

    【讨论】:

      猜你喜欢
      • 2018-10-10
      • 2015-05-22
      • 2015-02-25
      • 1970-01-01
      • 2015-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-25
      相关资源
      最近更新 更多