我有一个反向代理,可以检查多个应用程序的全局身份验证。当用户断开连接但仍尝试使用我的应用程序时,代理会发送302响应:
HTTP/1.1 302 Found
Date: Wed, 11 Sep 2013 09:05:34 GMT
Cache-Control: no-store
Location: https://other.url.com/globalLoginPage.html
Content-Length: 561
Content-Type: text/html; charset=iso-8859-1
Via: 1.1 my-proxy.com
Connection: Keep-Alive
在angularJs中,调用错误回调,但响应头为空,状态为0,数据为空字符串。所以似乎我真的无能为力地处理这个反应...... 我已经看到了关于这个主题的几个问题,我仍然不明白发生了什么(CORS因为代理或位置不同的域名?302浏览器行为?)。 特别是这部分来自答案(https://stackoverflow.com/a/17903447/1093925):
注意:如果您的服务器设置了响应代码301或302,您将无法获取Location标头,因为它将自动且透明地跟随XMLHttpRequest对象。
这个XMLHttpRequest对象怎么样?
在一个非常旧版本的Chrome中(不能使用更新的版本)我可以在网络面板中看到相应的请求,但由于没有响应,它似乎失败了。
在最新版本的Firefox中,没有任何进展。
我可以做任何事情,因为我无法更改代理配置和响应吗?
更新
我今天重播了我的场景,并且由于更新版本的firebug,我能够获得有关正在发生的事情的更多细节。
在我的问题中,我离anwser不远:跨领域政策
由于它是我的应用程序发出的HTTP请求,因此浏览器拒绝以下XMLHttpRequest(该应用程序看起来像是同一个请求)。因此错误和空洞的反应
所以我认为我无能为力
答案 0 :(得分:43)
我的应用中遇到了同样的问题。 你真的不能抓住" 302重定向响应。浏览器在Angular得到它之前抓住了它。实际上,当你收到你的回复时 - 已经太晚了。
坏消息:角度平台不是问题。 xmlHttpRequest不支持这种行为,浏览器在您可以执行任何操作之前执行操作。 参考:Prevent redirection of Xmlhttprequest
好消息:有很多方法可以绕过这个问题,通过截取响应 - 并找到一些方法来识别它是你的可爱302.这是一个黑客攻击,但是这是目前你能做的最好的事情。
<强>因此强> 例如,在我的应用程序中,重定向返回到应用程序的login.html页面,在应用程序中,我获得了200状态的响应,响应数据是我的login.html页面的内容。 所以在我的拦截器中,我检查结果是否是一个字符串(通常不是!所以 - 没有效率问题..)如果是这样 - 检查它是否是我的login.html页面。就这样,我可以抓住重定向并按照我的方式处理它。
yourApp.factory('redirectInterceptor', ['$location', '$q', function($location, $q) {
return function(promise) {
promise.then(
function(response) {
if (typeof response.data === 'string') {
if (response.data.indexOf instanceof Function &&
response.data.indexOf('<html id="ng-app" ng-app="loginApp">') != -1) {
$location.path("/logout");
window.location = url + "logout"; // just in case
}
}
return response;
},
function(response) {
return $q.reject(response);
}
);
return promise;
};
}]);
然后将此拦截器插入您的应用程序。像这样的东西:
$httpProvider.responseInterceptors.push('redirectInterceptor');
祝你好运。
答案 1 :(得分:3)
您的302 -Redirect正由浏览器直接处理,您无法直接处理它。但是,您可以使用httpInterceptor
来帮助您。你需要在你的应用程序DI列表中包含$httpProvider
,然后在你的配置函数中的某个位置像这样引用它:
$httpProvider.responseInterceptors.push('HttpInterceptor');
示例拦截器如下所示:
window.angular.module('HttpInterceptor', [])
.factory('HttpInterceptor', ['$q', '$injector',
function($q, $injector) {
'use strict';
return function(promise) {
return promise.then(success, error);
};
function success(response) {
return response;
}
function error(response) {
var isAuthRequest = (response.config.url.indexOf('/v1/rest/auth') !== -1);
//if we are on the authenticating don't open the redirect dialog
if (isAuthRequest) {
return $q.reject(response);
}
//open dialog and return rejected promise
openErrorDialog(response);
return $q.reject(response);
}
function openErrorDialog(response) {
$injector.get('$dialog').dialog({
backdropFade: true,
dialogFade: true,
dialogClass: 'modal newCustomerModal',
resolve: {
errorData: function() {
return response.data;
},
errorStatus: function() {
return response.status;
}
}
})
.open('/views/error-dialog-partial.htm',
'errorDialogController')
.then(function(response) {
if (response) {
window.location = '/';
}
});
}
}
]);
答案 2 :(得分:1)
我有一个非常类似的问题,并考虑了Ofer Segev提供的解决方案,但是检查响应的内容以查看它是否与另一个页面的html片段相匹配,这对我来说似乎太过分了。当有人更改该页面时会发生什么?
幸运的是,我也控制了后端,所以我没有返回302(重定向),而是返回403(Forbidden),并在标题中传递了所需的位置。与302不同,403将在您的错误处理程序中处理,您可以在其中决定下一步该做什么。这是我的结果处理程序:
function ($scope, $http) {
$http.get(_localAPIURL).then(function (response) {
// do what I'd normally do
}, function (response) {
if (response.status == 403)
{
window.location.href = response.headers().location;
}
else
{
// handle the error
}
答案 3 :(得分:1)
仅供参考,以防万一仍然有人在看这个:您还可以拨打预期从iframe返回302的呼叫。这样,您就可以停留在页面上,并且可以与https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
进行交流答案 4 :(得分:0)
如上所述,由于xmlHttpRequest不支持返回重定向,因此302对Angular不可用。浏览器在执行任何操作之前会起作用。
除了处理自定义数据响应和覆盖状态代码外,
您可以使用更通用的解决方案并添加自定义重定向标头,例如X-Redirect
并对其进行操作。 X-Redirect
的值应该是您要重定向到的网址,例如https://other.url.com/globalLoginPage.html
$http.get(orig_url).then(function(response) {
// do stuff
}, function (response) {
var headers = response.headers();
if ('x-redirect' in headers)
{
document.location.href = headers['x-redirect'];
}
return response;
}
}
对于更全面的解决方案,您还可以使用HTTP拦截器
app.factory('myHttpInterceptor', function ($q, myCache) {
return {
request: function (config) {
return config;
},
response: function(response){
var headers = response.headers();
if ('x-redirect' in headers)
{
document.location.href = headers['x-redirect'];
}
return response;
},
responseError: function(rejection) {
switch(rejection.status)
{
case 302:
// this will not occur, use the custom header X-Redirect instead
break;
case 403:
alert.error(rejection.data, 'Forbidden');
break;
}
return $q.reject(rejection);
}
};
});
您可以设置自定义标头服务器端。
例如,如果您使用的是PHP Symfony:
$response = new Response('', 204);
$response->headers->set('X-Redirect', $this->generateUrl('other_url'));
return $response;