Giter Site home page Giter Site logo

umi-request's Introduction

English | 简体中文

umi-request

The network request library, based on fetch encapsulation, combines the features of fetch and axios to provide developers with a unified api call method, simplifying usage, and providing common functions such as caching, timeout, character encoding processing, and error handling.

NPM version Build Status NPM downloads


Supported features

  • url parameter is automatically serialized
  • post data submission method is simplified
  • response return processing simplification
  • api timeout support
  • api request cache support
  • support for processing gbk
  • request and response interceptor support like axios
  • unified error handling
  • middleware support
  • cancel request support like axios
  • make http request from node.js

umi-request vs fetch vs axios

Features umi-request fetch axios
implementation Browser native support Browser native support XMLHttpRequest
size 9k 4k (polyfill) 14k
query simplification
post simplification
timeout
cache
error Check
error Handling
interceptor
prefix
suffix
processing gbk
middleware
cancel request

For more discussion, refer to Traditional Ajax is dead, Fetch eternal life If you have good suggestions and needs, please mention issue

TODO Welcome pr

  • Test case coverage 85%+
  • write a document
  • CI integration
  • release configuration
  • typescript

Installation

npm install --save umi-request

Example

Performing a GET request

import request from 'umi-request';

request
  .get('/api/v1/xxx?id=1')
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    console.log(error);
  });

// use options.params
request
  .get('/api/v1/xxx', {
    params: {
      id: 1,
    },
  })
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    console.log(error);
  });

Performing a POST request

request
  .post('/api/v1/user', {
    data: {
      name: 'Mike',
    },
  })
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    console.log(error);
  });

umi-request API

Requests can be made by passing relevant options to umi-request

umi-request(url[, options])

import request from 'umi-request';

request('/api/v1/xxx', {
  method: 'get',
  params: { id: 1 },
})
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    console.log(error);
  });

request('/api/v1/user', {
  method: 'post',
  data: {
    name: 'Mike',
  },
})
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    console.log(error);
  });

Request method aliases

For convenience umi-request have been provided for all supported methods.

request.get(url[, options])

request.post(url[, options])

request.delete(url[, options])

request.put(url[, options])

request.patch(url[, options])

request.head(url[, options])

request.options(url[, options])

Creating an instance

You can use extend({[options]}) to create a new instance of umi-request.

extend([options])

import { extend } from 'umi-request';

const request = extend({
  prefix: '/api/v1',
  timeout: 1000,
  headers: {
    'Content-Type': 'multipart/form-data',
  },
});

request
  .get('/user')
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    console.log(error);
  });

Create an instance of umi-request in NodeJS enviroment

const umi = require('umi-request');
const extendRequest = umi.extend({ timeout: 10000 });

extendRequest('/api/user')
  .then(res => {
    console.log(res);
  })
  .catch(err => {
    console.log(err);
  });

The available instance methods are list below. The specified options will be merge with the instance options.

request.get(url[, options])

request.post(url[, options])

request.delete(url[, options])

request.put(url[, options])

request.patch(url[, options])

request.head(url[, options])

request.options(url[, options])

More umi-request cases can see antd-pro

request options

Parameter Description Type Optional Value Default
method request method string get , post , put ... get
params url request parameters object or URLSearchParams -- --
data Submitted data any -- --
headers fetch original parameters object -- {}
timeout timeout, default millisecond, write with caution number --
timeoutMessage customize timeout error message, please config timeout first string -- --
prefix prefix, generally used to override the uniform settings prefix string -- --
suffix suffix, such as some scenes api need to be unified .json string --
credentials fetch request with cookies string -- credentials: 'same-origin'
useCache Whether to use caching (only support browser environment) boolean -- false
validateCache cache strategy function (url, options) => boolean -- only get request to cache
ttl Cache duration, 0 is not expired number -- 60000
maxCache Maximum number of caches number -- 0(Infinity)
requestType post request data type string json , form json
parseResponse response processing simplification boolean -- true
charset character set string utf8 , gbk utf8
responseType How to parse the returned data string json , text , blob , formData ... json , text
throwErrIfParseFail throw error when JSON parse fail and responseType is 'json' boolean -- false
getResponse Whether to get the source response, the result will wrap a layer boolean -- fasle
errorHandler exception handling, or override unified exception handling function(error) --
cancelToken Token to cancel request CancelToken.token -- --

The other parameters of fetch are valid. See fetch documentation

extend options Initialize default parameters, support all of the above

Parameter Description Type Optional Value Default
method request method string get , post , put ... get
params url request parameters object -- --
data Submitted data any -- --
...
{
  // 'method' is the request method to be used when making the request
  method: 'get', // default

  // 'params' are the URL parameters to be sent with request
  // Must be a plain object or a URLSearchParams object
  params: { id: 1 },

  // 'paramSerializer' is a function in charge of serializing 'params'. ( be aware of 'params' was merged by extends's 'params' and request's 'params' and URLSearchParams will be transform to plain object. )
  paramsSerializer: function (params) {
    return Qs.stringify(params, { arrayFormat: 'brackets' })
  },

  // 'data' 作为请求主体被发送的数据
  // 适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
  // 必须是以下类型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属:FormData, File, Blob
  // - Node 专属: Stream

  // 'data' is the data to be sent as the request body
  // Only applicable for request methods 'PUT', 'POST', and 'PATCH'
  // Must be of one of the following types:
  // 1. string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // 2. Browser only: FormData, File, Blob
  // 3. Node only: Stream
  data: { name: 'Mike' },

  // 'headers' are custom headers to be sent
  headers: { 'Content-Type': 'multipart/form-data' },

  // 'timeout' specifies the number of milliseconds before the request times out.
  // If the request takes longer than 'timeout', request will be aborted and throw RequestError.
  timeout: 1000,

  // ’prefix‘ used to set URL's prefix
  // ( e.g. request('/user/save', { prefix: '/api/v1' }) => request('/api/v1/user/save') )
  prefix: '',

  // ’suffix‘ used to set URL's suffix
  // ( e.g. request('/api/v1/user/save', { suffix: '.json'}) => request('/api/v1/user/save.json') )
  suffix: '',

  // 'credentials' indicates whether the user agent should send cookies from the other domain in the case of cross-origin requests.
  // omit: Never send or receive cookies.
  // same-origin: Send user credentials (cookies, basic http auth, etc..) if the URL is on the same origin as the calling script. This is the default value.
  // include: Always send user credentials (cookies, basic http auth, etc..), even for cross-origin calls.
  credentials: 'same-origin', // default

  // ’useCache‘ The GET request would be cache in ttl milliseconds when 'useCache' is true.
  // The cache key would be 'url + params + method'.
  useCache: false, // default

  // 'ttl' cache duration(milliseconds),0 is infinity
  ttl: 60000,

  // 'maxCache' are the max number of requests to be cached, 0 means infinity.
  maxCache: 0,

  // According to http protocal, request of GET used to get data from server, it's necessary to cache response data when server data update not frequently. We provide 'validateCache'
  // for some cases that need to cache data with other method reqeust.
  validateCache: (url, options) => { return options.method.toLowerCase() === 'get' },


  // 'requestType' umi-request will add headers and body according to the 'requestType' when the type of data is object or array.
  // 1. requestType === 'json' :(default )
  // options.headers = {
  //   Accept: 'application/json',
  //   'Content-Type': 'application/json;charset=UTF-8',
  //   ...options.headers,
  // }
  // options.body = JSON.stringify(data)
  //
  // 2. requestType === 'form':
  // options.headers = {
  //   Accept: 'application/json',
  //   'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
  //   ...options.headers,
  // };
  // options.body = query-string.stringify(data);
  //
  // 3. other requestType
  // options.headers = {
  //   Accept: 'application/json',
  //   ...options.headers,
  // };
  // options.body = data;
  requestType: 'json', // default

  // 'parseResponse' whether processing response
  parseResponse: true, // default

  // 'charset' This parameter can be used when the server returns gbk to avoid garbled characters.(parseResponse should set to true)
  charset: 'gbk',

  // 'responseType': how to processing response.(parseResponse should be true)
  // The default value is 'json', would processing response by Response.text().then( d => JSON.parse(d) )
  // Other responseType (text, blob, arrayBuffer, formData), would processing response by Response[responseType]()
  responseType: 'json', // default

  // 'throwErrIfParseFail': whether throw error or not when JSON parse data fail and responseType is 'json'.
  throwErrIfParseFail: false, // default

  // 'getResponse': if you need the origin Response, set true and will return { data, response }.
  getResponse: false,// default

  // 'errorHandler' error handle entry.
  errorHandler: function(error) { /* 异常处理 */ },

  // 'cancelToken' the token of cancel request.
  cancelToken: null,
}

Extend Options

Sometimes we need to update options after extend a request instance, umi-request provide extendOptions for users to update options:

const request = extend({ timeout: 1000, params: { a: '1' } });
// default options is: { timeout: 1000, params: { a: '1' }}

request.extendOptions({ timeout: 3000, params: { b: '2' } });
// after extendOptions: { timeout: 3000, params: { a: '1', b: '2' }}

Response Schema

The response for a request contains the following information.

{
  // 'data' is the response that was provided by the server
  data: {},

  // 'status' is the HTTP status code from the server response
  status: 200,

  // 'statusText' is the HTTP status message from the server response
  statusText: 'OK',

  // 'headers' the headers that the server responded with
  // All header names are lower cased
  headers: {},
}

When options.getResponse === false, the response schema would be 'data'

request.get('/api/v1/xxx', { getResponse: false }).then(function(data) {
  console.log(data);
});

When options.getResponse === true ,the response schema would be { data, response }

request.get('/api/v1/xxx', { getResponse: true }).then(function({ data, response }) {
  console.log(data);
  console.log(response.status);
  console.log(response.statusText);
  console.log(response.headers);
});

You can get Response from error object in errorHandler or request.catch.

Error handling

import request, { extend } from 'umi-request';

const errorHandler = function(error) {
  const codeMap = {
    '021': 'An error has occurred',
    '022': 'It’s a big mistake,',
    // ....
  };
  if (error.response) {
    // The request was made and the server responded with a status code
    // that falls out of the range of 2xx
    console.log(error.response.status);
    console.log(error.response.headers);
    console.log(error.data);
    console.log(error.request);
    console.log(codeMap[error.data.status]);
  } else {
    // The request was made but no response was received or error occurs when setting up the request.
    console.log(error.message);
  }

  throw error; // If throw. The error will continue to be thrown.

  // return {some: 'data'}; If return, return the value as a return. If you don't write it is equivalent to return undefined, you can judge whether the response has a value when processing the result.
  // return {some: 'data'};
};

// 1. Unified processing
const extendRequest = extend({ errorHandler });

// 2. Separate special treatment
// If unified processing is configured, but an api needs special handling. When requested, the errorHandler is passed as a parameter.
request('/api/v1/xxx', { errorHandler });

// 3. not configure errorHandler, the response will be directly treated as promise, and it will be caught.
request('/api/v1/xxx')
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    return errorHandler(error);
  });

Middleware

Expressive HTTP middleware framework for node.js. For development to enhance before and after request. Support create instance, global, core middlewares.

Instance Middleware (default) request.use(fn) Different instances's instance middleware are independence. Global Middleware request.use(fn, { global: true }) Different instances share global middlewares. Core Middleware request.use(fn, { core: true }) Used to expand request core.

request.use(fn[, options])

params

fn params

  • ctx(Object):context, content request and response
  • next(Function):function to call the next middleware

options params

  • global(boolean): whether global, higher priority than core
  • core(boolean): whether core

example

  1. same type of middlewares
import request, { extend } from 'umi-request';
request.use(async (ctx, next) => {
  console.log('a1');
  await next();
  console.log('a2');
});
request.use(async (ctx, next) => {
  console.log('b1');
  await next();
  console.log('b2');
});

const data = await request('/api/v1/a');

order of middlewares be called:

a1 -> b1 -> response -> b2 -> a2
  1. Different type of middlewares
request.use(async (ctx, next) => {
  console.log('instanceA1');
  await next();
  console.log('instanceA2');
});
request.use(async (ctx, next) => {
  console.log('instanceB1');
  await next();
  console.log('instanceB2');
});
request.use(
  async (ctx, next) => {
    console.log('globalA1');
    await next();
    console.log('globalA2');
  },
  { global: true }
);
request.use(
  async (ctx, next) => {
    console.log('coreA1');
    await next();
    console.log('coreA2');
  },
  { core: true }
);

order of middlewares be called:

instanceA1 -> instanceB1 -> globalA1 -> coreA1 -> coreA2 -> globalA2 -> instanceB2 -> instanceA2
  1. Enhance request
request.use(async (ctx, next) => {
  const { req } = ctx;
  const { url, options } = req;

  if (url.indexOf('/api') !== 0) {
    ctx.req.url = `/api/v1/${url}`;
  }
  ctx.req.options = {
    ...options,
    foo: 'foo',
  };

  await next();

  const { res } = ctx;
  const { success = false } = res;
  if (!success) {
    // ...
  }
});
  1. Use core middleware to expand request core.
request.use(
  async (ctx, next) => {
    const { req } = ctx;
    const { url, options } = req;
    const { __umiRequestCoreType__ = 'normal' } = options;

    // __umiRequestCoreType__ use to identificat request core
    // when value is 'normal' , use umi-request 's fetch request core
    if (__umiRequestCoreType__ === 'normal') {
      await next();
      return;
    }

    // when value is not normal, use your request func.
    const response = getResponseByOtherWay();

    ctx.res = response;

    await next();
    return;
  },
  { core: true }
);

request('/api/v1/rpc', {
  __umiRequestCoreType__: 'rpc',
  parseResponse: false,
})
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    console.log(error);
  });

Interceptor

You can intercept requests or responses before they are handled by then or catch.

  1. global Interceptor
// request interceptor, change url or options.
request.interceptors.request.use((url, options) => {
  return {
    url: `${url}&interceptors=yes`,
    options: { ...options, interceptors: true },
  };
});

// Same as the last one
request.interceptors.request.use(
  (url, options) => {
    return {
      url: `${url}&interceptors=yes`,
      options: { ...options, interceptors: true },
    };
  },
  { global: true }
);

// response interceptor, chagne response
request.interceptors.response.use((response, options) => {
  response.headers.append('interceptors', 'yes yo');
  return response;
});

// handling error in response interceptor
request.interceptors.response.use(response => {
  const codeMaps = {
    502: '网关错误。',
    503: '服务不可用,服务器暂时过载或维护。',
    504: '网关超时。',
  };
  message.error(codeMaps[response.status]);
  return response;
});

// clone response in response interceptor
request.interceptors.response.use(async response => {
  const data = await response.clone().json();
  if (data && data.NOT_LOGIN) {
    location.href = '登录url';
  }
  return response;
});
  1. instance Interceptor
// Global interceptors are used `request` instance method directly
request.interceptors.request.use(
  (url, options) => {
    return {
      url: `${url}&interceptors=yes`,
      options: { ...options, interceptors: true },
    };
  },
  { global: false }
); // second paramet defaults { global: true }

function createClient(baseUrl) {
  const request = extend({
    prefix: baseUrl,
  });
  return request;
}

const clientA = createClient('/api');
const clientB = createClient('/api');
// Independent instance Interceptor
clientA.interceptors.request.use(
  (url, options) => {
    return {
      url: `${url}&interceptors=clientA`,
      options,
    };
  },
  { global: false }
);

clientB.interceptors.request.use(
  (url, options) => {
    return {
      url: `${url}&interceptors=clientB`,
      options,
    };
  },
  { global: false }
);

Cancel request

Use AbortController

Base on AbortController that allows you to abort one or more Web requests as and when desired.

// polyfill abort controller if needed
import 'yet-another-abortcontroller-polyfill'
import Request from 'umi-request';

const controller = new AbortController(); // create a controller
const { signal } = controller; // grab a reference to its associated AbortSignal object using the AbortController.signal property

signal.addEventListener('abort', () => {
  console.log('aborted!');
});

Request('/api/response_after_1_sec', {
  signal, // pass in the AbortSignal as an option inside the request's options object (see {signal}, below). This associates the signal and controller with the fetch request and allows us to abort it by calling AbortController.abort(),
});

// 取消请求
setTimeout(() => {
  controller.abort(); // Aborts a DOM request before it has completed. This is able to abort fetch requests, consumption of any response Body, and streams.
}, 100);

Use Cancel Token

Cancel Token still work, but we don’t recommend using them in the new code.

  1. You can cancel a request using a cancel token.
import Request from 'umi-request';

const CancelToken = Request.CancelToken;
const { token, cancel } = CancelToken.source();

Request.get('/api/cancel', {
  cancelToken: token,
}).catch(function(thrown) {
  if (Request.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

Request.post(
  '/api/cancel',
  {
    name: 'hello world',
  },
  {
    cancelToken: token,
  }
);

// cancel request (the message parameter is optional)
cancel('Operation canceled by the user.');
  1. You can also create a cancel token by passing an executor function to the CancelToken constructor:
import Request from 'umi-request';

const CancelToken = Request.CancelToken;
let cancel;

Request.get('/api/cancel', {
  cancelToken: new CancelToken(function executor(c) {
    cancel = c;
  }),
});

// cancel request
cancel();

Cases

How to get Response Headers

Use Headers.get() (more detail see MDN 文档)

request('/api/v1/some/api', { getResponse: true }).then(({ data, response }) => {
  response.headers.get('Content-Type');
});

If want to get a custem header, you need to set Access-Control-Expose-Headers on server.

File upload

Use FormData() contructor,the browser will add request header "Content-Type: multipart/form-data" automatically, developer don't need to add request header Content-Type

const formData = new FormData();
formData.append('file', file);
request('/api/v1/some/api', { method: 'post', data: formData, requestType: 'form',});

The Access-Control-Expose-Headers response header indicates which headers can be exposed as part of the response by listing their names.Access-Control-Expose-Headers

Development and debugging

  • npm install
  • npm run dev
  • npm link
  • Then go to the project you are testing to execute npm link umi-request
  • Introduced and used

Questions & Suggestions

Please open an issue here.

Code Contributors

  • @clock157
  • @yesmeck
  • @yutingzhao1991

LICENSE

MIT

umi-request's People

Contributors

ahmadmayo avatar atzcl avatar chenjsh36 avatar chenshuai2144 avatar clock157 avatar diamondyuan avatar focus7eleven avatar foreverart avatar handycode avatar jiangkaifree avatar ourfeel avatar saturnism avatar sorrycc avatar suxin2017 avatar ttys026 avatar weishaodaren avatar wood3n avatar wynterding avatar wzb3422 avatar xchunzhao avatar xiabaiyang avatar xiaohuoni avatar ycjcl868 avatar yesmeck avatar yutingzhao1991 avatar zouxiaomingya avatar zven21 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

umi-request's Issues

data为Array时会有问题

传递的data为数组时,代码里面校验Object.prototype.toString.call(data) === "[object Object]" 是有问题的,
应该加上[object Array]这个校验才对,[{foo:"bar"}]也属于json类型

errorHandler 的error中没有request请求的参数?

想在token过期时无感知的刷新token并继续执行原有的操作,在errorHandler中捕获到401错误,刷新token成功后,再次调用原先请求,但是没有post请求body里面的参数,请问这个有什么更好解决办法嘛?如果使用response拦截器的话,重新请求了接口还是会再走一遍errorHandler函数,在yield call()中得不到正确的返回结果...

form 转化有问题

post 使用form-data方式转化有点问题的.

1.不支持三级对象.
2.数组会丢失,自动转成对象. 如,{cheked:[1,2,3]} 会转化成 checked:1 && checked:2 checked:3 ,应该是
checked[]:1 && checked[]:2 checked[]:3
3.json字符串,自动转成对象,我要的传字符串. 如 {mjson:"{a:11.b:22}"} 自动转成 mjson:object
这些都不是友好的使用方式.

post,put 请求类型处理太暴力了,请求类型有,"form-data","x-www-form-urlencoded","raw","binary"
raw 分 "json","text","html","javascript","xml"

然而umi-request 只支持 "form" || "json".

添加对上传文件的监听

umi-request是基于fetch的封装,当上传文件时,如何对上传文件的进度进行监听呢,像xhr.upload.onprogress

form请求问题

requestType:'form',设置这种后,请求参数为数组时,请求参数没有下标,变成这样
image
但是后端不识别,如何让请求参数变成下边这种带下标的结构
image

如何下载application/octet-stream文件?

当我使用原生fetch下载文件的时候是成功的,但是换成umi-request就报
20:1 Uncaught (in promise) SyntaxError: Unexpected token @ in JSON at position 0
错误。

  import request from 'umi-request';
   const reqUrl = `${SERVER_PRX}/contractTaskAttachment/downLoad/${attachmentId}`;
    const AUTHTOKEN = localStorage.getItem('auth_token') || '';
    request(reqUrl, {
      responseType: 'blob',
      headers: {
        Authorization: `Bearer ${AUTHTOKEN}`,
      },
    })
      .then(res => res.blob())
      .then(res => {
        const content = res;
        const blob = new Blob([content]);
        if ('download' in document.createElement('a')) {
          // 非IE下载
          const elink = document.createElement('a');
          elink.download = fileName;
          elink.style.display = 'none';
          elink.href = URL.createObjectURL(blob);
          document.body.appendChild(elink);
          elink.click();
          URL.revokeObjectURL(elink.href); // 释放URL 对象
          document.body.removeChild(elink);
        } else {
          // IE10+下载
          navigator.msSaveBlob(blob, fileName);
        }
      });

将request换成fetch就成功了。

如何处理 net::ERR_CONNECTION_REFUSED

服务端停了前端会请求出错 (net::ERR_CONNECTION_REFUSED)
但是没法处理,errorHandler里的error信息就一个字符串(TypeError: Failed to fetch)
还想通过url判断下结果获取不到,没有options信息。
是我用的不对还是errorHandler就这么简单

requestType 期待增加 multipart/form-data

目前 requestType 可选值:

json  //对应 Content-Type:application/json
form //对应 Content-Type:application/x-www-form-urlencoded

期待增加,multipart/form-data

content-type发生改变

发送前设置并打印显示是application/json

const request = extend({
  errorHandler, // 默认错误处理
  credentials: 'include', // 默认请求是否带上cookie
  mode: 'no-cors',
  headers: {
    'Content-Type': 'application/json;charset=UTF-8'
  }
});

chrome的network中看到的却是:Content-Type: text/plain;charset=UTF-8
求解

method=PATCH 时有问题

请求头不对,network 显示的是一个小写的 patch,服务端接收不到。

换成 fetch 就没问题。

return window.fetch(`/api/users/${id}`, {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(values),
});

数据放回后想进行权限判断,要怎么取到里边实际的数据啊

request.interceptors.response.use((res, options) => {
//返回的res并不是实际后端返回的数据,要怎么拿到实际的数据啊
if (
res.ret === -1 &&
(res.code === 'FALL' ||
res.code === 'SSO_FALL' ||
res.code === 'NO_PERMISSION' ||
res.code === 'ILLEGAL_REQUEST')
) {
router.push('/403');
} else if (res.ret === -1 && res.code === 'NO_LOGIN') {
goLogin();
}
return res;
});

response 返回值response 没有文档中的 data 选项, 只有 ReadableStream

背景umi-request version 1.2.11 , chrome 78.0.3904.108
请求方式

import { extend } from 'umi-request';
// errorHandler 拷贝的 ant-design-pro
const request = extend({
  errorHandler, 
  credentials: 'include', 
});

const response = request('/proxy/login', {
    method: 'POST',
    data: params,
  })

返回结果如下
{FB83A5BB-9D7D-4A2D-8CF6-078FFEA2D641}_20191126151315

问题 怎么方便的获取后台服务返回的文本?

断网下拦截不成功

hello~断网情况下发送请求,使用
image
image
image
这三种方式拦截,打断点都没走,请问是我的拦截方式不对吗
@sorrycc

cancellation support?

nice lib, 不过目前没看到有关于cancellation的内容,有考虑支持么?谢谢

请求拦截器中回调使用异步操作无法修改options的值

调用请求拦截器request.interceptors.request.use方法,在拦截器中为每个请求header添加token,因为localforage读取token是异步操作,将读取到的值设置到header中不会成功。

见代码:

// request拦截器
request.interceptors.request.use(async (url, options) => {
  options.headers.Authorization = '123';
  const token = await '456';  // 模拟localforage.getItem('token')异步操作
  options.headers.Authorization = token;

  console.log(options.headers.Authorization);  
  //  这里打印出来的Authorization值是正确的'456',
  //  真实请求中的Authorization值仍然还是'123'
  //  相同的操作换成axios没有问题
  return {url, options};
});

更好的处理 200 error

背景

目前提供的 errorHandler 只能根据状态码来判断是否出错,但是很多后端 API 错误没有基于状态,直接 json 里通过 errorCode 或者 success 来标识,所以很多开发者不知道如何处理,我们现在推荐的是通过 interceptor 来做,但是拦截器拦截的错误还是会走到 errorHandler,不优雅也不好用。

我的方案

增加一个 errorChecker 或者叫 errorDetector,识别错误

const errorHandler = error => {
}

// 200 需要识别的错误, 如果是错误继续进入 errorHandler
const errorChecker = data => {
    return !data.success || someStatus === 'failed';
}

const request = extend({
  errorChecker,  // 只有需要检查 200 错误才加,有状态的错误还是走之前逻辑。
  errorHandler, // 默认错误处理
  credentials: 'include', // 默认请求是否带上cookie
});

你们觉得如何?有没有更好的方案和意见

@sorrycc @yesmeck @afc163 @yutingzhao1991 @zhanba

没有正确导出ResponseError

在typescript中使用。

errorHandler: (error) => {
    // 集中处理请求错误
    const { response = {} } = error; ------->error:类型“Error”上不存在属性“response”
    const { status } = response;
    console.warn('error', error);
    let errorMessage = '请求错误,请重试!';
    switch (status) {
      case 500:
        errorMessage = '服务器异常';
        break;
      default:
        break;
  },

headers 请求头设置问题

requestType: "json",
headers: {
accept: "application/json",
content-type: "application/json"
}
请求头内容如上,
发起请求时,实际得到的请求头为
Accept: application/json; ,application/json
Content-Type: application/json;UTF-8 , application/json
手动设置的与默认的自动拼接到一起,中间还有个逗号
只有当accept 和 content-type 大小写完全一致时才不会出现该错误

上传文件

使用 application/x-www-form-urlencoded; charset=utf-8 请求实体为 formData 但多了分隔符
image
使用 multipart/form-data 也是类似
image
如实现如下(使用axios实现的)效果我应该怎么处理呢,现在不清楚是bug还是我配置的不对,能否帮忙解答一下
image

关于useCache: true, ttl: 10000一些疑问

// 使用缓存, 只有get时有效. 单位毫秒, 不加ttl默认60s, ttl=0不过期. cache key为url+params组合
request('/api/v1/some/api', { params: { hello: 'world' }, useCache: true, ttl: 10000 });

这个使用后,试缓存再那里的呢?浏览器的localStorage我没有看到,谢谢:)

中间件获取响应头

使用中间件处理请求,返回的接口如下,在其他issue里面有说通过headers,能过拿到响应头。但是好像没找见。
image

response 拦截器中不能获取到 response headers

我用ant-design-pro搭建后台管理系统,使用的是umi-request 是1.0.4,但是发现 每次查询返回的数据是对的 但是response.headers 都是空,而真实返回的头是有的 。 我们的服务器返回的response headers 包括Link , 以及一些自定义的headers 形如X-(...)的header , 但就是在response拦截器中看不到这个数据

有没有办法在拦截器里直接返回response.data

因为服务端的接口返回是{ code:0,message:"string",data:{}}
我们在拦截器中根据code和message进行处理错误
然后业务中只需要取data就行了,
拦截器中我试了一下,返回response以外的都会undefined
目前在model层面是每一个response都取response.data的,不知道是否有什么好的办法

该库可以直接用于RN么

有个项目打算用RN重构。

请求用原生的fetch是可以的。

不知道umi-request基于 fetch的封装,在rn内使用是否有支持,亦或者注意事项,谢谢

response拦截器

场景

统一拦截 reponse 判断是否登录

问题

目前在 response interceptor 中获取过响应体的内容后,后面就没办法再获取到响应体的内容了,是否考虑在 interceptor 中支持把解析后的响应体往后传递

处理超时的最佳实践?

  1. 现在超时会调用的话会走到 errorHandler,那么我要在 errorHandler 里怎么判断这是超时错误?我现在是根据 error.message 里的 timeout,这样感觉不靠谱。
  2. 现在超时触发后,如果请求回来了,这个请求的 Promise 还是会被 resolve。这个很奇怪,超时时应该已经 reject 掉了,为什么还会再 resolve?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.