封装fetch(例如携带token)

继续记录自己学习React的心得

封装fetch

为了让每个请求都携带token,同时减少工作量和duplicate code,封装一下fetch还是很有必要的。本项目中将fetch封装为http模块。

  1. 需要用到qs库
    // package.json
    {  
      ...,
      "dependencies": {
        "qs": "^6.10.3",
        ...
      },
    }

     

  2. http模块支持配置fetch config,因此需要创建Config接口以及相关操作
    // http.ts
    interface Config extends RequestInit { token
    ?: string; data?: object; } export const http = async ( endpoint: string, { data, token, headers, ...customConfig }: Config = {} ) => { const config = { method: "GET", headers: {
    // 如果customConfig中传入了token,则会在这里将token添加到headers Authorization: token
    ? `Bearer ${token}` : "", "Content-Type": data ? "application/json" : "", }, ...customConfig, }; ... }

    模块默认GET请求,headers中的Authorization是指定的写法。

  3. 主要逻辑
    (1)先对GET/POST请求进行不同处理
      
      if (config.method.toUpperCase() === "GET") {
        // GET请求直接在endpoint中添加参数
        endpoint += `?${qs.stringify(data)}`;
      } else {
        // POST则在body中JSON序列化数据
        config.body = JSON.stringify(data || {});
      }

    (2)发送fetch请求

    export const http = async (
      endpoint: string,
      { data, token, headers, ...customConfig }: Config = {}
    ) => {
      ......
      return window.fetch(`${apiUrl}/${endpoint}`, config).then(async (res) => {
    // 401 Unauthorized,登出 if (res.status === 401) { await auth.logout; window.location.reload(); return Promise.reject({ message: "请重新登录" }); }
    // res.json()需要await const data
    = await res.json(); if (res.ok) { return data; } else { return Promise.reject(data); } }); };

     

  4. 传出useHttp hook
    export const useHttp = () => {
    // useAuth是用户认证模块的hook const { user }
    = useAuth();
    return ([endpoint, config]: [string, Config]) => http(endpoint, { ...config, token: user?.token }); };
    // 或者可以用下面的写法,这里的[string, Config]和http()传入的参数类型一致,因此可以使用Parameters<typeof http>,这样保持和http()的代码上下一致,不写重复代码
    //
    return (...[endpoint, config]: Parameters<typeof http>) => http(endpoint, { ...config, token: user?.token }); };
    }

     

  5. 用法
    例如获取用户列表接口,就使用到了useHttp:
    export const useUsers = (param?: Partial<User>) => {
      const client = useHttp();
      const { run, ...result } = useAsync<User[]>();
    
      useEffect(() => {
        run(client("users", { data: cleanObject(param || {}) }));
      }, [param]);
    
      return result;
    };

     

posted @ 2022-09-09 16:28  晚安NN  阅读(2693)  评论(0)    收藏  举报