从fetch()

时间:2017-01-23 17:22:23

标签: javascript response fetch-api response-headers

我正在为一个简单的react / redux应用程序建模auth层。在服务器端,我有一个基于devise_token_auth gem的API。

我正在使用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响应和我需要的所有数据。我的问题是,信息在响应主体和标题之间分配。

  • 正文:用户信息
  • 标题:访问令牌,过期等

我可以用这种方式解析JSON主体:

postLogin({ 'test@test.it', password: 'whatever' })
  .then(res => res.json())
  .then(resJson => dispatch(myAction(resJson))

但是myAction不会从标题中获取任何数据(在解析JSON时丢失)。

有没有办法从fetch请求中获取标题和正文? 谢谢!

4 个答案:

答案 0 :(得分:4)

我想我会分享我们最终解决这个问题的方式:只需在.then链中添加一个步骤(在解析JSON之前)来解析auth头并调度正确的操作:

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

另一种方法,受到强大的丹阿布拉莫夫(http://stackoverflow.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

答案 1 :(得分:0)

可能是这样的:

postLogin({ 'test@test.it', password: 'whatever' })
  .then(res => {
    processHeader(res.headers.raw())
    dispatch(myAction(res.json()))
  })

答案 2 :(得分:0)

我对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)
  })

答案 3 :(得分:0)

如果您想将所有标头解析为一个对象(而不是保留迭代器),则可以执行以下操作(基于上述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上下文/函数中:

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()的内容类型。