使用 HttpResponseMessage 401 在 ajax 帖子上总是成功
Posted
技术标签:
【中文标题】使用 HttpResponseMessage 401 在 ajax 帖子上总是成功【英文标题】:Always success on ajax post with HttpResponseMessage 401 【发布时间】:2014-01-06 21:28:29 【问题描述】:我总是在客户端的 ajax 帖子上收到 statusCode=200
,而服务器则以 HttpStatusCode.Unauthorized
回答。
我的控制器代码:
public class AccountApiController : ApiController
public HttpResponseMessage Login(HttpRequestMessage request, [FromBody]LoginViewModel loginModel)
return request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Unauthorized login.");
我的 ajax 代码:
$.ajax(
url: '/api/accountapi/login',
type: 'POST',
data: data
)
.done(function (object, status, xhr)
alert("Success: " + xhr.status + " : " + xhr.statusText);
)
.always(function (object)
$("#output").text(JSON.stringify(object, null, 4));
);
结果:带有文本Success: 200 : OK
的警报
和输出窗口:
"Message": "Unauthorized login."
所以,我可以得到文本错误消息,但我需要得到 HttpStatusCode 来处理错误语句。请帮帮我。
有关此问题的更多信息以及 Brock Allen 提供的优雅解决方案: http://brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/
【问题讨论】:
使用您的开发者工具查看请求/响应属性。在 chrome 中转到网络选项卡,发出请求,检查请求 URL 和状态代码。 我得到了:Request URL:http://localhost:31757/api/accountapi/login Request Method:POST Status Code:200 OK
和 X-Responded-JSON:"status":401,"headers":"location":"http:\/\/localhost:31757\/Account\/Login?ReturnUrl=%2Fapi%2Faccountapi%2Flogin"
。 JSON 答案看起来是正确的挖掘方法:)
【参考方案1】:
因为返回的状态为 200,但用户未被授权,另一种选择是在您的 javascript 中检查状态为 401 的 X-Responded-JSON。
.done(function (object, status, xhr)
if (xhr.getResponseHeader("X-Responded-JSON") != null
&& JSON.parse(xhr.getResponseHeader("X-Responded-JSON")).status == "401")
//some message here
return;
【讨论】:
【参考方案2】:您的页面可能会在您返回HttpStatusCode.Unauthorized
后立即被表单身份验证模块重定向到登录页面。
来自 MSDN:
所有未经身份验证的用户都被拒绝访问您的任何页面 应用。如果未经身份验证的用户尝试访问页面,则 表单身份验证模块将用户重定向到登录页面 由表单元素的 loginUrl 属性指定。
登录页面,或者它被重定向到的任何页面,然后提供状态代码 200。
【讨论】:
一切都设置为允许匿名。但是页面无论如何都不会重定向:( 作为测试,尝试将 StatusCode 更改为 Unauthorized 以外的任何值,看看是否有效。我担心这是表单身份验证模块中的设计。 我怀疑你覆盖了allowanonymous,因为你无论如何都返回Unauthorize,所以它们毕竟是不允许的。 Magnus,谢谢,404 和 403 按预期工作。所以问题只存在于 401。 乐于助人!遗憾的是它没有解决您的问题,但希望它提供了您需要继续进行的内容:)【参考方案3】:详细说明 Valin 的评论,并内联 Brock Allen 的解决方案。
线索在于返回的 OK 响应,它在内部将重定向捕获到表单登录:
<b>X-Responded-JSON</b>: "status": 401, "headers": "location":"http:\/\/localhost:50004\/Login?ReturnUrl=%2FClient"
如果您想在服务器上进行修复,而不是抓取此内部错误状态的响应,您可以使用 Brock Allen 在Using cookie authentication middleware with Web API and 401 response codes 上的文章中的解决方案:
通常在使用 cookie 身份验证中间件时,当服务器(MVC 或 WebForms)发出 401 时,响应将转换为 302 重定向到登录页面(由 CookieAuthenticationOptions 上的 LoginPath 配置)。但是当进行 Ajax 调用并且响应是 401 时,将 302 重定向返回到登录页面是没有意义的。相反,您只希望返回 401 响应。不幸的是,这不是我们通过 cookie 中间件获得的行为——响应更改为 200 状态代码,带有 JSON 响应正文和消息:
"Message":"Authorization has been denied for this request."
我不确定此功能的要求是什么。要更改它,您必须通过在 cookie 身份验证中间件上配置 CookieAuthenticationProvider 来控制出现 401 未授权响应时的行为:
app.UseCookieAuthentication(new CookieAuthenticationOptions AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), Provider = new CookieAuthenticationProvider OnApplyRedirect = ctx => if (!IsAjaxRequest(ctx.Request)) ctx.Response.Redirect(ctx.RedirectUri); );
注意它处理 OnApplyRedirect 事件。当调用不是 Ajax 调用时,我们重定向。否则,我们什么也不做,让 401 返回给调用者。
IsAjaxRequest 的检查只是从 katana 项目中的 helper 复制而来:
private static bool IsAjaxRequest(IOwinRequest request) IReadableStringCollection query = request.Query; if ((query != null) && (query["X-Requested-With"] == "XMLHttpRequest")) return true; IHeaderDictionary headers = request.Headers; return ((headers != null) && (headers["X-Requested-With"] == "XMLHttpRequest"));
【讨论】:
这是我一直在寻找的答案。出色的解决方案 - 感谢您的分享!以上是关于使用 HttpResponseMessage 401 在 ajax 帖子上总是成功的主要内容,如果未能解决你的问题,请参考以下文章
无法使用 UTF8 编码转换 HttpResponseMessage
使用 HttpResponseMessage 401 在 ajax 帖子上总是成功
将内容放在 HttpResponseMessage 对象中?