使用 XMLHttpRequest 发布到 ASP.Net Core WebAPI 时出现错误 415

Posted

技术标签:

【中文标题】使用 XMLHttpRequest 发布到 ASP.Net Core WebAPI 时出现错误 415【英文标题】:Error 415 when posting to ASP.Net Core WebAPI using XMLHttpRequest 【发布时间】:2017-05-03 16:05:13 【问题描述】:

使用 WebAPI 后端服务器处理一个新项目,我在从实际网站向控制器发布时遇到问题,尽管 Postman 向控制器发布没有问题。我收到错误 415,浏览器控制台日志记录:

HTTP415: UNSUPPORTED MEDIA TYPE - The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method.
(XHR)OPTIONS - http://localhost:5000/api/Users

虽然来自 Kestrel 的日志是

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 OPTIONS http://localhost:5000/api/Users  0
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 OPTIONS http://localhost:5000/api/Users  0
info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1]
      Executing HttpStatusCodeResult, setting HTTP status code 415
Microsoft.AspNetCore.Mvc.StatusCodeResult:Information: Executing HttpStatusCodeResult, setting HTTP status code 415
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action SchoolsChat.Controllers.UserContoller.Post (SchoolsChat) in 2.5323ms
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action SchoolsChat.Controllers.UserContoller.Post (SchoolsChat) in 2.5323ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 6.6615ms 415 
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 6.6615ms 415 

我正在尝试发布以下 JSON:


    UserDOB: "2016-12-18",
    UserFirstName: "asdf",
    UserLastName: "asasdf",
    UserName: "asdf",
    UserSecret: "asdf"

使用这个 TypeScript 类

/**
 * JsonPost
 */
class JsonPost 
    private _response: number;
    public get Reponse(): number 
        return this._response;
    
    constructor(link: string, data: Object) 
        let request = new XMLHttpRequest();
        request.withCredentials = true;

        request.open("POST", APIUri + link, true);
        request.setRequestHeader("content-type", "application/json");
        request.setRequestHeader("cache-control", "no-cache");
        request.onreadystatechange = () => this._response = request.status;
        console.log(request);
        request.send(JSON.stringify(data));
    

User的模型是

public class User
    
        [KeyAttribute]
        public int UserId  get; set; 
        [RequiredAttribute]
        public int SchoolId  get; set; 
        [RequiredAttribute]
        public string UserName  get; set; 
        [RequiredAttribute]
        [DataTypeAttribute(DataType.Password)]
        public string UserSecret  get; set;  // Unnecessary due to school linking?
        [RequiredAttribute]
        public virtual School UserSchool  get; set; 
    

虽然发布的控制器很简单,只是输出名字

[HttpPost]
    public IActionResult Post([FromBody]User user)
    
        Console.WriteLine(user.UserName);
        return StatusCode(200);
    

编辑 虽然 nemec 的回答有助于解决问题,但我发现对于 WebAPI,最好的解决方案是仅使用 app.UseCors 作为服务配置 cors。在许多情况下,AddCors 实际上并没有在响应中包含必要的标头。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        
            app.UseCors(options => options.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials());
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();
            app.UseMvc();
        

【问题讨论】:

请参阅 ***.com/questions/8153832/… 了解为什么您看到的是 OPTIONS 请求而不是 POST 【参考方案1】:

就我而言,问题在于我在操作参数之前放置了一个FromBody 属性。

发件人:

[HttpPost("Contact")]
public async Task<IActionResult> NewContact([FromBody]Contact contact)

收件人:

[HttpPost("Contact")]
public async Task<IActionResult> NewContact(Contact contact)

【讨论】:

它也为我解决了这个问题,但仔细检查后,我的网络应用使用application/x-www-form-urlencoded 的内容类型发布。一旦我将POST 的内容类型更改为application/json [FromBody] 就可以做到这一点。我还没有深入研究是否可以将[FromBody]application/x-www-form-urlencoded 的内容类型结合使用。 出现问题是因为[FromBody]的ContentType必须是Json。如果它不是 JSON,它将执行 415 错误。取出时,接受分配的ContentType,不接受ContentType。 我同意@mohas。对我来说,ASP.Net Core 415 错误的常见原因是缺少绑定属性或请求与声明的绑定([FromBody]、[FromForm]、[FromQuery] 等)不匹配。旧版本的 MVC 通常可以在没有绑定属性的情况下正常工作。【参考方案2】:

正如 Evan 在他的评论中提到的,当您发出跨域 ajax 请求时,您的 POST 正在变成 OPTIONS。由于浏览器的跨域安全策略,您的 web api 需要告诉浏览器/js,您的网站允许对其进行 ajax 请求。

https://docs.microsoft.com/en-us/aspnet/core/security/cors

要为您的应用程序设置 CORS,请将 Microsoft.AspNetCore.Cors 包添加到您的项目中。

在 Startup.cs 中添加 CORS 服务:

public void ConfigureServices(IServiceCollection services)

    services.AddCors();

如果您按照链接的说明进行操作,您甚至可以使用IApplicationBuilder.UseCors 进一步自定义允许哪些网站。

例如:

app.UseCors(builder =>
    builder.WithOrigins("http://example.com")
           .AllowAnyHeader()
);

Postman 是一款应用程序,因此可以免除跨域规则的约束。

【讨论】:

【参考方案3】:

还不知道为什么,我对 .Net Core Web API 还是很陌生。我删除了控制器属性 [ApiController],一切都到位了。

在我的情况下,我在同一个项目上有一个 MVC 接口和 WebApi。 希望这对某人有所帮助。

【讨论】:

【参考方案4】:

我们升级到 .NET core 3.0,当您从查询参数构建对象时需要使用 [FromQuery],例如使用 GET 请求。

例子:

[HttpGet("Hierarchy")]
public virtual async Task<IActionResult> GetHierarchy([FromServices] IDeviceHierarchyService service, [FromQuery] HierarchyStructureRequest structureLoad)

【讨论】:

以上是关于使用 XMLHttpRequest 发布到 ASP.Net Core WebAPI 时出现错误 415的主要内容,如果未能解决你的问题,请参考以下文章

用于 XmlHttpRequest 的带有 WebAPI 的 CORS

带有 Vue JS 的 ASP.NET Core 5 从源访问 XMLHttpRequest 已被 CORS 策略阻止

是否可以在XMLHttpRequest标头中包含antiforgerytoken?

无法将 JSON 发布到 ASP.NET Core RazorPage 处理程序

基础:ASP.NET使用原始AJAX

在 Asp.net 中使用 HTML5 的拖放上传文件