简体   繁体   English

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

[英]Error 415 when posting to ASP.Net Core WebAPI using XMLHttpRequest

Working on a new project using a WebAPI backend server and I am having trouble posting to the controller from an actual website, despite Postman having no issues posting to the controller.使用 WebAPI 后端服务器处理一个新项目,尽管 Postman 向控制器发布没有问题,但我无法从实际网站向控制器发布信息。 I get the an error 415, the browser console logging:我收到错误 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

Whilst the log from Kestrel is虽然来自 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 

I am trying to post the following JSON:我正在尝试发布以下 JSON:

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

using this TypeScript class使用这个 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));
    }
}

The model of User is用户模型为

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

Whilst the controller for posting is simple, just outputting the first name虽然发布的控制器很简单,只是输出名字

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

Edit Whilst the answer from nemec was helpeful in resolving the problem, I found that for the WebAPI specifically the best resolution was to only configure cors using app.UseCors as services.AddCors in many cases didn't actually include the necessary headers in the response.编辑虽然 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();
        }

In my case the problem was that I put a FromBody attribute before my action parameter.就我而言,问题是我在操作参数之前放置了FromBody属性。

From:从:

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

To:到:

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

As Evan mentioned in his comment, your POST is turning into an OPTIONS when you make a cross-origin ajax request.正如 Evan 在他的评论中提到的,当您发出跨域 ajax 请求时,您的POST正在变成一个OPTIONS Due to browsers' cross-origin security policies, your web api needs to tell the browser/js that your website is allowed to make ajax requests against it.由于浏览器的跨域安全策略,您的 web api 需要告诉浏览器/js 您的网站被允许对其发出 ajax 请求。

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

To setup CORS for your application add the Microsoft.AspNetCore.Cors package to your project.要为您的应用程序设置 CORS,请将Microsoft.AspNetCore.Cors包添加到您的项目中。

Add the CORS services in Startup.cs:在 Startup.cs 中添加 CORS 服务:

 public void ConfigureServices(IServiceCollection services) { services.AddCors(); }

If you follow the linked instructions, you can even use IApplicationBuilder.UseCors to further customize which sites are allowed.如果您按照链接的说明进行操作,您甚至可以使用IApplicationBuilder.UseCors进一步自定义允许哪些站点。

For example:例如:

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

Postman is an app and therefore has the ability to exempt itself from cross-origin rules. Postman 是一个应用程序,因此可以免除跨域规则的约束。

Don't know why yet, I'm still pretty new to .Net Core Web API's.不知道为什么,我对 .Net Core Web API 还是很陌生。 I removed the controller attribute [ApiController] and everything fell into place.我删除了控制器属性 [ApiController],一切都到位了。

In my situation, I have a MVC interface & WebApi on the same project.在我的情况下,我在同一个项目中有一个 MVC 接口和 WebApi。 Hope this helps someone.希望这可以帮助某人。

We upgraded to .NET core 3.0 and this required to use [FromQuery] when you're building an object from query parameters, eg with a GET request.我们升级到 .NET 核心 3.0,当您从查询参数(例如,使用 GET 请求)构建对象时,这需要使用 [FromQuery]。

Example:例子:

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

I agree with @mohas. 我同意@mohas。 For me, common cause of 415 errors with ASP.Net Core is a missing binding attribute or a mismatch between the request and the declared binding ([FromBody], [FromForm], [FromQuery] etc). 对我来说,ASP.Net Core导致415错误的常见原因是缺少绑定属性或请求与声明的绑定之间不匹配([FromBody],[FromForm],[FromQuery]等)。

Older versions of MVC could often work OK without binding attributes. 较旧版本的MVC在没有绑定属性的情况下通常可以正常运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM