调用 Web API 2 端点时出现 HTTP 415 不支持的媒体类型错误

Posted

技术标签:

【中文标题】调用 Web API 2 端点时出现 HTTP 415 不支持的媒体类型错误【英文标题】:HTTP 415 unsupported media type error when calling Web API 2 endpoint 【发布时间】:2016-04-12 04:01:17 【问题描述】:

我有一个现有的 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 错误。 【参考方案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”,也不是核心/标准库的一部分。请参阅***.com/questions/10362140/… - 有人非常友好地创建了一个更完整的常量列表。【参考方案3】:

我也遇到了这个错误。

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

【讨论】:

看起来像评论的答案需要编辑,不推荐使用。 好。完整的端到端示例在这里:***.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;
 

【讨论】:

以上是关于调用 Web API 2 端点时出现 HTTP 415 不支持的媒体类型错误的主要内容,如果未能解决你的问题,请参考以下文章

通过 SSL 调用 Web Api 时出现 403 禁止错误

为什么在调用azure数据湖gen2的put文件api时出现丢失的头错误?

使用http postflutter web时出现XMLHttpRequest错误

使用 Ajax 调用 Web Api 方法时出现错误 400

尝试在 Web API 请求上检索 Azure Blob 时出现 403 错误

为啥调用 API 时出现 CORS 错误