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

Posted

技术标签:

【中文标题】CORS Post 请求在本地工作但不在服务器上【英文标题】:CORS Post request working locally but not on server 【发布时间】:2015-02-14 04:49:12 【问题描述】:

我在同一个解决方案中有两个项目。一个是 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 标头,但据我所知应该如此。我是否需要在服务器上做任何进一步的配置,或者我错过了什么?提前谢谢你。

【问题讨论】:

您是否尝试过使用 config.EnableCors() 或 config.EnableCors("","","*")? 【参考方案1】:

您似乎没有处理预检Options请求

Web API 需要响应Options 请求,以确认它确实配置为支持CORS

要处理这个问题,您需要做的就是发回一个空响应。您可以在您的操作中执行此操作,也可以像这样在全局范围内执行此操作:

protected void Application_BeginRequest()

    if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
    
        Response.Flush();
    

添加了这项额外检查以确保不会利用设计为仅接受 GETPOST 请求的旧 APIs。想象一下,当这个 动词 不存在时,向 API 发送一个 DELETE 请求。结果是不可预测的,结果可能是危险的

我还建议通过 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>

请注意,方法都是单独指定的,而不是使用*。这是因为使用*时出现了一个bug。

【讨论】:

感谢您的回答。它帮助很大。现在 OPTIONS 请求返回状态码 200。但是如果您查看开发人员工具中的响应,它会返回一个错误,指出“服务器在发送 HTTP 标头后无法设置状态。”。然后上传开始并成功处理。虽然有效,但出现的错误似乎有点奇怪。你有什么解释吗? 您可以尝试在Response.Flush(); 之后使用Response.End();。此外,您应该调查您的 Web API 的其他部分是否在 Application_BeginRequest 之前设置标头。

以上是关于CORS Post 请求在本地工作但不在服务器上的主要内容,如果未能解决你的问题,请参考以下文章

cors 在本地主机上工作,但不在生产上

CORS AngularJS 不使用 POST 或 DELETE 发送 Cookie/凭据,但 GET OK

CORS 正在阻止 PUT、DELETE 和 POST 请求,但 GET 正在工作

向本地nodeJS服务器发出发布请求时出现AngularJS CORS错误

发出 GET 请求时没有 CORS 错误,但发出 POST 请求时出现 CORS 错误

本地 Javascript Fetch Post 请求失败,调用 ASP.NET Core 2.2 Web API。 CORS 已启用