ChatGPT解决这个技术问题 Extra ChatGPT

JavaScript,使用 fetch() 使用 JSON 数据进行 POST

我正在尝试使用 fetch 发布 JSON 对象。据我了解,我需要将一个字符串化对象附加到请求的正文中,例如:

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's JSON echo 时,我希望看到我发回的对象 ({a: 1, b: 2}),但这不会发生 - chrome devtools 甚至没有将 JSON 显示为请求的一部分,这意味着它不是被发送。

你使用的是什么浏览器?
@KrzysztofSafjanowski chrome 42,意味着有 full fetch support
检查这个小提琴jsfiddle.net/abbpbah4/2你期待什么数据?因为 fiddle.jshell.net/echo/json 的获取请求显示的是空对象。 {}
@KaushikKishore 编辑以阐明预期输出。 res.json() 应该返回 {a: 1, b: 2}
您忘记包含包含您要发送的数据的 json 属性。但是,我无论如何都没有正确对待body。请参阅此小提琴以查看 5 秒的延迟被跳过。 jsfiddle.net/99arsnkg 此外,当您尝试添加其他标头时,它们会被忽略。这可能是 fetch() 本身的问题。

R
Razor

使用 ES2017 async/await support,这是 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 的answer using promises

然而,问题是询问由长期修复的 chrome 错误引起的问题。原始答案如下。

chrome devtools 甚至没有将 JSON 显示为请求的一部分

这是真正的问题,它是 bug with chrome devtools,已在 Chrome 46 中修复。

该代码工作正常 - 它正确地发布 JSON,它只是看不到。

我希望看到我发回的对象

这不起作用,因为那不是 correct format for JSfiddle's echo

correct code 是:

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 有效负载的端点,原始代码是正确的


作为记录,这不是发布 JSON 有效负载 - 这是一个表单发布 (x-www-form-urlencoded),在名为 json 的字段中包含 JSON 数据。所以数据是双重编码的。有关干净的 JSON 帖子,请参阅下面@vp_arth 的回答。
@mindplay.dk 这不是 x-www-form-urlencoded 帖子。 Fetch API 总是对 FormData 对象使用 multipart/form-data 编码。
@JukkaP 我是正确的。我的主要观点是双重编码问题。
Content-Type 仍然是 text/html; charset=iso-8859-1 不知道我在做什么错...
为了安全起见,最好确认 res.ok 以防响应代码出现某种错误。最后有一个 .catch() 子句也很好。我意识到这只是一个示例片段,但请记住这些事情以供实际使用。
y
yousoumar

我认为您的问题是 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.日志(资源));


这是正确的解决方案,句号 - 其他所有人似乎都混淆了 x-www-form-urlencodedapplication/json,要么不匹配,要么将 JSON 双重包装在 url 编码的字符串中。
但这不适用于 jsfiddle。所以,我不确定我是否理解你为什么会说“这是正确的解决方案,句号”。不是其他人都在做包装来满足 jsfiddle 的 /echo 路由的 API 吗?
对于不熟悉箭头函数的用户,您必须在此处返回 res.json(),以便在下一次 .then() 调用中获取数据。
我认为方法拼写为 POST 而不是 post?
它将在某个地方修复(fetch.js 或 http 服务器,idk)。但是你在这里,http动词区分大小写..
z
zaghadon

从搜索引擎中,我最终在这个主题上使用 fetch 发布非 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-stringqs 包中的 stringify 函数。所以使用它看起来像:

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

非常感谢您提供查询字符串,我用 JSON.stringify 尝试了很多次,但 ajax 没有返回响应。但查询字符串成功了。我还发现这是因为 fetch create json for body params 而不是创建字符串。
谢谢你,兄弟!这是最好的回复!我昨天碰壁了几个小时,试图找到一种方法将带有表单数据的“正文”从我的 Web 应用程序发送到我的服务器......一个建议:$ npm install cors --save 这是摆脱“ mode : 'no-cors'" 在 Fetch 请求中参见 github.com/expressjs/cors
谢谢@AlexanderCherednichenko!感谢分享 cors 笔记,这是一个我不知道的有趣的笔记。 :)
非常感谢,我完全错过了正确的 Content-type,我的 PHP 后端没有收到任何东西。 'application/x-www-form-urlencoded' 已正确修复。
发自内心的感谢。你两次节省了我的时间和生命:)
I
Iain Collins

在花费了一些时间后,对 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/ &&火狐> 39&&铬 > 42


为什么是 'x-www-form-urlencoded 而不是 application/json?有什么不同?
@JuanPicado - 在 2 年前的 jsfiddle 逆向工程之后,它只是一种可行的选择。当然 application/json 是正确的形式,并且现在可以使用。谢谢你的好眼光:)
哟。奇怪的细节,它以旧方式对我有用,使用 fetch (stackoverflow.com/questions/41984893/…) 而不是 application/json。也许你知道为什么...
Content-Typeapplication/json,但您的实际 body 似乎是 x-www-form-urlencoded - 我认为这应该行不通?如果它确实有效,那么您的服务器必须非常宽容。下面@vp_arth 的答案似乎是正确的。
是的,'Content-Type': 'application/json' 是错误的,因为正文是作为 x-www-form-urlencoded 发送的
T
Tellisense

2021 年回答:以防万一您来到这里寻找如何使用 async/await 或与 axios 相比的 Promise 进行 GET 和 POST Fetch api 请求。

我正在使用 jsonplaceholder fake API 来演示:

使用 async/await 获取 api GET 请求:

         const asyncGetCall = async () => {
            try {
                const response = await fetch('https://jsonplaceholder.typicode.com/posts');
                 const data = await response.json();
                // enter you logic when the fetch is successful
                 console.log(data);
               } catch(error) {
            // enter your logic for when there is an error (ex. error toast)
                  console.log(error)
                 } 
            }


          asyncGetCall()

使用 async/await 获取 api POST 请求:

    const asyncPostCall = async () => {
            try {
                const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
                 method: 'POST',
                 headers: {
                   'Content-Type': 'application/json'
                   },
                   body: JSON.stringify({
             // your expected POST request payload goes here
                     title: "My post title",
                     body: "My post content."
                    })
                 });
                 const data = await response.json();
              // enter you logic when the fetch is successful
                 console.log(data);
               } catch(error) {
             // enter your logic for when there is an error (ex. error toast)

                  console.log(error)
                 } 
            }

asyncPostCall()

使用 Promises 获取请求:

  fetch('https://jsonplaceholder.typicode.com/posts')
  .then(res => res.json())
  .then(data => {
   // enter you logic when the fetch is successful
    console.log(data)
  })
  .catch(error => {
    // enter your logic for when there is an error (ex. error toast)
   console.log(error)
  })

使用 Promises 的 POST 请求:

fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
   body: JSON.stringify({
     // your expected POST request payload goes here
      title: "My post title",
      body: "My post content."
      })
})
  .then(res => res.json())
  .then(data => {
   // enter you logic when the fetch is successful
    console.log(data)
  })
  .catch(error => {
  // enter your logic for when there is an error (ex. error toast)
   console.log(error)
  })  

使用 Axios 获取请求:

        const axiosGetCall = async () => {
            try {
              const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts')
    // enter you logic when the fetch is successful
              console.log(`data: `, data)
           
            } catch (error) {
    // enter your logic for when there is an error (ex. error toast)
              console.log(`error: `, error)
            }
          }
    
    axiosGetCall()

使用 Axios 的 POST 请求:

const axiosPostCall = async () => {
    try {
      const { data } = await axios.post('https://jsonplaceholder.typicode.com/posts',  {
      // your expected POST request payload goes here
      title: "My post title",
      body: "My post content."
      })
   // enter you logic when the fetch is successful
      console.log(`data: `, data)
   
    } catch (error) {
  // enter your logic for when there is an error (ex. error toast)
      console.log(`error: `, error)
    }
  }


axiosPostCall()

F
Francisco Presencia

如果您使用的是纯 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 完全正确,当时我不知道这种细微差别,但现在这是我这样做的唯一方法
M
Marcus Lind

这与 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'}
})

我的后端开发人员使用 PHP 构建了 API,期望数据是查询字符串,而不是 json 对象。这解决了服务器端的空响应。
y
yousoumar

有同样的问题 - 没有 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 => {
   ...
})

k
kungfooman

最佳答案不适用于 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);
    });
}

D
Daniel García

我认为,我们不需要将 JSON 对象解析为字符串,如果远程服务器接受 json 到他们的请求中,只需运行:

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

比如 curl 请求

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 请求

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

这是明显不正确的。无论您是否需要对 json 进行字符串化,它与服务器端无关。这正是您的 curl 命令正在隐式执行的操作!如果您在将对象作为 body 传递之前没有对它们进行字符串化,那么您只需将 "[object Object]" 作为请求的正文发送。开发工具中的一个简单测试会告诉你这一点。打开它并在不离开此标签的情况下尝试:a = new FormData(); a.append("foo","bar"); fetch("/foo/bar", { method: 'POST', body: {}, headers: { 'Content-type': 'application/json' } })
u
user_CC

它可能对某人有用:

我遇到了没有为我的请求发送表单数据的问题

在我的情况下,以下标题的组合也导致了问题和错误的 Content-Type。

因此,我将这两个标头与请求一起发送,当我删除有效的标头时,它没有发送表单数据。

“X-Prototype-Version”:“1.6.1”,“X-Requested-With”:“XMLHttpRequest”

此外,其他答案表明 Content-Type 标头需要正确。

对于我的请求,正确的 Content-Type 标头是:

“内容类型”:“应用程序/x-www-form-urlencoded;charset=UTF-8”

因此,如果您的表单数据未附加到请求中,那么底线可能是您的标题。尝试将您的标题减少到最低限度,然后尝试逐个添加它们以查看您的问题是否已解决。


E
Eric Sellin

如果您的 JSON 有效负载包含数组和嵌套对象,我将使用 URLSearchParams 和 jQuery 的 param() 方法。

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

对于您的服务器来说,这看起来像是一个标准的 HTML <form> 正在POST编辑。


C
Cassio Seffrin

使用 await/async 可以做得更好。

http请求的参数:

const _url = 'https://jsonplaceholder.typicode.com/posts';
let _body = JSON.stringify({
  title: 'foo',
  body: 'bar',
  userId: 1,
});
  const _headers = {
  'Content-type': 'application/json; charset=UTF-8',
};
const _options = { method: 'POST', headers: _headers, body: _body };

使用干净的 async/await 语法:

const response = await fetch(_url, _options);
if (response.status >= 200 && response.status <= 204) {
  let data = await response.json();
  console.log(data);
} else {
  console.log(`something wrong, the server code: ${response.status}`);
}

使用老式 fetch().then().then():

fetch(_url, _options)
  .then((res) => res.json())
  .then((json) => console.log(json));

A
Ahmed Shahin

您只需要检查响应是否正常,因为呼叫没有返回任何内容。

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((response) => {if(response.ok){alert("the call works ok")}})
.catch (function (error) {
    console.log('Request failed', error);
});    

b
bortunac

我的简单目标是js object ->-> php $_POST

Object.defineProperties(FormData.prototype, { // extend FormData for direct use of js objects
    load: {
       value: function (d) {
                   for (var v in d) {
                      this.append(v, typeof d[v] === 'string' ? d[v] : JSON.stringify(d[v]));
                   }
               }
           }
   })

var F = new FormData;
F.load({A:1,B:2});

fetch('url_target?C=3&D=blabla', {
        method: "POST", 
          body: F
     }).then( response_handler )

y
yuchen huang

您可以使用 fill-fetch,它是 fetch 的扩展。简单地说,您可以发布如下数据:

import { fill } from 'fill-fetch';

const fetcher = fill();

fetcher.config.timeout = 3000;
fetcher.config.maxConcurrence = 10;
fetcher.config.baseURL = 'http://www.github.com';

const res = await fetcher.post('/', { a: 1 }, {
    headers: {
        'bearer': '1234'
    }
});