问题
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.
回答1:
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.
回答2:
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.
回答3:
Can you try adding the below code in both of your HTML and iFrame page (in the HTML DOC) and check if it works?
<script>document.domain = 'myDomain.com'</script>
Note: Please replace the 'myDomain' with appropriate domain name of the domain you are using (the origin)
回答4:
Making AJAX requests appears to be absolutely impossible from a sandboxed iframe without the allow-same-origin
option.
See this answer for a detailed explanation: IFRAME sandbox attribute is blocking AJAX calls
However, I'm not quite convinced about it. Before giving up, make sure that your server accepts AJAX requests from a different hostname without sandboxing (ie. if it supports CORS).
For more info about CORS see: http://www.html5rocks.com/en/tutorials/cors/
回答5:
The error your are getting:
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.
is because your application have been secured from the clickjacking attacks. In your case X-Fame-Options
in your application web.config is probably set to Deny
, setting it to 'SAMEORIGIN' would help fix your problem, provided you have your application has the same domain as your iframe
.
This is how its done:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN" />
</customHeaders>
</httpProtocol>
</system.webServer>
If you are able find a work around for this (I mean make your application work in iframe with Deny option set), then it would defeat the sole purpose (security against clickjacking) of having such a feature.
Hope this helps.
来源:https://stackoverflow.com/questions/29633898/header-not-being-set-for-options-ajax-request