在使用 web api 时,我的 Angular 项目中的预检响应具有无效的 http 状态代码 404

Posted

技术标签:

【中文标题】在使用 web api 时,我的 Angular 项目中的预检响应具有无效的 http 状态代码 404【英文标题】:Response for preflight has invalid http status code 404 in my angular project while consuming web api 【发布时间】:2018-07-19 23:15:50 【问题描述】:

我知道这是 CORS 问题。我在 web api 服务器端启用了 cors。 Get 方法工作正常,但在处理 post 方法时我遇到了问题。请有人在 web api 和客户端上用非常简单的帖子示例回答我。解释如何处理预检、选项等。

控制台

1) zone.js:2935 选项http://localhost:49975/api/Add_Client_/postgoals 404(未找到)

2) 无法加载 http://localhost:49975/api/Add_Client_/postgoals:预检响应包含无效的 HTTP 状态代码 404。

web.config

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*"/>
    <add name="Access-Control-Allow-Headers" value="Origin, Content-Type, X-Auth-Token"/>
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    <add name="Content-Type" value="application/json"/>

    <add name="Access-Control-Allow-Credentials" value="true" />
  </customHeaders>
</httpProtocol>

角度发布方法

    save_Goals()

  let headers : Headers= new Headers();
  //headers.append('Content-Type','application/x-www-form-urlencoded');
  //headers.append("Access-Control-Allow-Origin","true");
  headers.append('Content-Type', 'application/json');

  headers.append('Access-Control-Allow-Origin','*');
  headers.append('Access-Control-Allow-Methods','GET,PUT,POST,DELETE');
  headers.append('Access-Control-Allow-Headers','Content-Type');

  let options = new RequestOptions( headers: headers );

    return this._http.post('http://localhost:49975/api/Add_Client_/postgoals', goal:'foo',options)
   .map(res =>  res.json());
  

谢谢!

【问题讨论】:

通常 CORS 问题不会出现 404 错误(除非手动设置服务器端)。他们甚至可以带有 200 ok 状态。控制台中的 CORS 消息是什么?添加一些细节也会有所帮助,例如是否添加了自定义标题?什么是响应头? (不显示合理值) 是的,我在 web.config 文件中添加了自定义标头。 请编辑原始问题,cmets 中的代码很难阅读。因此,除其他事项外,发出OPTIONS 请求以检查服务器是否允许自定义标头,您是否允许它们?知道确切的 CORS 错误(如果有)仍然有用。 我已经编辑了这个问题..请通过,我坚持了很多天。 【参考方案1】:

我终于找到了解决办法。我所做的是从 web.config 文件中删除了自定义标头。即,

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*"/>
    <add name="Access-Control-Allow-Headers" value="Origin, Content-Type, X-Auth-Token"/>
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    <add name="Content-Type" value="application/json"/>

    <add name="Access-Control-Allow-Credentials" value="true" />
  </customHeaders>
</httpProtocol>

删除了此内容

WebApiConfig.cs 中我做了以下更改

var enableCorsAttribute = new EnableCorsAttribute(origins:"*",headers:"*",methods:"*");

            var json = config.Formatters.JsonFormatter;

            json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
            config.Formatters.Remove(config.Formatters.XmlFormatter);

            config.EnableCors(enableCorsAttribute);

控制器看起来像这样。

[EnableCors(origins: "*", headers: "*", methods: "*", SupportsCredentials = true)]
    [RoutePrefix("api/Add_Client_")]
    public class Add_Client_Controller : ApiController
    
[AcceptVerbs("POST")]

        [HttpPost]
        [Route("PostGoals")]
        public string PostGoals(string goal)
        
            Goal g = new Goal();
            g.Goals = goal;
            db.Goals.Add(g);
            int res = db.SaveChanges();

            return ("Success");
        

Angular POST 方法如下所示

 save_Goals()

  let headers : Headers= new Headers();
        headers.append('Content-Type','application/x-www-form-urlencoded');
    headers.append('Access-Control-Allow-Origin','*');
      headers.append('Access-Control-Allow-Methods','GET,PUT,POST,DELETE');
      headers.append('Access-Control-Allow-Headers','Content-Type');

      let options = new RequestOptions( headers: headers );
    return this._http.post('http://localhost:49975/api/Add_Client_/PostGoals?goal=check',options)
       .map(res =>  res.json());
    

这是通过 URL 发送数据的解决方法。

【讨论】:

【参考方案2】:

你也可以使用 chrome 扩展

https://chrome.google.com/webstore/detail/moesif-origin-cors-change/digfbfaphojjndkpccljibejjbppifbc

设置标题类型 application/x-www-form-urlencoded

let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/x-www-form-urlencoded');
headers.append('Access-Control-Allow-Origin','*');
headers.append('Access-Control-Allow-Methods','GET,PUT,POST,DELETE');
headers.append('Access-Control-Allow-Headers','Content-Type');

【讨论】:

【参考方案3】:

我迟到了,但仍想发布答案,以便对其他人有所帮助。 下面的代码对我来说就像一个魅力!

以下是问题的详细答案:

从 Angular 端将数据传递到 HTTP 标头(请注意,我是 在应用程序中使用 Angular4.0+)。

我们可以将数据传递到标头中的方法不止一种。 语法不同,但意思都一样。

// Option 1 
 const httpOptions = 
   headers: new HttpHeaders(
     'Authorization': 'my-auth-token',
     'ID': emp.UserID,
   )
 ;


// Option 2

let httpHeaders = new HttpHeaders();
httpHeaders = httpHeaders.append('Authorization', 'my-auth-token');
httpHeaders = httpHeaders.append('ID', '001');
httpHeaders.set('Content-Type', 'application/json');    

let options = headers:httpHeaders;


// Option 1
   return this.http.post(this.url + 'testMethod', body,httpOptions)

// Option 2
   return this.http.post(this.url + 'testMethod', body,options)

在调用中,您可以找到作为标题传递的字段,如下图所示:

    在后端/Web API 端进行更改

添加新的 WebApiConfig 文件并添加以下内容。

public static class WebApiConfig
    
        public static void Register(HttpConfiguration config)
        
            config.EnableCors(new EnableCorsAttribute("http://localhost:4200", headers: "ID", methods: "*")  SupportsCredentials = true ); // In the Header define all the header by comma cepration or you can write * if it works for you.
            /config.EnableCors(enableCorsAttribute);

            // Web API routes
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/controller/id",
                defaults: new  id = RouteParameter.Optional 
            );
        
    

在 Global.asax.cs 文件中添加以下事件

protected void Application_BeginRequest()
        
            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers","ID");// In the Header define all the header by comma cepration or you can write * if it works for you.
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "http://localhost:4200");
                HttpContext.Current.Response.End();
            
        

在 Web API 端,您可以使用以下语句获取该代码:

 if (Request.Headers.Contains("ID"))
            
                var ID= Request.Headers.GetValues("ID").First();
            

您可以按照以下步骤处理以下错误:

对预检请求的响应未通过访问控制检查:否 ''Access-Control-Allow-Origin'' 标头出现在请求的 资源。因此不允许使用原点 ''http://localhost:4200'' 访问

预检响应没有 HTTP ok 状态。

此代码适用于我,我可以在 HTTP 标头中传递 ID,并且我可以在 Web API 端检索。

感谢和快乐编码!

【讨论】:

以上是关于在使用 web api 时,我的 Angular 项目中的预检响应具有无效的 http 状态代码 404的主要内容,如果未能解决你的问题,请参考以下文章

使用 Angular 6 将文件上传到 Web Api C#

使用 angular js 和 c# 使用 web api

Angular 8 使用 ASP NET Core 3.1 Web Api 时出现 CORS 策略问题

在不同的端口上运行 Angular UI 和 Asp.net Web Api

使用 MSAL 保护 ASP.Net Core Web API 和 Angular App

Web Share API 在 iOS 上不起作用:Angular