使用Fetch API,处理错误时如何访问JSON数据

时间:2019-04-16 09:26:10

标签: javascript fetch-api

我们的API服务器返回带有错误响应的JSON数据。我找不到在错误处理方法上处理JSON数据的标准方法。我当前的解决方案是这样。它正在工作,但是我想在catch()方法中处理错误,而不是then();

let url = 'http://localhost:8080';
    let data = {'field': 'value'};
    fetch(url, {
      method: 'PUT',
      body: JSON.stringify(data),
      credentials: 'same-origin',
      mode: 'cors',
      headers: {
        'content-type': 'application/json',
        'accept': 'application/json'        
      }
    })
      .then(res => {
        if (res.status == 400) {
          return res.json();
        } else if (!res.ok) {
          throw (res);
        } else {
          return res.json();
        }
      }).then(data => {
        if (data.status == 400) {
          throw (data);
        }
        return (data);
      }).catch(err => {
        if (err.status == 400) {
          throw this.handleError(err); 
        } else {
          throw new Error(`HTTP Error ${err.status}`);
        }
      });

这是来自服务器的JSON响应的示例。

{
    "parameters": {
        "type": {
            "isEmpty": "Field is required and cannot be empty"
        },
        "from": {
            "isEmpty": "Field is required and cannot be empty"
        },
        "to": {
            "isEmpty": "Field is required and cannot be empty"
        }
    },
    "title": "Invalid parameter",
    "type": "/api/doc/invalid-parameter",
    "status": 400,
    "detail": "Invalid parameter"
}

1 个答案:

答案 0 :(得分:1)

我会在fetch周围做一个薄薄的包装,它会引发> = 400个带有已解析主体的响应,否则会解析成功响应。

function parse(res) {
  const contentType = res.headers.get('Content-Type') || '';
  const isJson = contentType.includes('application/json');
  return isJson ? res.json() : res;
}

async function throwOnError(res) {
  if (res.status >= 400) {
    const err = new Error(res.statusText || 'Internal Server Error');
    err.status = res.status;
    const parsedRes = await parse(res);
    err.body = parsedRes;
    throw err;
  }

  return res;
}

async function fetchWrapper({ method, url, data, headers }) {
  const combinedHeaders = {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  };

  if (headers) {
    Object.assign(combinedHeaders, headers);
  }

  const options = {
    credentials: 'same-origin',
    mode: 'cors',
    method,
    headers: combinedHeaders,
  };

  if (data) {
    options.body = JSON.stringify(data);
  }

  return fetch(url, options)
    .then(throwOnError)
    .then(parse);
}

const queryParams = (params) =>
  Object.keys(params)
    .filter(k => params[k] !== null && typeof params[k] !== 'undefined')
    .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)
    .join('&');

export const appendUrlParams = (url, params) => (params ? `${url}?${queryParams(params)}` : url);

export const $get = (url, params, { ...options }) =>
  fetchWrapper({ method: 'GET', url: appendUrlParams(url, params), ...options });

export const $del = (url, params, { ...options }) =>
  fetchWrapper({ method: 'DELETE', url: appendUrlParams(url, params), ...options });

export const $post = (url, data, { ...options }) =>
  fetchWrapper({ method: 'POST', url, data, ...options });

export const $put = (url, data, { ...options }) =>
  fetchWrapper({ method: 'PUT', url, data, ...options });

例如

async function fetchSomething() {
  try {
    const res = await $get('someurl');
    // Do something with successful `res`.
  } catch (err) {
    console.error(err);
    // err.status -> the status of the response
    // err.body -> the body of the response
  }
}

或者,如果您愿意,可以使用then / catch。