CORS Post请求在本地工作但不在服务器上工作

时间:2014-12-15 23:31:55

标签: javascript asp.net-mvc asp.net-web-api cors

我在同一个解决方案中有两个项目。一个是ASP.NET MVC项目,另一个是Web API项目。在我的本地机器上,MVC项目在http://localhost:2302/上运行我使用WebApiConfig.cs文件中的以下代码在Web API项目中启用了CORS:

namespace WebServices
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            var cors = new EnableCorsAttribute("http://localhost:2302", "*", "*");
            config.EnableCors(cors);
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute("ActionApi", "{controller}/{action}/");
        }
    }
}

我还有一个控制器,我有一个如下控制器:

namespace WebServices.Controllers
{
    public class UploadController : ApiController
    {
        private readonly IUploadManager _uploadManager;

        public UploadController(IUploadManager uploadManager)
        {
            _uploadManager = uploadManager;
        }

        [HttpPost]
        public async Task<HttpResponseMessage> UploadImage()
        {
            var result = await _uploadManager.UploadImage(Request);

            return result.Success
                ? Request.CreateResponse(HttpStatusCode.OK, result)
                : Request.CreateResponse(HttpStatusCode.Conflict);
        }
    }
}

UploadImage方法存在于一个存储库类中,我在那里有上传逻辑。最后,我使用XMLHttpRequest JavaScript对象调用我的服务,如下所示:

var xhr = new window.XMLHttpRequest();
var uploadPercent;

xhr.upload.addEventListener('progress', function (event) {
    var percent = Math.floor((event.loaded / event.total) * 100);
    uploadPercent = percent;
}, false);

xhr.onreadystatechange = function (event) {
    if (event.target.readyState === event.target.DONE) {
        if (event.target.status !== 200) {
            console.log('error in uploading image');
        } else {
            var status = JSON.parse(event.target.response);
            var imageGuid = status.returnId;
            var imageUrl = status.returnString;
        }
     }
};

xhr.open('post', 'http://localhost:4797/Upload/UploadImage', true);
var data = new FormData();
var files = $('#uploadInput')[0].files;

for (var i = 0; i < files.length; i++) {
    data.append('file' + i, files[i]);
}

xhr.send(data);

当我在本地计算机上测试时,上面的代码很有用。但是,当我在实际的服务器上部署它时,它不会(当然我已经更改了所有链接到我的域的相应链接 - 也是项目是单独部署但在同一台服务器上)。发送OPTIONS请求时,我收到400 Bad Request状态码。我在互联网上阅读了很多信息,但似乎没有任何帮助。这是浏览器发送的请求:

Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,el;q=0.6
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:api.example.com
Origin:http://example.com
Referer:http://example.com/Account/ExtraDetails/91a832ee-496c-46a7-ac4b-dfb89bbc8fc5
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36

并收到回复:

Cache-Control:no-cache
Content-Length:69
Content-Type:application/json; charset=utf-8
Date:Mon, 15 Dec 2014 22:42:11 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET

我注意到在部署应用程序时没有在响应中创建Access-Control-Allow-Origin标头,但据我所知它应该是。我是否需要在服务器上进行任何进一步的配置,或者我错过了什么?提前谢谢。

1 个答案:

答案 0 :(得分:2)

您似乎无法处理预检Options 请求

Web API需要回复Options请求,以确认其确实已配置为支持CORS

要处理此问题,您需要做的就是发回空响应。你可以在你的行动中做到这一点,或者你可以这样做:

protected void Application_BeginRequest()
{
    if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
    {
        Response.Flush();
    }
}

添加了此额外检查,以确保不会利用仅用于接受APIsGET请求的旧版POST。想象一下,当{em>动词不存在时,向DELETE发送API请求。结果是不可预测的,结果可能危险

另外,我建议 web.config 而不是config.EnableCors(cors);

启用 Cors
<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type" />
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
  </customHeaders>
 </httpProtocol>

请注意, Methods 都是单独指定的,而不是*。这是因为使用*时会出现错误。