【问题标题】:Header not being set for OPTIONS Ajax request没有为 OPTIONS Ajax 请求设置标头
【发布时间】:2015-06-20 10:48:08
【问题描述】:

我有一个ascx 页面GetToken.ashx

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

当我 AJAX 到这个页面时,它返回以下标题:

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

当发出 AJAX 请求的页面放置在沙盒 iFrame 中时,会显示错误:

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.

并返回标题:

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

我似乎无法获得 OPTIONS 添加标头的请求。将allow-same-origin 添加到沙盒属性会将请求更改为GET,但我不希望授予 iFrame 这些权限。

【问题讨论】:

    标签: asp.net ajax iis-7 get access-control


    【解决方案1】:

    我假设您打算写ashx,而不是ascxProcessRequest (HttpContext context) 方法的存在表明它是一个通用处理程序,而不是用户控件。

    我制作了一个非常简单的页面来测试:

    <%@ 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>
    

    我在http://localhost:49253/SandboxTest.aspx 上加载页面。然后页面向http://localhost:49253/Handler/testCors.ashx 发出ajax 请求,并将其输出放入testCorsDiv div。这会为处理程序生成一个直接的GET(因为它来自同一来源)并插入输出。

    页面中还有一个沙盒 iframe,它使用 URL http://127.0.0.1:49253/SandboxTest.aspx 加载相同的页面。 ?sandboxed=true 用于防止 iframe 递归加载内部 iframe。然后,在 iframe 中加载的页面将尝试向 http://127.0.0.1:49253/Handler/testCors.ashx 发出 ajax 请求,并在其自己的 testCorsDiv div 副本中显示输出。

    只要沙盒 iframe 有 allow-scripts 这就像一个魅力。 iframe 生成一个如下所示的 OPTIONS 请求(来自 Fiddler,使用 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
    

    我的testCors.ashx 处理程序然后吐出一些标头,说这看起来不错,然后浏览器跟进GET,它就可以工作了。

    testCors.ashx 这样做:

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

    所以我的测试表明应该可以做你想做的事。尽管这可能是一个问题,但如果您的处理程序只能由经过身份验证/授权的用户访问,那么这可能是一个问题。如您所见,OPTIONS 请求没有向处理程序发送 cookie。但另一方面,您的问题表明对您的选项请求的响应是Status Code:200。我想如果缺少所需的身份验证 cookie,那将是一些 4**

    结束,我真的不知道您的情况出了什么问题,但也许(?)我的简单示例页面可以为您提供一些线索,帮助您自己找到问题。

    【讨论】:

    • 谢谢你,使用你的例子我设法简单地重现了问题,然后通过一些调整让它工作了!
    • @TomGullen 很高兴我的回答对您有所帮助。并感谢您的赏金,即使我不确定我是否应得的感谢,因为我并没有真正解决您的问题...
    【解决方案2】:

    确保您的 IIS 设置允许 OPTION 访问该处理程序 - 部署到应用程序池名称为“web-app”的应用程序,并且相应的处理程序映射应允许 OPTION 请求。

    以下是执行此操作的步骤。

    • 选择所需的应用程序池
    • 点击处理程序映射
    • 选择 *.ashx 并双击相应的处理程序,点击 Request Restriction ,看看那里有没有选项动词,如果没有,添加。

    上面提到的这里-http://www.chrisweldon.net/blog/2012/04/13/jquery-file-uploader/

    您可能需要使用以下代码。

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

    我已经在my blog 中解释了这一点。这适用于 WCF,但它也适用于您的情况!您可能需要将 * 允许的来源更改为请求的来源,因为 * 存在安全问题,它允许所有域进行 CORS 调用。

    【讨论】:

    • 我所有的 ASHX 处理程序都有 OPTION 动词,并且我使用了上面的代码。它仍然无法正常工作! No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
    • 这可能是一个愚蠢的建议,您可以尝试添加null 代替* 吗?
    【解决方案3】:

    您能否尝试在您的 HTML 和 iFrame 页面(在 HTML DOC 中)中添加以下代码并检查它是否有效?

    <script>document.domain = 'myDomain.com'</script>
    

    注意:请将“myDomain”替换为您正在使用的域的适当域名(来源)

    【讨论】:

      【解决方案4】:

      如果没有 allow-same-origin 选项,从沙盒 iframe 发出 AJAX 请求似乎是绝对不可能的。

      详细解释请看这个答案:IFRAME sandbox attribute is blocking AJAX calls

      但是,我对此不太相信。在放弃之前,请确保您的服务器接受来自不同主机名的 AJAX 请求而没有沙箱(即,如果它支持 CORS)。

      有关 CORS 的更多信息,请参阅:http://www.html5rocks.com/en/tutorials/cors/

      【讨论】:

        【解决方案5】:

        你得到的错误:

        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.
        

        是因为您的应用程序已免受点击劫持攻击。在您的情况下,您的应用程序 web.config 中的 X-Fame-Options 可能设置为 Deny,将其设置为“SAMEORIGIN”将有助于解决您的问题,前提是您的应用程序与您的 iframe 具有相同的域。

        这就是它的完成方式:

        <system.webServer>
              <httpProtocol>
                 <customHeaders>
                    <add name="X-Frame-Options" value="SAMEORIGIN" />
                 </customHeaders>
              </httpProtocol>
        </system.webServer>
        

        如果您能够找到解决此问题的方法(我的意思是让您的应用程序在设置了拒绝选项的 iframe 中运行),那么它将破坏拥有此类功能的唯一目的(防止点击劫持)。

        希望这会有所帮助。

        【讨论】:

          猜你喜欢
          • 2019-10-13
          • 1970-01-01
          • 2015-07-17
          • 1970-01-01
          • 2015-10-30
          • 2013-01-09
          • 2014-11-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多