Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Header not being set for OPTIONS Ajax request

I have an ascx page GetToken.ashx.

public void ProcessRequest (HttpContext context) {
    context.Response.ContentType = "text/plain";
    context.Response.AppendHeader("Access-Control-Allow-Origin", "*");
    context.Response.Write(Token.CreateToken());
}

When I AJAX to this page, it returns the following headers:

Request Method:GET
Status Code:200 OK
Access-Control-Allow-Origin:*
Cache-Control:private
Content-Length:36
Content-Type:text/plain; charset=utf-8
Date:Tue, 14 Apr 2015 17:20:53 GMT
Server:Microsoft-IIS/8.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET

When the page that makes the AJAX request is placed in a sandboxed iFrame, it shows the error:

XMLHttpRequest cannot load https://127.0.0.1:112/handlers/gettoken.ashx. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

And returns the headers:

Request Method:OPTIONS
Status Code:200 OK
Allow:OPTIONS, TRACE, GET, HEAD, POST
Content-Length:0
Date:Tue, 14 Apr 2015 17:30:14 GMT
Public:OPTIONS, TRACE, GET, HEAD, POST
Server:Microsoft-IIS/8.5
X-Powered-By:ASP.NET

I cannot seem to get the OPTIONS request to add the header. Adding allow-same-origin to the sandbox properties changes the request to a GET, but I do not wish to grant the iFrame those permissions.

like image 475
Tom Gullen Avatar asked Apr 14 '15 17:04

Tom Gullen


People also ask

How do I get a header from Ajax request?

ajaxSetup({ headers: { 'custom-header': 'some value' } }); // Sends your custom header $. ajax({ url: 'edureka/co' }); // Overwrites the default header with a new header $. ajax({ url: 'edureka/co', headers: { 'some-other-header': 'some value' } }); To add a header to every request then use the beforeSend hook with $.

What are headers in Ajax call?

The headers are additional key-value pairs send along with ajax request using the XMLHttpRequest object. An asynchronous HTTP request to the server by using The ajax() function and by including the header it describes to the server what kind of response it accept.

What is processData in Ajax?

processData. If set to false it stops jQuery processing any of the data. In other words if processData is false jQuery simply sends whatever you specify as data in an Ajax request without any attempt to modify it by encoding as a query string.

What does get response header does in Ajax?

getResponseHeader() The XMLHttpRequest method getResponseHeader() returns the string containing the text of a particular header's value.


2 Answers

I assume that you meant to write ashx, not ascx. The presence of the ProcessRequest (HttpContext context) method suggests it's a generic handler and not a user control.

I've made a very simple page to test with:

<%@ Page Language="C#" AutoEventWireup="true" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript" src="Scripts/jquery-1.4.1.js"></script>
</head>
<body>
    <div id="testCorsDiv">
    </div>
    <script type="text/javascript">
        $.ajax({
            type: "GET",
            url: "/Handler/testCors.ashx",
            dataType: "text",
            success: function (theData) { $("#testCorsDiv").text(theData); },
            error: function (theData) { alert('error'); }
        });
    </script>
    <% if(string.IsNullOrEmpty(Request.QueryString["sandboxed"])) { %>
    <iframe src="http://127.0.0.1:49253/SandboxTest.aspx?sandboxed=true" sandbox="allow-scripts" width="600">
    </iframe>
    <% } %>
</body>
</html>

I load the page on http://localhost:49253/SandboxTest.aspx. The page then makes an ajax request to http://localhost:49253/Handler/testCors.ashx and puts the output from that into the testCorsDiv div. This generates a straight GET to the handler (since it's coming from the same origin) and the output gets inserted.

In the page is also a sandboxed iframe which loads the same page using the url http://127.0.0.1:49253/SandboxTest.aspx. The ?sandboxed=true is there to prevent the iframe from recursively loading an inner iframe. The page loaded in the iframe will then try to make an ajax request to http://127.0.0.1:49253/Handler/testCors.ashx and display the output in it's own copy of the testCorsDiv div.

As long as the sandboxed iframe has allow-scripts this works like a charm. The iframe generates an OPTIONS request looking like this (from Fiddler, tested with Chrome):

OPTIONS http://127.0.0.1:49253/Handler/testCors.ashx HTTP/1.1
Host: 127.0.0.1:49253
Connection: keep-alive
Cache-Control: max-age=0
Access-Control-Request-Method: GET
Origin: null
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90     Safari/537.36
Access-Control-Request-Headers: accept, x-requested-with
Accept: */*
Referer: http://127.0.0.1:49253/SandboxTest.aspx?sandboxed=true
Accept-Encoding: gzip, deflate, sdch
Accept-Language: fi-FI,fi;q=0.8,en-US;q=0.6,en;q=0.4

My testCors.ashx handler then spits out some headers that says that this looks ay-ok and the browser then follows up with a GET and it just works.

The testCors.ashx does this:

public void ProcessRequest(HttpContext context)
{
    context.Response.ContentType = "text/plain";
    context.Response.AppendHeader("Access-Control-Allow-Origin", "*");
    context.Response.AppendHeader("Access-Control-Allow-Headers", "content-type, x-requested-with, accept");
    context.Response.AppendHeader("Access-Control-Allow-Methods", "POST, OPTIONS, GET");
    context.Response.Write("Hello World");
}

So my testing suggests that it should be possible to do what you want. One thing though that might be an issue is if your handler is only accessible to authenticated/authorized users. As you can see the OPTIONS request has not sent a cookie to the handler. But on the other hand your question says that the response to you options request is Status Code:200. I suppose that would be some 4** if a required authentication cookie was missing.

Wrapping up, I don't really know what's wrong in your case, but maybe (?) my simple sample page can give you some clues that will help you find the issue yourself.

like image 179
user1429080 Avatar answered Nov 03 '22 06:11

user1429080


Make sure you have IIS setting to allow OPTION to that handler - deployed to app having say App pool name "web-app" and corresponding handler mapping should allow OPTION request.

Following are the steps to do that.

  • select required app pool
  • Click on handler mappings
  • select *.ashx and double click on the corresponding handler , click on Request Restriction , see if you have option verb there, if not, add that.

Above mentioned here - http://www.chrisweldon.net/blog/2012/04/13/jquery-file-uploader/

You may need to use following code.

public void ProcessRequest (HttpContext context) {
    context.Response.ContentType = "text/plain";
    context.Response.AddHeader("Access-Control-Allow-Origin", "*");
    // You can try adding requested origin here instead of * like this - Request.Headers["Origin"] or only the specific domain, in your case it is -https://127.0.0.1:112
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        context.Response.AddHeader("Access-Control-Allow-Methods", "POST, PUT, DELETE");
        context.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        context.Response.AddHeader("Access-Control-Max-Age", "1728000");
    }
    context.Response.Write(Token.CreateToken());
}

I have explained this in my blog. This was for WCF, but it should work for your case too! You might need to change * for allowed origin to requested origin, as * has security issue, it allows all domains to make CORS call.

like image 42
Arindam Nayak Avatar answered Nov 03 '22 07:11

Arindam Nayak