我在AngularJS路由中使用html5Mode = true。工作良好。当我使用IE访问该站点时,Angular路由回退到Hashbang URI,如http://example.com/#!/route-name。那一切都很好。除了在Express中我需要知道路由,因为它告诉我从Express提供哪个html文件。 URL的#部分不会发送到服务器。
我的问题是,如何让我的服务器知道在IE中使用hashbang路由请求哪条AngularJS路由?我正在考虑配置Angular以某种方式将路由作为http标头发送,我可以在快递中阅读,但我不知道该怎么做。有什么想法吗?
更新:根据我收到的反馈,让我告诉您该网站有模板。一个用于主页,一个用于所有其他页面。它们都非常不同。根据路线,服务器需要知道何时为主页提供文件以及何时为其他页面提供文件。
答案 0 :(得分:1)
只是要清楚:这不会在主页面请求上发送hashbang。基于HTTP specifications,无法做到这一点。
你可以在后续的AJAX请求中发送它,但这并不能真正帮助你解决这个问题。除了不支持不支持html5mode的浏览器之外,没有其他解决方案。
浏览器不会自动将hashbang发送到服务器,所以是的,您需要手动发送。使用标题是一个不错的选择。
查看docs中的$httpProvider.interceptors
。
你可以为$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(#!
)进行测试,而只是一个哈希,因为小提琴不允许它。
答案 1 :(得分:1)
我遇到了类似的问题,在重定向删除之前我需要URL的参数。由于URL是从原始URL重定向的,因此先前的URL位于referer标头中。
所以我使用这个快速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
。
答案 2 :(得分:0)
根据Sergiu Paraschiv的回答,似乎没有客户端的答案。所以我调查了服务器端解决方案,客户端只需要一件事。确保你总是像在链接到/ xxxxx而不是/#!/ xxxxx的html5Mode中那样进行链接。
然后在html5Mode and IE9 and lower,会发生什么是AngularJS将所有/ xxxxx重定向到/#!/ xxxxx。在Express中,这会生成url /和referer / xxxxx。这是你可以很容易检查的东西。
如果你想迎合IE8及更低版本,那么很遗憾Angular在这个秋季回归场景中使用window.location.href重定向到/#!/ xxxxx。见github / angular.js / src / ng / browser.js第169行。 使用window.location.href会导致IE8降低到not send引用。
这是一个服务器端(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浏览器(按照正则表达式)。