最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - 415 (Unsupported Media Type) with REST Post request - Stack Overflow

programmeradmin3浏览0评论

I have a react component that when a checkbox is pressed, it calls a rest api, post request with a single parameter.

I put a breakpoint in the webapi and its never hit, still I get a 415 unsopported media type on the component

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;

and the webapi method

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

I have a react component that when a checkbox is pressed, it calls a rest api, post request with a single parameter.

I put a breakpoint in the webapi and its never hit, still I get a 415 unsopported media type on the component

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;

and the webapi method

[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);
        }
Share Improve this question asked Aug 8, 2018 at 20:20 Luis ValenciaLuis Valencia 34k99 gold badges308 silver badges531 bronze badges 11
  • Press F12, go to network log, do the request, check open the request look for the Content-Type parameter in the request, then look down in the bottom what the payload is – Pavlo Commented Aug 8, 2018 at 20:24
  • screencast.com/t/rGmbacnPJ – Luis Valencia Commented Aug 8, 2018 at 20:27
  • open the Request Headers, that's where the media type is specified – Pavlo Commented Aug 8, 2018 at 20:28
  • screencast.com/t/YB6b9D0LJkS – Luis Valencia Commented Aug 8, 2018 at 20:30
  • Your Content-Type is text/plain; charset=utf-8, which is technically correct, but the server is probably expecting application/json; charset=utf-8. I see that adalFetch doesn't set the content type with config.contentType – Pavlo Commented Aug 8, 2018 at 20:34
 |  Show 6 more comments

5 Answers 5

Reset to default 7 +50

Couple of things I noticed.

  1. You're trying to do a POST request with a JSON body. On the client, your request looks fine.

As I understand the POST body is

{ clientid: 'some-client-id' }
  1. The interesting thing is in the web API you receive it as

public async Task<IHttpActionResult> SetTenantActive([FromBody]string clientid)

This is possibly the culprit. Your API is expecting a string as a POST body where it is a json object. Have you tried changing the type to dynamic or JObject?

So, essentially,

public async Task<IHttpActionResult> SetTenantActive([FromBody]dynamic clientRequest)

OR

public async Task<IHttpActionResult> SetTenantActive([FromBody]JObject clientRequest)

Alternately,

If you want to continue using your API as is, then you can just change the request you’re making from the client to ’some-client-id’ instead of { clientid: 'some-client-id' }

Change

const options = { 
    method: 'post', 
    body: JSON.stringify({ clientid : selectedRows[0].key.toString() }) ,
    config: {
        headers: {
            'Content-Type': 'application/json'
        }
    }
};

to

const options = { 
    method: 'post', 
    body: JSON.stringify({ clientid : selectedRows[0].key.toString() }) ,
    headers: {
        'Content-Type': 'application/json; charset=utf-8'
    }
};

Check your server settings. By default it should support json but its better to verify it. Also try to clear Accept header in yor api code and set to * which means all types.

Moreover check adalApiFetch method. What headers it send? Is the format of Content-Type used & set correctly?

For a simple RESTFul call like that you could follow suggestion naming conventions along with HTTP verbs that better clarifies the intention and simplify the call itself. No need to over complicate the API model for such a simple call.

Something like

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

And on the client

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

Why are you using post? From a 'REST`y point of view, it is used to create an entity (a tenant in your case).

The simple request intended can be solved via GET with the clientid as part of the route:

[HttpGet]
[Route("api/Tenant/SetTenantActive/{clientid}")]
public async Task<IHttpActionResult> SetTenantActive(string clientid)
{
   // ...
}
发布评论

评论列表(0)

  1. 暂无评论