最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • whatwg-fetch的业务封装

    正文概述 掘金(纸上的彩虹)   2021-03-24   777
    /**
     *  常用的请求方法
     *  支持 get post 类型
     *  文件等其他类型处理其他方法
     * @param apiUrl
     * @param method  'get' || 'post'
     * @param body  object
     * @param contentType 'json' || ''
     * @returns {Promise<Response | never>}
     */
    const fetchApi = ( apiUrl, method, body, contentType ) => {
    
      if( process.env.NODE_ENV === 'development' ) {
        console.log('请求地址====================》', apiUrl);
        console.log('请求参数====================》', body);
      }
    	// requestPath是公共的请求地址
      let url = requestPath + apiUrl ;
      // IE浏览器第一次发请求没有问题,再发送请求时,当参数一样时,浏览器会直接使用缓存数据. 导致页面 还是原来的页面,所以在请求时加上时间戳
      body.timeStamp = new Date().getTime();
    
      const fetchOptions = {}
    
      fetchOptions.method = method || 'get';
      fetchOptions.credentials = 'include';
      fetchOptions.mode = 'no-cors';
    
      if (fetchOptions.method === 'get') {
        url = getRequestBodyHandler(url, body)
      }
    
      if (fetchOptions.method === 'post') {
        // application/json
        if (contentType === 'json') {
          fetchOptions.headers = {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
          }
          //这里的配置是为了fetch处理跨域
          fetchOptions.mode = 'cors';
          fetchOptions.cache = 'force-cache';
          
          fetchOptions.body = fetchJsonBodyHandler(body)
        } else { // form data
          fetchOptions.body = postRequestBodyHandler(body)
        }
      }
      return fetch(url, fetchOptions)
        .then(checkServerStatus)
        .then(parseJSON)
        .then(checkServerDataStatus);
    
    }
    

    关于fetch请求跨域的说明和处理

    CORS分为两种:

    • 简单请求

      某些请求不会触发 CORS 预检请求。本文称这样的请求为“简单请求”。若请求满足所有下述条件,则该请求可视为“简单请求”:

      1. 使用下列方法之一: GET HEAD POST
      2. Fetch 规范定义了对 CORS 安全的首部字段集合,不得人为设置该集合之外的其他首部字段。该集合为: Accept Accept-Language Content-Language Content-Type (需要注意额外的限制) DPR Downlink Save-Data Viewport-Width Width
      3. Content-Type 的值属于下列之一: application/x-www-form-urlencoded multipart/form-data text/plain
    • 带有preflight预请求的CORS

      带有preflight的CORS ,浏览器会先发出一个 OPTIONS请求,服务器在响应里写入是否允许该域名发起访问,在response的header里面加入了Access-Control-Allow-Origin,Access-Contral-Allow-Methods,Access-Contraol-Allow-Headers,Access-Control-Max-Age这几个字段。

    进行带有身份凭证的CORS 请求

    默认情况下的跨域请求都是不会把cookie发送给服务器的,在需要发送的情况下,如果是xhr,那么需要设置xhr.withCredentials = true,如果是采用fetch获取的话,那么需要在request里面设置 credentials:'include', 但是如果服务器在预请求的时候没返回Access-Control-Allow-Crenditials:true的话,那么在实际请求的时候,cookie是不会被发送给服务器端的,要特别注意对于简单的get请求,不会有预请求的过程,那么在实际请求的时候,如果服务器没有返回Access-Control-Allow-Crenditials:true的话 那么响应结果浏览器也不会交给请求者。

    关于fetch跨域说明的来源地址:blog.csdn.net/danzhang101…

    实际遇到的问题

    后台后个接口规定只接收post请求,那么带预请求的fetch请求就会返回405。为了处理这种情况需要在代码中加入如下配置:

    fetchOptions.mode = 'cors';
    fetchOptions.cache = 'force-cache';
    

    其他辅助方法

    /**
     * get 请求的情况下
     * 将 json 请求参数 添加到 url 上
     * @param url
     * @param ob
     * @returns {*}
     */
    const getRequestBodyHandler = function (url, ob) {
    
      if (ob) {
    
        let param = ''
    
        Object.keys(ob).forEach((key, value) => {
          param ? (param += '&') : (param += '?')
          param += (key + '=' + ob[key])
        })
    
        return url + param
      }
    
      return url
    
    }
    
    /**
     * post请求时
     * 将 json 请求参数 转化为 formData body
     * @param ob
     * @returns {*}
     */
    const postRequestBodyHandler = function (ob) {
    
      if (ob) {
    
        const body = new FormData()
    
        Object.keys(ob).forEach((key) => {
          body.append(key, ob[key])
        })
    
        return body
      }
    
      return null
    
    }
    
    const fetchJsonBodyHandler = function (ob) {
      return typeof ob === 'object' ? JSON.stringify(ob) : ob
    }
    
    /**
     * 接口数据  状态验证
     * @param data
     * @returns {*}
     */
    const checkServerDataStatus = (data) => {
    
      if( process.env.NODE_ENV === 'development' ){
        console.log('请求返回数据====================》', data)
      }
      // 成功返回
      if ( data && (data.status === 200 || data.state === 0)) {
        return data.data ;
      }
    
      // 错误处理
      const errorInfoMap = {
        99999 :{
          type: 'dataException',
          msg: '数据异常'
        },
        100000: {
          type: 'unknown',
          msg: '未知的异常'
        },
        500 : {
          type: 'exception',
          msg: '接口异常'
        },
        501 : {
          type: 'exception',
          msg: '接口异常'
        },
        502 : {
          type: 'exception',
          msg: '接口异常'
        },
        503 : {
          type: 'exception',
          msg: '接口异常'
        },
        401 : {
          type: 'noPrmission',
          msg: '没有访问权限'
        },
        403: {
          type: 'refuse',
          msg: '接口拒绝访问'
        },
        404: {
          type: 'notFound',
          msg: '接口链接不存在'
        }
      }
    
      // 错误信息
      let errorInfo = {
        type: 'unknown',
        msg: '未知的异常'
      }
    
      // 错误对象
      const error = new Error();
    
      // 数据格式异常
      if( !data || !data.status ){
        Object.assign( error, errorInfo, errorInfoMap[99999] );
        throw error;
      }
    
      // 根据code捕获的错误
      let extraErrorInfo = errorInfoMap[ data.status ];
      if( extraErrorInfo ){
        Object.assign( error, errorInfo, extraErrorInfo );
        throw error;
      }
    
      // 未知错误
      throw error
    
    }
    
    /**
     * 服务器请求 状态验证
     * @param data
     * @returns {*}
     */
    const checkServerStatus = (response) => {
      // 请求接受成功
      if (response.status >= 200 && response.status < 300) {
    
        return response
    
      } else {
    
        // 错误处理
        const errorInfoMap = {
          100000: {
            type: 'serverUnknown',
            msg: 'server: 未知的异常'
          },
          502 : {
            type: 'serverMaintainace',
            msg: 'server: 服务器正在维护'
          },
          404 : {
            type: 'serverException',
            msg: 'server: 访问地址不存在'
          }
        }
    
        // 错误信息
        let errorInfo = {
          type: 'serverUnknown',
          msg: 'server: 未知的异常'
        }
    
        // 错误对象
        const error = new Error();
    
        // 根据code捕获的错误
        let extraErrorInfo = errorInfoMap[ response.status ];
        if( extraErrorInfo ){
          Object.assign( error, errorInfo, extraErrorInfo );
          throw error;
        }
    
        // 未知错误
        throw error
    
      }
    
    }
    
    // json  转换
    const parseJSON = (response) => {
      //response.text()获得文本类型的
      //response.json()会帮助你运行一次JSON.parse(response.text())
      return response.json()
    }
    

    下载网 » whatwg-fetch的业务封装

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元