web-dev-qa-db-ja.com

フェッチ: POST JSONデータ

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 echoを使用する場合 私は送ったオブジェクト({a: 1, b: 2})が戻ってくることを期待しますが、これは起こりません - chrome devtoolsはリクエストの一部としてJSONを表示さえしません送信されていません。

385
Razor

ES2017 async/await support で、これはJSONペイロードをPOSTする方法です:

(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が使えませんか? @ vp_artの promiseを使った答え を参照してください。

しかし、問題は長い間修正されたクロムのバグ)によって引き起こされた問題を尋ねています。
元の答えが続きます。

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

これが本当の問題です、そしてChrome 46で修正された chrome devtoolsのバグ です。

そのコードはうまく動作します - それは正しくJSONをPOSTしています、それはただ見ることができません。

私は送ってきたオブジェクトが見えると期待しています

これは JSfiddleのエコーの正しい形式 ではないため、うまくいきません。

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

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ペイロードを受け入れるエンドポイントの場合、元のコードは正しい

374
Razor

あなたの問題はjsfiddleform-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));
159
vp_arth

検索エンジンから、私はフェッチで非json投稿データのためにこのトピックになったので、私はこれを追加すると思いました。

non-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ストリングを作成する別の方法は、ライブラリーを使用することです。例えば、 query-string または stringify packagesのqs関数です。それでこれを使うとそれは次のようになるでしょう:

import queryString from 'query-string';
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}
});
38
Noitidart

しばらく使った後、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

32

純粋にjson REST AP​​Iを使用している場合は、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');
});
15

同じ問題がありました - 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 => {
   ...
})
10
Green

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

しかし、jQueryの$.post()を試してもうまくいくのは、おそらくjQueryがContent-Type: 'x-www-form-urlencoded'の代わりに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'}
})
9
Marcus Lind

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

Formdataが私の要求のために送られていないという問題を抱えていました

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

それで私はリクエストと共にこれら二つのヘッダを送っていて、うまくいったヘッダを取り除いたときそれはフォームデータを送っていませんでした。

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

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

私の要求では、正しいContent-Typeヘッダーは次のとおりです。

"Content-Type": "アプリケーション/ x-www-form-urlencoded;文字セット= UTF-8"

つまり、あなたのフォームデータがリクエストに添付されていないのなら、それは潜在的にあなたのヘッダかもしれません。あなたの問題が解決されたかどうかを確かめるためにあなたのヘッダを最小にしてそれから一つずつ追加してみてください。

3
user_CC

あなたのJSONペイロードが配列と入れ子になったオブジェクトを含むならば、私はURLSearchParamsとjQueryのparam()メソッドを使います。

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

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

3
Eric Sellin

一番上の答えは、間違ったエンコーディングを持っているのでPHP7ではうまくいきませんが、他の答えで正しいエンコーディングを見つけ出すことができます。このコードは認証クッキーも送信します。 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);
    });
}
1
lama12345