【问题标题】:HTTP 415 unsupported media type error when calling Web API 2 endpoint调用 Web API 2 端点时出现 HTTP 415 不支持的媒体类型错误
【发布时间】:2023-03-08 21:16:01
【问题描述】:

我有一个现有的 Web API 2 服务,需要修改其中一个方法以将自定义对象作为另一个参数,目前该方法有一个参数,它是来自 URL 的简单字符串。添加自定义对象作为参数后,我现在在从 .NET Windows 应用程序调用服务时收到 415 不支持的媒体类型错误。有趣的是,我可以使用 javascript 和 jquery ajax 方法成功调用此方法。

Web API 2 服务方法如下所示:

<HttpPost>
<HttpGet>
<Route("{view}")>
Public Function GetResultsWithView(view As String, pPaging As Paging) As HttpResponseMessage
   Dim resp As New HttpResponseMessage
   Dim lstrFetchXml As String = String.Empty
   Dim lstrResults As String = String.Empty

   Try
      '... do some work here to generate xml string for the response
      '// write xml results to response
      resp.Content = New StringContent(lstrResults)
      resp.Content.Headers.ContentType.MediaType = "text/xml"
      resp.Headers.Add("Status-Message", "Query executed successfully")
      resp.StatusCode = HttpStatusCode.OK
   Catch ex As Exception
      resp.StatusCode = HttpStatusCode.InternalServerError
      resp.Headers.Add("Status-Message", String.Format("Error while retrieving results from view {0}: {1}", view, ex.Message))
   End Try
   Return resp
End Function

该方法允许POSTGET,因为Paging 对象是可选的。如果我使用GET 请求调用此方法,它会起作用。

调用服务的简单 .NET 客户端代码如下所示:

Dim uri As String = BASE_URI + "fetch/someview"
Dim resp As HttpWebResponse
Dim sr As StreamReader
Dim lstrResponse As String
Dim reqStream As Stream
Dim bytData As Byte()
Dim req As HttpWebRequest = WebRequest.Create(uri)
Dim lstrPagingJSON As String
Dim lPaging As New Paging
Try
   lPaging.Page = 1
   lPaging.Count = 100
   lPaging.PagingCookie = ""
   req.Method = "POST"
   lstrPagingJSON = JsonSerializer(Of Paging)(lPaging)
   bytData = Encoding.UTF8.GetBytes(lstrPagingJSON)
   req.ContentLength = bytData.Length
   reqStream = req.GetRequestStream()
   reqStream.Write(bytData, 0, bytData.Length)
   reqStream.Close()
   req.ContentType = "application/json"

   resp = req.GetResponse()

   sr = New StreamReader(resp.GetResponseStream, Encoding.UTF8)
   lstrResponse = sr.ReadToEnd
   '// do something with the response here
Catch exweb As WebException
   txtOutput.AppendText("Error during request: " + exweb.Message)
Catch ex As Exception
   txtOutput.AppendText(String.Format("General error during request to {0}: {1}", uri, ex.Message))
End Try

.NET 客户端在 4.5 框架上运行,服务在 4.5.2 框架上。错误在resp = req.GetResponse() 行引发。我已经尝试过的一些事情:

  • 在客户端上,将req.Accept 值设置为“application/xml”或 “文本/xml”
  • 在服务方法中,删除了该行 `resp.Content.Headers.ContentType.MediaType = "text/xml"
  • 用一些静态 JSON 替换 XML 响应内容,尝试排除在请求中发送 JSON 并在响应中返回 XML 的任何问题

到目前为止,无论我尝试什么,我都会收到相同的 415 错误响应。

我提到当从 javascript 调用时这有效,这是我的 ajax 调用有效:

$.ajax({
   headers: {},
   url: "api/fetch/someview",
   type: "POST",
   data: "{Count:100,Page:1,PagingCookie:\"\"}",
   contentType: "application/json; charset=utf-8",
   dataType: "xml",
   success: function (data) {
      alert("call succeeded");
   },
   failure: function (response) {
      alert("call failed");
   }
});

在服务方面,路由配置或其他任何东西都没有什么特别之处,它几乎都是开箱即用的 Web API 2。我知道路由正在工作,调用被正确路由到该方法,他们不会出乎意料地去其他地方,那么我在.NET客户端中缺少什么?非常感谢任何帮助!

--- 更新 ---
我尝试创建一个全新的 Web API 服务来排除现有服务可能存在的任何问题,我创建了一个控制器,它具有一个将自定义对象作为参数的单一方法。然后我尝试从 .NET 客户端调用它并得到同样的错误。我也尝试使用 WebClient 而不是 HttpWebRequest,但仍然得到相同的错误。这也是以前使用 Web API(在 Web API 2 之前)对我有用的东西。

--- 更新 ---
我还尝试使用 Web API 1 创建一个新的 Web 应用程序,当我使用 POST 调用它时,我的复杂对象参数现在为空。我有另一个运行 Web API 1 的 Web 服务,并验证我仍然可以使用复杂的对象成功调用它。无论我的问题是什么,它似乎与客户端和服务器之间传递的 JSON 有关。我已经检查了我发送的 JSON 及其有效性,对象定义也是客户端和服务器之间的完全匹配,因此 JSON 应该能够被服务器解析。

【问题讨论】:

  • 我在执行 DELETE 并在不需要的地方添加 JSON 有效负载时收到此 415 错误。

标签: json vb.net asp.net-web-api asp.net-web-api2 http-status-code-415


【解决方案1】:

已解决
在用这个问题把我的头撞到墙上几天之后,看起来这个问题与客户端和服务器之间的内容类型协商有关。我使用 Fiddler 更深入地研究了来自客户端应用程序的请求详细信息,这是 fiddler 捕获的原始请求的屏幕截图:

显然缺少的是 Content-Type 标头,尽管我在原始帖子的代码示例中设置了它。我觉得奇怪的是 Content-Type 即使我正在设置它也从未通过,所以我再次查看了调用不同 Web API 服务的其他(工作)代码,唯一的区别是我碰巧设置了req.ContentType 在这种情况下写入请求正文之前的属性。我对这个新代码进行了更改并做到了,Content-Type 现在出现了,我从 Web 服务获得了预期的成功响应。我的 .NET 客户端的新代码现在如下所示:

req.Method = "POST"
req.ContentType = "application/json"
lstrPagingJSON = JsonSerializer(Of Paging)(lPaging)
bytData = Encoding.UTF8.GetBytes(lstrPagingJSON)
req.ContentLength = bytData.Length
reqStream = req.GetRequestStream()
reqStream.Write(bytData, 0, bytData.Length)
reqStream.Close()
'// Content-Type was being set here, causing the problem
'req.ContentType = "application/json"

就是这样,只需在写入请求正文之前设置 ContentType 属性

我相信这种行为是因为一旦将内容写入主体,它就会流式传输到被调用的服务端点,与请求相关的任何其他属性都需要在此之前设置。如果我错了或者需要更多详细信息,请纠正我。

【讨论】:

    【解决方案2】:

    我在调用我的 web api 端点时遇到了这个问题并解决了。

    就我而言,这是客户端对正文内容进行编码的方式的问题。我没有指定编码或媒体类型。指定它们解决了它。

    未指定编码类型,导致415错误:

    var content = new StringContent(postData);
    httpClient.PostAsync(uri, content);
    

    指定编码和媒体类型,成功:

    var content = new StringContent(postData, Encoding.UTF8, "application/json");
    httpClient.PostAsync(uri, content);
    

    【讨论】:

    • 魔术字符串 "application/json" 在 .NET Core 库中的任何位置都可用作常量吗?
    • @CSJ 在 System.Net.Mime 命名空间中有一些(例如 System.Net.Mime.MediaTypeNames.Application.pdf 给出“application/pdf”),但列表不完整,并且,对于我们这里的特定目的,没有“应用程序/json”,也不是核心/标准库的一部分。请参阅stackoverflow.com/questions/10362140/… - 有人非常友好地创建了一个更完整的常量列表。
    【解决方案3】:

    我也遇到了这个错误。

    我添加到标题Content-Typeapplication/json。更改后,我的提交成功!

    【讨论】:

    • 看起来像评论的答案需要编辑,不推荐使用。
    • 好。完整的端到端示例在这里:stackoverflow.com/a/52003230/984471
    • @Mulliganaceous - 我使用的是“高级 REST 客户端”,尽管它很简洁,但这个答案对我有帮助。我添加了标题“Content-Type”和值“application/json”,重新提交,它起作用了。请注意,内容类型可能需要与控制器的“Produces”属性中指定的匹配(例如 [Produces("application/json")] )
    【解决方案4】:

    我正在尝试编写可在 Mac 和 Windows 上运行的代码。 该代码在 Windows 上运行良好,但在 Mac 上响应为 'Unsupported Media Type'。 这是我使用的代码,下面这行代码也可以在 Mac 上运行:

    Request.AddHeader "Content-Type", "application/json"
    

    这是我的代码的 sn-p:

    Dim Client As New WebClient
    Dim Request As New WebRequest
    Dim Response As WebResponse
    Dim Distance As String
    
    Client.BaseUrl = "http://1.1.1.1:8080/config"
    Request.AddHeader "Content-Type", "application/json" *** The line that made the code work on mac
    
    Set Response = Client.Execute(Request)
    

    【讨论】:

      【解决方案5】:

      在我的例子中,它是 Asp.Net Core 3.1 API。我将 HTTP GET 方法从 public ActionResult GetValidationRulesForField( GetValidationRulesForFieldDto getValidationRulesForFieldDto) 更改为 public ActionResult GetValidationRulesForField([FromQuery] GetValidationRulesForFieldDto getValidationRulesForFieldDto) 并且它工作正常。

      【讨论】:

      • 添加 [FromQuery] 也为我解决了这个问题。我错过了 MSDN Model Binding docs 中的这条重要声明:“路由数据和查询字符串值仅用于简单类型。”因此对于查询字符串中的复杂类型参数,您必须明确告诉它与 [FromQuery] 绑定。
      【解决方案6】:

      我未能在 DELETE 上发送一个正文,该正文需要一个,因此收到此消息。

      【讨论】:

        【解决方案7】:

        以防万一有人遇到我的愚蠢问题:我收到此错误是因为我使用类/合同来请求请求并且是 HttpGet,我忘记添加 [FromQuery]。

        public async Task<IActionResult> EndpointAction([FromQuery] TheContract request)
        {
           return Ok();
        }
        
         // The Contract Type
        public class TheContract 
        {
           public int Id;
        } 
        

        【讨论】:

          猜你喜欢
          • 2023-03-13
          • 1970-01-01
          • 2017-07-05
          • 2015-08-29
          • 2017-09-23
          • 1970-01-01
          • 2018-10-13
          • 2018-07-25
          相关资源
          最近更新 更多