가져 오기 : POST JSON 데이터


561

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})를 다시 볼 것으로 예상 되지만 이것은 발생하지 않습니다. 크롬 devtools는 JSON을 요청의 일부로 표시하지 않으므로 전송되지 않습니다.


어떤 브라우저를 사용하고 있습니까?
Krzysztof Safjanowski

@KrzysztofSafjanowski chrome 42
Razor

이 바이올린을 확인하십시오 jsfiddle.net/abbpbah4/2 어떤 데이터를 기대하십니까? fiddle.jshell.net/echo/json의 get 요청에 빈 객체가 표시 되기 때문 입니다. {}
Kaushik

예상 출력을 명확하게하기 위해 @KaushikKishore가 편집되었습니다. res.json()반환해야합니다 {a: 1, b: 2}.
면도기

1
json보내려는 데이터 가 포함 된 속성을 포함하는 것을 잊었습니다 . 그러나, 나는 body어쨌든 올바르게 취급되지 않습니다. 이 바이올린을보고 5 초 지연을 건너 뜁니다. jsfiddle.net/99arsnkg 또한 헤더를 추가하려고하면 무시됩니다. 이것은 아마도 fetch()자체 문제 일 것입니다 .
boombox

답변:


597

ES2017 async/await지원POST 으로 JSON 페이로드 하는 방법은 다음과 같습니다.

(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 's 참조약속을 사용하여 답변

그러나이 문제 는 오랫동안 수정 된 크롬 버그로 인한 문제를 묻고 있습니다.
원래 답변은 다음과 같습니다.

크롬 devtools는 요청의 일부로 JSON을 표시하지 않습니다.

이것은 실제 문제 이며 크롬 devtools버그입니다. 이며 Chrome 46에서 수정 된 .

이 코드는 정상적으로 작동합니다 .JSON을 올바르게 게시하고 있으며 볼 수 없습니다.

내가 보낸 개체를 볼 것으로 예상됩니다

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 페이로드를 허용하는 엔드 포인트의 경우 원래 코드가 정확합니다.


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()마지막에 절을 두는 것도 좋습니다 . 나는 이것이 샘플 스 니펫이라는 것을 알고 있지만 실제 사용을 위해 이러한 것들을 명심하십시오.
Ken Lyon

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의 /echo경로 API를 만족시키기 위해 다른 사람들이 래핑을 수행하지 않습니까?
adam-beck

69

검색 엔진에서 필자는 json이 아닌 게시 ​​데이터에 대해이 주제를 찾았으므로 이것을 추가 할 것이라고 생각했습니다.

들어 비 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위와 같이 문자열을 작성하는 대신 문자열 을 작성하는 다른 방법 은 라이브러리를 사용하는 것입니다. 예를 들어 stringifyfrom 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가 문자열을 만드는 대신 body 매개 변수에 대해 json을 생성하기 때문이라는 것을 알았습니다.
덴마크

1
고마워요! 이것은 최고의 답변입니다! 어제 웹 애플리케이션에서 서버로 양식 데이터가있는 '본문'을 보내는 방법을 찾으려고 몇 시간 동안 벽에 부딪 혔습니다 ... 한 가지 제안 : $ npm install cors --save이 명령을 제거하려면 " Fetch 요청의 'no-cors'모드는 github.com/expressjs/cors
Alexander Cherednichenko

감사합니다 @AlexanderCherednichenko! 그리고 내가 알지 못했던 흥미로운 것을 주목 해 주셔서 감사합니다. :)
Noitidart

1
내 마음 깊은 곳에서 감사합니다. 당신은 내 시간과 내 인생을 두 번 구했습니다 :)
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? 차이점이 뭐야?
Juan Picado

@ JuanPicado- 2 년 전 jsfiddle 리버스 엔지니어링 후 작동 할 수있는 유일한 옵션이었습니다. 물론 application/json올바른 형식이며 지금 작동합니다. 좋은 눈을 주셔서 감사합니다
:)

yw. 호기심 많은 세부 사항은 fetch( stackoverflow.com/questions/41984893/… ) 대신 이전 방식으로 작동 합니다 application/json. 아마도 당신은 이유를 알고 있습니다 ...
Juan Picado

6
Content-Type것입니다 application/json만, 실제 body나타난다는 수 x-www-form-urlencoded-이 작동합니다 생각하지 않아요? 작동한다면 서버는 용서해야합니다. 아래 @vp_arth의 답변이 올바른 것 같습니다.
mindplay.dk

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

@Mobigital 완전히 맞아, 그때 그 뉘앙스에 대해 몰랐지만 지금은 내가하는 유일한 방법입니다
Francisco Presencia

11

와 관련이 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'}
})

1
내 백엔드 개발자는 PHP로 API를 빌드했으며 데이터가 json 객체가 아닌 쿼리 문자열과 같을 것으로 기대했습니다. 이것은 서버 쪽의 빈 응답을 해결했습니다.
eballeste

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에서는 인코딩이 잘못되었으므로 상위 답변이 작동하지 않지만 다른 답변으로 올바른 인코딩을 파악할 수 있습니다. 이 코드는 또한 인증 쿠키를 전송하는데, 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

누군가에게 유용 할 수 있습니다.

요청에 대해 formdata가 전송되지 않는 문제가있었습니다.

내 경우에는 문제와 잘못된 Content-Type을 유발하는 다음 헤더의 조합이었습니다.

그래서 요청과 함께이 두 헤더를 보내고 있었고 작동하는 헤더를 제거 할 때 formdata를 보내지 않았습니다.

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

또한 다른 답변에 따르면 Content-Type 헤더가 정확해야합니다.

내 요청에 대한 올바른 Content-Type 헤더는 다음과 같습니다.

"콘텐츠 유형": "application / x-www-form-urlencoded; charset = UTF-8"

따라서 폼 데이터가 요청에 첨부되지 않은 경우 잠재적으로 헤더 일 수 있습니다. 헤더를 최소화 한 다음 하나씩 추가하여 문제가 해결되는지 확인하십시오.


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]"됩니다. Dev Tools의 간단한 테스트를 통해 알 수 있습니다. 그것을 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))
})

서버에이 표준 HTML의 모양을 <form>존재의 POST에디션.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.