Извлечь как JSON, так и заголовки из fetch()
Я моделирую аутентификационный слой для простого приложения "Реакция / Избыток". На стороне сервера у меня есть API, основанный на геме devise_token_auth.
я использую fetch
чтобы разместить знак в запросе:
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: информация о пользователе
- Заголовки: токен доступа, срок действия и т. Д.
Я мог бы разобрать тело JSON следующим образом:
postLogin({ 'test@test.it', password: 'whatever' })
.then(res => res.json())
.then(resJson => dispatch(myAction(resJson))
Но потом myAction
не получит никаких данных из заголовков (потерян при анализе JSON).
Есть ли способ получить заголовки и тело от fetch
Запрос? Спасибо!
2 ответа
Я думал, что поделюсь тем, как мы наконец решили эту проблему: просто добавив шаг в .then
цепочка (перед синтаксическим анализом JSON) для анализа заголовков аутентификации и отправки правильного действия:
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))
Еще один подход, вдохновленный могущественным Даном Абрамовым ( /questions/2487077/kak-obrabatyivat-oshibki-v-otvetah-fetch-s-pomoschyu-redux-thunk/2487091#2487091)
fetch('/some/url')
.then(res => res.json().then(json => ({
headers: res.headers,
status: res.status,
json
}))
.then({ headers, status, json } => goCrazyWith(headers, status, json));
НТН
Может быть так:
postLogin({ 'test@test.it', password: 'whatever' })
.then(res => {
processHeader(res.headers.raw())
dispatch(myAction(res.json()))
})
Если вы хотите проанализировать все заголовки в объект (а не сохранять итератор), вы можете сделать следующее (на основе подхода Дэна Абрамова выше):
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
контекст / функция:
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
}
в зависимости от вашего варианта использования это может быть более удобно. Это решение также учитывает тип содержимого для вызова либо.json()
или .text()
на ответ.
Мое решение для 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)
})