带有 REST Post 请求的 415(不支持的媒体类型)
Posted
技术标签:
【中文标题】带有 REST Post 请求的 415(不支持的媒体类型)【英文标题】:415 (Unsupported Media Type) with REST Post request 【发布时间】:2019-01-16 05:03:55 【问题描述】:我有一个反应组件,当一个复选框被按下时,它会调用一个rest api,使用单个参数发布请求。
我在 webapi 中设置了一个断点,但它从未命中,但我仍然在组件上得到一个 415 不支持的媒体类型
react js component (see onchange event)
import React, Component from 'react';
import Table, Radio from 'antd';
import adalApiFetch from '../../adalConfig';
import Notification from '../../components/notification';
class ListTenants extends Component
constructor(props)
super(props);
this.state =
data: []
;
fetchData = () =>
adalApiFetch(fetch, "/Tenant", )
.then(response => response.json())
.then(responseJson =>
if (!this.isCancelled)
const results= responseJson.map(row => (
key: row.ClientId,
ClientId: row.ClientId,
ClientSecret: row.ClientSecret,
Id: row.Id,
SiteCollectionTestUrl: row.SiteCollectionTestUrl,
TenantDomainUrl: row.TenantDomainUrl
))
this.setState( data: results );
)
.catch(error =>
console.error(error);
);
;
componentDidMount()
this.fetchData();
render()
const columns = [
title: 'Client Id',
dataIndex: 'ClientId',
key: 'ClientId'
,
title: 'Site Collection TestUrl',
dataIndex: 'SiteCollectionTestUrl',
key: 'SiteCollectionTestUrl',
,
title: 'Tenant DomainUrl',
dataIndex: 'TenantDomainUrl',
key: 'TenantDomainUrl',
];
// rowSelection object indicates the need for row selection
const rowSelection =
onChange: (selectedRowKeys, selectedRows) =>
if(selectedRows[0].key != undefined)
console.log(selectedRows[0].key);
const options =
method: 'post',
body: JSON.stringify( clientid : selectedRows[0].key.toString() ) ,
config:
headers:
'Content-Type': 'application/json'
;
adalApiFetch(fetch, "/Tenant/SetTenantActive", options)
.then(response =>
if(response.status === 200)
Notification(
'success',
'Tenant set to active',
''
);
else
throw "error";
)
.catch(error =>
Notification(
'error',
'Tenant not activated',
error
);
console.error(error);
);
,
getCheckboxProps: record => (
type: Radio
),
;
return (
<Table rowSelection=rowSelection columns=columns dataSource=this.state.data />
);
export default ListTenants;
和 webapi 方法
[HttpPost]
[Route("api/Tenant/SetTenantActive")]
public async Task<IHttpActionResult> SetTenantActive([FromBody]string clientid)
var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
var allTenants = await tenantStore.Query().Where(x => x.TenantDomainUrl != null).ToListAsync();
foreach(Tenant ten in allTenants)
ten.Active = false;
await tenantStore.UpdateAsync(ten);
var tenant = await tenantStore.Query().FirstOrDefaultAsync(x => x.clientid == clientid);
if (tenant == null)
return NotFound();
tenant.Active = true;
var result = await tenantStore.UpdateAsync(tenant);
return Ok(result);
【问题讨论】:
按F12,进入网络日志,做请求,检查打开请求在请求中查找Content-Type参数,然后在底部查看payload是什么 screencast.com/t/rGmbacnPJ 打开请求标头,这是指定媒体类型的地方 screencast.com/t/YB6b9D0LJkS 您的 Content-Type 是 text/plain; charset=utf-8,这在技术上是正确的,但服务器可能期待 application/json;字符集=utf-8。我看到 adalFetch 没有用config.contentType
设置内容类型
【参考方案1】:
我注意到的几件事。
-
您正在尝试使用 JSON 正文执行
POST
请求。在客户端,您的请求看起来不错。
据我了解,POST 正文是
clientid: 'some-client-id'
-
有趣的是在您收到它的 Web API 中
public async Task<IHttpActionResult> SetTenantActive([FromBody]string clientid)
这可能是罪魁祸首。您的 API 需要一个字符串作为 POST 正文,其中它是一个 json 对象。您是否尝试将类型更改为dynamic
或JObject
?
所以,本质上,
public async Task<IHttpActionResult> SetTenantActive([FromBody]dynamic clientRequest)
或
public async Task<IHttpActionResult> SetTenantActive([FromBody]JObject clientRequest)
或者,
如果您想继续按原样使用您的 API,那么您只需将您从客户端发出的请求更改为 ’some-client-id’
而不是 clientid: 'some-client-id'
【讨论】:
你是对的,完全错过了。或者,可以将正文设置为'some-client-id'
(包括引号并保持application/json
作为内容类型),这将被反序列化为一个简单的字符串,因此@Luis Valencia 可以使用他的post
端点。但这仍然不能解释生成的状态码。【参考方案2】:
改变
const options =
method: 'post',
body: JSON.stringify( clientid : selectedRows[0].key.toString() ) ,
config:
headers:
'Content-Type': 'application/json'
;
到
const options =
method: 'post',
body: JSON.stringify( clientid : selectedRows[0].key.toString() ) ,
headers:
'Content-Type': 'application/json; charset=utf-8'
;
【讨论】:
【参考方案3】:检查您的服务器设置。默认情况下它应该支持json
,但最好验证它。也尝试清除你的api代码中的Accept
标头并设置为*
,这意味着所有类型。
另外检查adalApiFetch
方法。它发送什么标头? Content-Type
的格式是否使用&设置正确?
【讨论】:
【参考方案4】:对于像这样的简单 RESTFul 调用,您可以遵循建议命名约定以及 HTTP 动词,这样可以更好地阐明意图并简化调用本身。对于这样一个简单的调用,无需过度复杂化 API 模型。
类似
[HttpPut] // Or HttpPost. PUT is usually used to update the resourcce
[Route("api/Tenant/clientid/Active")]
public async Task<IHttpActionResult> SetTenantActive(string clientid)
var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
var allTenants = await tenantStore.Query().Where(x => x.TenantDomainUrl != null).ToListAsync();
var updates = new List<Task>();
foreach(Tenant ten in allTenants)
ten.Active = false;
updates.Add(tenantStore.UpdateAsync(ten));
await Task.WhenAll(updates);
var tenant = await tenantStore.Query().FirstOrDefaultAsync(x => x.clientid == clientid);
if (tenant == null)
return NotFound();
tenant.Active = true;
var result = await tenantStore.UpdateAsync(tenant);
return Ok(result);
在客户端
const rowSelection =
onChange: (selectedRowKeys, selectedRows) =>
if(selectedRows[0].key != undefined)
var clientid = selectedRows[0].key;
console.log(clientid);
var url = "/Tenant/" + clientid + "/Active"
const options =
method: 'put'
;
adalApiFetch(fetch, url, options)
.then(response =>
if(response.status === 200)
Notification(
'success',
'Tenant set to active',
''
);
else
throw "error";
)
.catch(error =>
Notification(
'error',
'Tenant not activated',
error
);
console.error(error);
);
,
getCheckboxProps: record => (
type: Radio
),
;
【讨论】:
【参考方案5】:你为什么使用post
?从 'REST`y 的角度来看,它用于创建实体(在您的情况下为租户)。
预期的简单请求可以通过GET
解决,clientid
作为路由的一部分:
[HttpGet]
[Route("api/Tenant/SetTenantActive/clientid")]
public async Task<IHttpActionResult> SetTenantActive(string clientid)
// ...
【讨论】:
我以为get只是读操作,settenantactive是对DB的更新操作 您的端点和意图不适合标准的“REST”示例(主要是 CRUD 的东西)。您正在更新现有租户,因此您可以使用PUT
或 PATCH
(其中可能会导致同样的问题)。但是由于您没有要通过主体传递的具有预期新属性值的租户对象,因此您最好使用GET
。以上是关于带有 REST Post 请求的 415(不支持的媒体类型)的主要内容,如果未能解决你的问题,请参考以下文章
Rest API Post Json 使用带有两个参数的 C#
错误 415 不支持的媒体类型:如果是 JSON,则 POST 未达到 REST,但如果是 XML,则可以
POST 到 Jersey REST 服务收到错误 415 Unsupported Media Type
解决了! - Spring boot:获取 415 不支持的媒体类型
带有 XML 参数的 REST 服务操作上的 HTTP 错误 415 不受支持的媒体类型(Jersey + Jetty)