1

I'm submitting a standard $.ajax() request like this:

$.ajax({ type: "GET", url: myUrl success: function(data) { $("#replace").html(data) }, error: function (data) { console.warn(data); } }); 

Or the same thing by attaching the handler to the ajax promise callbacks like this:

$.ajax({ type: "GET", url: myUrl }) .done(function(data, status) { console.log(data); }) .fail(function(data, status) { console.warn(status); }); 

In both cases, or when using $.ajaxError() handler, the error/fail function is called when a HTTP status error is returned.


In my ASP.NET MVC project, I'm trying to return the proper HTTP Status Code, both for semantic reasons and to be caught by the right client side handler.

Attempt #1 - As suggested by this answer I've tried to return a HttpStatusCodeResult like this:

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { if (filterContext.HttpContext.Request.IsAjaxRequest()) { filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Unauthorized, accessResult.AccessDeniedMessage); filterContext.HttpContext.Response.End(); } else { base.HandleUnauthorizedRequest(filterContext); } } 

Attempt #2 - Alternatively, as suggested by this answer, I've tried returning a JsonResult and also setting the Response.StatusCode

filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; filterContext.Result = new JsonResult() { Data = new { Error = "Unauthorized User" }, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; filterContext.HttpContext.Response.End(); 

In both cases, the response still comes back as 200 OK

AJAX Status Code Screenshot

Questions:

  • Am I correct about the semantics that I should be returning an AJAX response with a Unauthorized Status Code?
  • Is there somewhere else to set this value that I need to do also?
  • Is there some server level setting to allow non-200 status codes to be returned?

This question on Always success on ajax post with HttpResponseMessage 401 seems to be running into the same error, but doesn't propose a server side solution, instead just allowing the OK error status code and scraping the response to determine if an error occurred.

5
  • Not quite sure why this isn't working as expected, but I do notice that in your picture the Response Headers has a X-Responded-JSON which actually contains your response data as JSON. Maybe try to clear the response first: filterContext.HttpContext.Response.Clear(); Commented Mar 1, 2018 at 16:25
  • @TheMuffinMan, Yeah - I saw that too - I think there are definitely ways to stuff data somewhere into the response and to be able to react appropriately on the client. Lots of people will add Success to their returned Data object, but it's still bothering me from a semantic point of view that the request is unauthorized and still being returned with a 200 status when I've manually specified something else Commented Mar 1, 2018 at 16:29
  • In the first example where you check if type of current request isajaxrequest there could you change your code to filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized; filterContext.HttpContext.Response.End(); and try?probably you are not setting the response. Commented Mar 1, 2018 at 16:31
  • @NavoneelTalukdar, added a call to Response.End() on each attempt and in both cases the return status was still 200 Commented Mar 1, 2018 at 16:38
  • Possible duplicate of Always success on ajax post with HttpResponseMessage 401 Commented Mar 1, 2018 at 17:45

1 Answer 1

1

The offending issue was indeed the same as in Always success on ajax post with HttpResponseMessage 401. The response was returned successfully, but trapped a redirect to a form login

X-Responded-JSON: {"status": 401, "headers": {"location":"http:\/\/localhost:50004\/Login?ReturnUrl=%2FClient"}}

Although that question doesn't seem to suggest a server side solution, instead simply relying on a parsing the error state on the client. Brock Allen suggests a server side fix in his post on Using cookie authentication middleware with Web API and 401 response codes:

Normally when using cookie authentication middleware, when the server (MVC or WebForms) issues a 401, then the response is converted to a 302 redirect to the login page (as configured by the LoginPath on the CookieAuthenticationOptions). But when an Ajax call is made and the response is a 401, it would not make sense to return a 302 redirect to the login page. Instead you’d just expect the 401 response to be returned. Unfortunately this is not the behavior we get with the cookie middleware — the response is changed to a 200 status code with a JSON response body with a message:

{"Message":"Authorization has been denied for this request."} 

I’m not sure what the requirement was for this feature. To alter it, you must take over control of the behavior when there is a 401 unauthorized response by configuring a CookieAuthenticationProvider on the cookie authentication middleware:

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); } } } }); 

Notice it handles the OnApplyRedirect event. When the call is not an Ajax call, we redirect. Otherwise, we do nothing which allows the 401 to be returned to the caller.

The check for IsAjaxRequest is simply copied from a helper in the katana project:

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")); } 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.