从 fetch() 中提取 JSON 和 headers
extract both JSON and headers from fetch()
我正在为一个简单的 react/redux 应用程序的身份验证层建模。在服务器端,我有一个基于 devise_token_auth gem.
的 API
我正在使用 fetch
来 post 登录请求:
const JSON_HEADERS = new Headers({
'Content-Type': 'application/json'
});
export const postLogin = ({ email, password }) => fetch(
`${API_ROOT}/v1/auth/sign_in`, {
method: 'POST',
headers: JSON_HEADERS,
body: JSON.stringify({ email, password })
});
// postLogin({ email: 'test@test.it', password: 'whatever' });
这有效,我得到了 200 响应和我需要的所有数据。我的问题是,信息在响应 body 和 headers 之间分配。
- Body: 用户信息
- Headers:access-token、过期等
我可以这样解析 JSON body:
postLogin({ 'test@test.it', password: 'whatever' })
.then(res => res.json())
.then(resJson => dispatch(myAction(resJson))
但是 myAction
不会从 headers 中获取任何数据(在解析 JSON 时丢失)。
有没有办法从 fetch
请求中同时获得 headers 和 body?
谢谢!
使用async/await:
const res = await fetch('/url')
const json = await res.json()
doSomething(headers, json)
没有async/await:
fetch('/url')
.then( res => {
const headers = res.headers.raw())
return new Promise((resolve, reject) => {
res.json().then( json => resolve({headers, json}) )
})
})
.then( ({headers, json}) => doSomething(headers, json) )
这种 Promise
的方法更通用。它在所有情况下都有效,即使不方便创建捕获 res
变量的闭包(如此处的其他答案)。例如,当处理程序更复杂并提取(重构)为单独的函数时。
我想我会分享我们最终解决这个问题的方法:只需在 .then
链中添加一个步骤(在解析 JSON 之前)来解析 auth headers 并派遣适当的行动:
fetch('/some/url')
.then(res => {
const authHeaders = ['access-token', 'client', 'uid']
.reduce((result, key) => {
let val = res.headers.get(key);
if (val) {
result[key] = val;
}
}, {});
store.dispatch(doSomethingWith(authHeaders)); // or localStorage
return res;
})
.then(res => res.json())
.then(jsonResponse => doSomethingElseWith(jsonResponse))
另一种方法,灵感来自强大的 Dan Abramov (http://whosebug.com/a/37099629/1463770)
fetch('/some/url')
.then(res => res.json().then(json => ({
headers: res.headers,
status: res.status,
json
}))
.then({ headers, status, json } => goCrazyWith(headers, status, json));
HTH
我的 WP 解决方案 json API
fetch(getWPContent(searchTerm, page))
.then(response => response.json().then(json => ({
totalPages: response.headers.get("x-wp-totalpages"),
totalHits: response.headers.get("x-wp-total"),
json
})))
.then(result => {
console.log(result)
})
如果您想将所有 headers 解析为一个 object(而不是保留迭代器),您可以执行以下操作(基于上面 Dan Abramov 的方法):
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => (res.headers.get('content-type').includes('json') ? res.json() : res.text())
.then(data => ({
headers: [...res.headers].reduce((acc, header) => {
return {...acc, [header[0]]: header[1]};
}, {}),
status: res.status,
data: data,
}))
.then((headers, status, data) => console.log(headers, status, data)));
或 async
context/function:
let response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await (
response.headers.get('content-type').includes('json')
? response.json()
: response.text()
);
response = {
headers: [...response.headers].reduce((acc, header) => {
return {...acc, [header[0]]: header[1]};
}, {}),
status: response.status,
data: data,
};
将导致:
{
data: [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}],
headers: {
cache-control: "public, max-age=14400"
content-type: "application/json; charset=utf-8"
expires: "Sun, 23 Jun 2019 22:50:21 GMT"
pragma: "no-cache"
},
status: 200
}
根据您的用例,这可能更方便使用。此解决方案还考虑了 content-type 在响应中调用 .json()
或 .text()
。
我正在为一个简单的 react/redux 应用程序的身份验证层建模。在服务器端,我有一个基于 devise_token_auth gem.
的 API我正在使用 fetch
来 post 登录请求:
const JSON_HEADERS = new Headers({
'Content-Type': 'application/json'
});
export const postLogin = ({ email, password }) => fetch(
`${API_ROOT}/v1/auth/sign_in`, {
method: 'POST',
headers: JSON_HEADERS,
body: JSON.stringify({ email, password })
});
// postLogin({ email: 'test@test.it', password: 'whatever' });
这有效,我得到了 200 响应和我需要的所有数据。我的问题是,信息在响应 body 和 headers 之间分配。
- Body: 用户信息
- Headers:access-token、过期等
我可以这样解析 JSON body:
postLogin({ 'test@test.it', password: 'whatever' })
.then(res => res.json())
.then(resJson => dispatch(myAction(resJson))
但是 myAction
不会从 headers 中获取任何数据(在解析 JSON 时丢失)。
有没有办法从 fetch
请求中同时获得 headers 和 body?
谢谢!
使用async/await:
const res = await fetch('/url')
const json = await res.json()
doSomething(headers, json)
没有async/await:
fetch('/url')
.then( res => {
const headers = res.headers.raw())
return new Promise((resolve, reject) => {
res.json().then( json => resolve({headers, json}) )
})
})
.then( ({headers, json}) => doSomething(headers, json) )
这种 Promise
的方法更通用。它在所有情况下都有效,即使不方便创建捕获 res
变量的闭包(如此处的其他答案)。例如,当处理程序更复杂并提取(重构)为单独的函数时。
我想我会分享我们最终解决这个问题的方法:只需在 .then
链中添加一个步骤(在解析 JSON 之前)来解析 auth headers 并派遣适当的行动:
fetch('/some/url')
.then(res => {
const authHeaders = ['access-token', 'client', 'uid']
.reduce((result, key) => {
let val = res.headers.get(key);
if (val) {
result[key] = val;
}
}, {});
store.dispatch(doSomethingWith(authHeaders)); // or localStorage
return res;
})
.then(res => res.json())
.then(jsonResponse => doSomethingElseWith(jsonResponse))
另一种方法,灵感来自强大的 Dan Abramov (http://whosebug.com/a/37099629/1463770)
fetch('/some/url')
.then(res => res.json().then(json => ({
headers: res.headers,
status: res.status,
json
}))
.then({ headers, status, json } => goCrazyWith(headers, status, json));
HTH
我的 WP 解决方案 json API
fetch(getWPContent(searchTerm, page))
.then(response => response.json().then(json => ({
totalPages: response.headers.get("x-wp-totalpages"),
totalHits: response.headers.get("x-wp-total"),
json
})))
.then(result => {
console.log(result)
})
如果您想将所有 headers 解析为一个 object(而不是保留迭代器),您可以执行以下操作(基于上面 Dan Abramov 的方法):
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => (res.headers.get('content-type').includes('json') ? res.json() : res.text())
.then(data => ({
headers: [...res.headers].reduce((acc, header) => {
return {...acc, [header[0]]: header[1]};
}, {}),
status: res.status,
data: data,
}))
.then((headers, status, data) => console.log(headers, status, data)));
或 async
context/function:
let response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await (
response.headers.get('content-type').includes('json')
? response.json()
: response.text()
);
response = {
headers: [...response.headers].reduce((acc, header) => {
return {...acc, [header[0]]: header[1]};
}, {}),
status: response.status,
data: data,
};
将导致:
{
data: [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}],
headers: {
cache-control: "public, max-age=14400"
content-type: "application/json; charset=utf-8"
expires: "Sun, 23 Jun 2019 22:50:21 GMT"
pragma: "no-cache"
},
status: 200
}
根据您的用例,这可能更方便使用。此解决方案还考虑了 content-type 在响应中调用 .json()
或 .text()
。