te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>javascript - extract both JSON and headers from fetch() - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - extract both JSON and headers from fetch() - Stack Overflow

programmeradmin3浏览0评论

I am modelling the auth layer for a simple react/redux app. On the server side I have an API based on the devise_token_auth gem.

I am using fetch to post a sign in request:

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: '[email protected]', password: 'whatever' });

This works, and I get a 200 response and all the data I need. My problem is, information is divided between the response body and headers.

  • Body: user info
  • Headers: access-token, expiration, etc.

I could parse the JSON body this way:

postLogin({ '[email protected]', password: 'whatever' })
  .then(res => res.json())
  .then(resJson => dispatch(myAction(resJson))

But then myAction would not get any data from the headers (lost while parsing JSON).

Is there a way to get both headers and body from a fetch Request? Thanks!

I am modelling the auth layer for a simple react/redux app. On the server side I have an API based on the devise_token_auth gem.

I am using fetch to post a sign in request:

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: '[email protected]', password: 'whatever' });

This works, and I get a 200 response and all the data I need. My problem is, information is divided between the response body and headers.

  • Body: user info
  • Headers: access-token, expiration, etc.

I could parse the JSON body this way:

postLogin({ '[email protected]', password: 'whatever' })
  .then(res => res.json())
  .then(resJson => dispatch(myAction(resJson))

But then myAction would not get any data from the headers (lost while parsing JSON).

Is there a way to get both headers and body from a fetch Request? Thanks!

Share Improve this question edited Dec 19, 2018 at 11:43 nerfologist asked Jan 23, 2017 at 17:22 nerfologistnerfologist 7711 gold badge10 silver badges23 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 11

I thought I'd share the way we finally solved this problem: by just adding a step in the .then chain (before parsing the JSON) to parse the auth headers and dispatch the proper action:

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

One more approach, inspired by the mighty Dan Abramov (http://stackoverflow./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

Using async/await:

const res = await fetch('/url')
const json = await res.json()
doSomething(headers, json)

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

This approach with Promise is more general. It is working in all cases, even when it is inconvenient to create a closure that captures res variable (as in the other answer here). For example when handlers is more plex and extracted (refactored) to separated functions.

My solution for the 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)
  })

If you want to parse all headers into an object (rather than keeping the Iterator) you can do as follows (based on Dan Abramov's approach above):

fetch('https://jsonplaceholder.typicode./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)));

or within an async context/function:

let response = await fetch('https://jsonplaceholder.typicode./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,
};

will result in:

{
    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
}

depending on your use case this might be more convenient to use. This solution also takes into account the content-type to call either .json() or .text() on the response.

发布评论

评论列表(0)

  1. 暂无评论