フェッチ:POST jsonデータ


562

fetchを使用してJSONオブジェクトをPOSTしようとしています。

私が理解できることから、文字列化されたオブジェクトをリクエストの本文に添付する必要があります。例:

fetch("/echo/json/",
{
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    method: "POST",
    body: JSON.stringify({a: 1, b: 2})
})
.then(function(res){ console.log(res) })
.catch(function(res){ console.log(res) })

jsfiddleのjsonエコーを使用すると、送信したオブジェクト({a: 1, b: 2})が返されることが期待されますが、これは発生しません。Chromedevtoolsでは、リクエストの一部としてJSONも表示されないため、送信されません。


どのブラウザを使用していますか?
Krzysztof Safjanowski 2015

@KrzysztofSafjanowski chrome 42、これは完全なフェッチサポートを提供
Razor

このフィドルjsfiddle.net/abbpbah4/2をチェックして、 どのデータを期待していますか?fiddle.jshell.net/echo/jsonの getリクエストが空のオブジェクトを表示しているためです。{}
Kaushik 2015

@KaushikKishoreは、予想される出力を明確にするために編集されました。res.json()戻る必要があり{a: 1, b: 2}ます。
かみそり

1
json送信するデータを含むプロパティを含めるのを忘れました。しかし、bodyとにかく正しく扱われていません。このフィドルを見て、5秒の遅延がスキップされることを確認してください。 jsfiddle.net/99arsnkgまた、追加のヘッダーを追加しようとしても無視されます。これはおそらくfetch()それ自体の問題です。
ラジカセ

回答:


598

ES2017 async/awaitサポートでは、これはPOSTJSONペイロードへの方法です。

(async () => {
  const rawResponse = await fetch('https://httpbin.org/post', {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({a: 1, b: 'Textual content'})
  });
  const content = await rawResponse.json();

  console.log(content);
})();

ES2017は使えませんか?promise を使用して @vp_artの回答を見る

ただし、問題は、長い間修正されたChromeのバグによって引き起こされる問題を求めています。
元の答えは次のとおりです。

chrome devtoolsはリクエストの一部としてJSONさえ表示しません

これは本当の問題であり、Chrome 46で修正されたChrome devtoolsのバグです。

そのコードは正常に機能します。JSONを正しくPOSTしているため、表示されません。

返送したオブジェクトが表示されることを期待しています

JSfiddleのechoの正しい形式ではないため、機能しません。

正しいコードは次のとおりです。

var payload = {
    a: 1,
    b: 2
};

var data = new FormData();
data.append( "json", JSON.stringify( payload ) );

fetch("/echo/json/",
{
    method: "POST",
    body: data
})
.then(function(res){ return res.json(); })
.then(function(data){ alert( JSON.stringify( data ) ) })

JSONペイロードを受け入れるエンドポイントの場合、元のコードは正しい


15
レコードの場合、これはJSONペイロードを投稿するものではありません。これは、というx-www-form-urlencoded名前のフィールドにJSONデータを含むフォーム投稿()jsonです。したがって、データは二重にエンコードされます。きれいなJSON投稿については、以下の@vp_arthによる回答を参照してください。
mindplay.dk

1
@ mindplay.dkこれはx-www-form-urlencodedの投稿ではありません。Fetch APIは、FormDataオブジェクトで常にmultipart / form-dataエンコーディングを使用します。
JukkaP

@JukkaP私はスタンドを修正しました。私の主なポイントは、二重エンコーディングの問題でした。
mindplay.dk

2
Content-Typeは引き続きtext / htmlです。charset = iso-8859-1私が間違っていることを知らない...
KT Works

3
安全のためres.okに、応答コードがなんらかのエラーである場合は確認することをお勧めします。.catch()最後に節があるといいでしょう。これは単なるサンプルスニペットであることを理解していますが、実際の使用ではこれらのことを念頭に置いてください。
ケン・リヨン

206

あなたの問題はリクエストのみjsfiddleを処理できると思いますform-urlencoded

しかし、jsonリクエストを行う正しい方法はjson、本文として正しく渡すことです。

fetch('https://httpbin.org/post', {
  method: 'post',
  headers: {
    'Accept': 'application/json, text/plain, */*',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({a: 7, str: 'Some string: &=&'})
}).then(res=>res.json())
  .then(res => console.log(res));


6
これは正しい解決策です。ピリオド -他の誰もがx-www-form-urlencodedvs について混乱しているようでapplication/json、それらを一致させないか、URLエンコードされた文字列でJSONを二重にラップしています。
mindplay.dk

しかし、これはjsfiddleでは機能しません。だから、なぜ「これが正しい解決策、期間だ」とあなたが言うのか、私にはわかりません。jsfiddleのAPIを満たすために他のすべての人がラッピングを行っているわけではありません/echoルートのか?
adam-beck

69

検索エンジンから、json以外のfetch付きの投稿データについてこのトピックにたどり着いたので、これを追加すると思いました。

以下のために非JSONフォームデータを使用する必要はありません。Content-Typeヘッダーを設定しapplication/x-www-form-urlencodedて文字列を使用するだけです:

fetch('url here', {
    method: 'POST',
    headers: {'Content-Type':'application/x-www-form-urlencoded'}, // this line is important, if this content-type is not set it wont work
    body: 'foo=bar&blah=1'
});

body上記のように入力するのではなく、その文字列を作成する別の方法は、ライブラリを使用することです。たとえばstringifyからの関数query-stringまたはqsパッケージ。したがって、これを使用すると次のようになります。

import queryString from 'query-string'; // import the queryString class

fetch('url here', {
    method: 'POST',
    headers: {'Content-Type':'application/x-www-form-urlencoded'}, // this line is important, if this content-type is not set it wont work
    body: queryString.stringify({for:'bar', blah:1}) //use the stringify object of the queryString class
});

2
クエリ文字列をありがとうございました。JSON.stringifyで何度も試しましたが、ajaxが応答を返しませんでした。しかし、クエリ文字列でうまくいきました。また、文字列を作成するのではなく、本文パラメーターのfetch create jsonが原因であることがわかりました。
デンマーク語

1
ありがとうございます!これが一番の返事です!私は昨日数時間壁にぶつかり、フォームデータを含む 'body'をWebアプリケーションからサーバーに送信する方法を見つけようとしました... 1つの提案:$ npm install cors --saveこれは、 " mode: 'no- cors
Alexander Cherednichenko

ありがとう@AlexanderCherednichenko!そして、corsを共有してくれてありがとう、それは私が知らなかった興味深いものです。:)
Noitidart 2017

1
心から感謝します。あなたは私の時間と私の人生を2度節約しました:)
bafsar

1
Thnaks @bafsar!
Noitidart、

42

何度か費やした後、jsFiddleをリバースエンジニアリングし、ペイロードを生成しようとしました-効果があります。

return response.json();返答が返答ではない-約束である線に目を向けてください(注意)。

var json = {
    json: JSON.stringify({
        a: 1,
        b: 2
    }),
    delay: 3
};

fetch('/echo/json/', {
    method: 'post',
    headers: {
        'Accept': 'application/json, text/plain, */*',
        'Content-Type': 'application/json'
    },
    body: 'json=' + encodeURIComponent(JSON.stringify(json.json)) + '&delay=' + json.delay
})
.then(function (response) {
    return response.json();
})
.then(function (result) {
    alert(result);
})
.catch (function (error) {
    console.log('Request failed', error);
});

jsFiddle:http ://jsfiddle.net/egxt6cpz/46/ && Firefox> 39 && Chrome> 42


なぜ'x-www-form-urlencoded代わりにapplication/json?違いは何ですか?
ファンピカド2017

@JuanPicado- 2年前のjsfiddleリバースエンジニアリングの後、それが機能する唯一のオプションでした。もちろんapplication/json正しい形であり、現在は機能しています。良い目をありがとう:)
Krzysztof Safjanowski

うん。奇妙な詳細、それはfetchstackoverflow.com/questions/41984893/…)の代わりに古い方法で私のために機能しますapplication/json。たぶん、あなたはその理由を知っています...
Juan Picado

6
Content-Typeですapplication/jsonが、あなたの実際のbody現れがあることをx-www-form-urlencoded-私は、これは動作するはずだと思いませんか?それが機能する場合、サーバーはかなり寛容でなければなりません。以下の@vp_arthの答えは正しいようです。
mindplay.dk 2017年

18

純粋なjson REST APIを使用している場合、fetch()の周りに薄いラッパーを作成し、多くの改良を加えました。

// Small library to improve on fetch() usage
const api = function(method, url, data, headers = {}){
  return fetch(url, {
    method: method.toUpperCase(),
    body: JSON.stringify(data),  // send it as stringified json
    credentials: api.credentials,  // to keep the session on the request
    headers: Object.assign({}, api.headers, headers)  // extend the headers
  }).then(res => res.ok ? res.json() : Promise.reject(res));
};

// Defaults that can be globally overwritten
api.credentials = 'include';
api.headers = {
  'csrf-token': window.csrf || '',    // only if globally set, otherwise ignored
  'Accept': 'application/json',       // receive json
  'Content-Type': 'application/json'  // send json
};

// Convenient methods
['get', 'post', 'put', 'delete'].forEach(method => {
  api[method] = api.bind(null, method);
});

それを使用するには、変数apiと4つのメソッドがあります。

api.get('/todo').then(all => { /* ... */ });

そしてasync関数内:

const all = await api.get('/todo');
// ...

jQueryの例:

$('.like').on('click', async e => {
  const id = 123;  // Get it however it is better suited

  await api.put(`/like/${id}`, { like: true });

  // Whatever:
  $(e.target).addClass('active dislike').removeClass('like');
});

あなたは別の引数のセットを意味したと思いますObject.assignか?あるべきObject.assign({}, api.headers, headers)カスタムを追加し続けるしたくないので、headers共通のハッシュへapi.headers。正しい?
Mobigital 2018年

@Mobigital正解、当時はそのニュアンスを知りませんでしたが、今ではそれが唯一の方法です
Francisco Presencia

11

これはに関連していContent-Typeます。他の議論やこの質問への回答から気づいたかもしれませんが、を設定することで解決できる人もいましたContent-Type: 'application/json'。残念ながら、私の場合は機能しませんでした。私のPOSTリクエストはサーバー側でまだ空でした。

ただし、jQueryを試してみて機能している場合$.post()、その理由はおそらくのContent-Type: 'x-www-form-urlencoded'代わりにjQueryを使用しているためですapplication/json

data = Object.keys(data).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key])).join('&')
fetch('/api/', {
    method: 'post', 
    credentials: "include", 
    body: data, 
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})

1
私のバックエンド開発者は、PHPを使用してAPIを構築し、データがjsonオブジェクトではなくクエリ文字列であると期待していました。これにより、サーバー側の空の応答が解決されました。
eballeste 2017年

11

同じ問題がありました-いいえ bodyクライアントからサーバーに送信されでした。

Content-Typeヘッダーを追加することで解決しました:

var headers = new Headers();

headers.append('Accept', 'application/json'); // This one is enough for GET requests
headers.append('Content-Type', 'application/json'); // This one sends body

return fetch('/some/endpoint', {
    method: 'POST',
    mode: 'same-origin',
    credentials: 'include',
    redirect: 'follow',
    headers: headers,
    body: JSON.stringify({
        name: 'John',
        surname: 'Doe'
    }),
}).then(resp => {
    ...
}).catch(err => {
   ...
})

7

PHP7の場合、エンコードが間違っているため、上の答えは機能しませんが、他の答えで正しいエンコードを見つけることができました。このコードは、認証Cookieも送信します。これは、PHPフォーラムなどを処理するときにおそらく必要です。

julia = function(juliacode) {
    fetch('julia.php', {
        method: "POST",
        credentials: "include", // send cookies
        headers: {
            'Accept': 'application/json, text/plain, */*',
            //'Content-Type': 'application/json'
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" // otherwise $_POST is empty
        },
        body: "juliacode=" + encodeURIComponent(juliacode)
    })
    .then(function(response) {
        return response.json(); // .text();
    })
    .then(function(myJson) {
        console.log(myJson);
    });
}

3

それは誰かに役立つかもしれません:

リクエストに対してフォームデータが送信されないという問題がありました

私の場合、それは問題と間違ったContent-Typeも引き起こしていた次のヘッダーの組み合わせでした。

したがって、私はリクエストでこれら2つのヘッダーを送信していましたが、機能するヘッダーを削除したときにformdataを送信していませんでした。

"X-Prototype-Version" : "1.6.1",
"X-Requested-With" : "XMLHttpRequest"

また、他の回答が示唆するように、Content-Typeヘッダーは正しい必要があります。

私のリクエストの正しいContent-Typeヘッダーは次のとおりです。

"Content-Type": "application / x-www-form-urlencoded; charset = UTF-8"

つまり、フォームデータがリクエストに添付されていない場合、ヘッダーになる可能性があります。ヘッダーを最小限にしてから、ヘッダーを1つずつ追加して、問題が解決するかどうかを確認してください。


3

JSONオブジェクトを文字列に解析する必要はないと思います。リモートサーバーがリクエストにjsonを受け入れる場合は、次のように実行します。

const request = await fetch ('/echo/json', {
  headers: {
    'Content-type': 'application/json'
  },
  method: 'POST',
  body: { a: 1, b: 2 }
});

カールリクエストなど

curl -v -X POST -H 'Content-Type: application/json' -d '@data.json' '/echo/json'

本体としてjsonファイルを受け入れないリモートサーバーの場合は、dataFormを送信するだけです。

const data =  new FormData ();
data.append ('a', 1);
data.append ('b', 2);

const request = await fetch ('/echo/form', {
  headers: {
    'Content-type': 'application/x-www-form-urlencoded'
  },
  method: 'POST',
  body: data
});

カールリクエストなど

curl -v -X POST -H 'Content-type: application/x-www-form-urlencoded' -d '@data.txt' '/echo/form'

2
これは明らかに不正解です。jsonを文字列化する必要があるかどうかに関係なく、サーバー側とは関係ありません。これは、curlコマンドが暗黙的に行っていることです!オブジェクトを渡す前にオブジェクトを文字列化しない場合は、リクエストの本文としてbody送信"[object Object]"します。開発ツールでの簡単なテストはそれを示します。それを開いて、このタブを離れることなくこれを試してください:a = new FormData(); a.append("foo","bar"); fetch("/foo/bar", { method: 'POST', body: {}, headers: { 'Content-type': 'application/json' } })
オリゴフレン

2

JSONペイロードに配列とネストされたオブジェクトが含まれている場合はURLSearchParams 、jQueryのparam()メソッドを使用します。

fetch('/somewhere', {
  method: 'POST',
  body: new URLSearchParams($.param(payload))
})

サーバーにとっては、これは編集<form>されている標準のHTMLのように見えますPOST

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.