415(不支持的媒体类型)REST Post 请求
415 (Unsupported Media Type) with REST Post request
我有一个 React 组件,当一个复选框被按下时,它会用一个参数调用 rest api、post 请求。
我在网络中放置了一个断点api但它从未命中,我仍然在组件上得到 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;
和网络api方法
[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);
}
改变
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'
}
};
为什么要使用 post
?从“REST”的角度来看,它用于创建一个实体(在您的案例中是一个租户)。
可以通过 GET
将 clientid
作为路由的一部分来解决简单的请求:
[HttpGet]
[Route("api/Tenant/SetTenantActive/{clientid}")]
public async Task<IHttpActionResult> SetTenantActive(string clientid)
{
// ...
}
检查您的服务器设置。默认情况下它应该支持 json
但最好验证它。还要尝试清除 Accept
header 中的 api 代码并设置为 *
这意味着所有类型。
另外检查adalApiFetch
方法。它发送什么header? Content-Type
的格式使用和设置是否正确?
对于像这样的简单 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
}),
};
我注意到几件事。
- 您正在尝试使用 JSON 正文执行
POST
请求。在客户端,您的请求看起来没问题。
据我了解 POST 正文是
{ clientid: 'some-client-id' }
- 有趣的是在网络上 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' }
我有一个 React 组件,当一个复选框被按下时,它会用一个参数调用 rest api、post 请求。
我在网络中放置了一个断点api但它从未命中,我仍然在组件上得到 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;
和网络api方法
[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);
}
改变
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'
}
};
为什么要使用 post
?从“REST”的角度来看,它用于创建一个实体(在您的案例中是一个租户)。
可以通过 GET
将 clientid
作为路由的一部分来解决简单的请求:
[HttpGet]
[Route("api/Tenant/SetTenantActive/{clientid}")]
public async Task<IHttpActionResult> SetTenantActive(string clientid)
{
// ...
}
检查您的服务器设置。默认情况下它应该支持 json
但最好验证它。还要尝试清除 Accept
header 中的 api 代码并设置为 *
这意味着所有类型。
另外检查adalApiFetch
方法。它发送什么header? Content-Type
的格式使用和设置是否正确?
对于像这样的简单 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
}),
};
我注意到几件事。
- 您正在尝试使用 JSON 正文执行
POST
请求。在客户端,您的请求看起来没问题。
据我了解 POST 正文是
{ clientid: 'some-client-id' }
- 有趣的是在网络上 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' }