美文网首页
8-1、axios其他功能实现

8-1、axios其他功能实现

作者: Eileen_1d88 | 来源:发表于2019-12-13 16:19 被阅读0次
    1、withCredentials

    修改类型定义:

    interface AxiosRequestConfig {
      // ...
      withCredentials?: boolean
    }
    

    修改实现

    export default function xhr(config: AxiosRequestConfig): AxiosPromise {
      return new Promise((resolve, reject) => {
        // method和data可能没有, 所以给出默认值
        const {
          url,
          method = 'get',
          data = null,
          headers,
          responseType,
          timeout,
          cancelToken,
          withCredentials
        } = config
         // ...
        if (withCredentials) {
          request.withCredentials = withCredentials
        }
      })
    }
    
    2、CSRF防御

    CSRF的防御手段有很多,比如验证请求的referer,但是referer是可以伪造的,所以杜绝此类攻击的一种方式是服务器要求每次请求都包含一个token,这个token不在前端生成,而是在我们每次访问站点的时候生成,并通过set-cookie的方式保存在客户端,然后客户端发送请求的时候,从cookie中对应的字段独处token,然后添加到请求headers中。这样服务器就可以从请求headers中读取这个token并验证。由于这个token是很难伪造的,所以就能区分这个请求是否是用户正常发起的。

    对于我们的ta-axios库,我们要自动把这几件事做了,每次发送请求的时候,从cookie中读取对应的token值,然后添加到请求headers中。我们允许用户配置xsrfCookieName表示存储token的cookie名称,xsrfHeaderName表示请求headers中token对应的header名称。

    axios.get('/more/get',{
      xsrfCookieName: 'XSRF-TOKEN', // default
      xsrfHeaderName: 'X-XSRF-TOKEN' // default
    }).then(res => {
      console.log(res)
    })
    

    我们提供xsrfCookieName和xsrfHeaderName的默认值,当然用户也可以根据自己的需求在请求中去配置xsrfCookieName和xsrfHeaderName。

    代码实现
    • 修改定义
    interface AxiosRequestConfig {
      //...
      xsrfCookieName?: string,
      xsrfHeaderName?: string
    }
    
    • 修改默认配置
    const defaults: AxiosRequestConfig = {
      // ...
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN'
    }
    

    接下来我们要做3件事
    1、首先判断如果配置withCredentials为true或者是同源请求,我们才会在请求headers中添加xsrf相关字段;
    2、如果判断成功,尝试从cookie中读取xsrf的token值;
    3、如果能读到,则把它添加到请求headers的xsrf的相关字段中。

    • 同源判断
      helpers/url.ts
    interface URLOrigin {
      protocol: string,
      host: string
    }
    
    const urlParsingNode = document.createElement('a')
    const currentOrigin = resolveURL(window.location.href)
    
    function resolveURL(url: string): URLOrigin {
      urlParsingNode.setAttribute('href', url)
      const { protocol, host } = urlParsingNode
      return {
        protocol,
        host
      }
    }
    
    function isURLSameOrigin(requestURL: string): boolean {
      const parsedOrigin = resolveURL(requestURL)
      return currentOrigin.protocol === parsedOrigin.protocol && currentOrigin.host === parsedOrigin.host
    
    }
    
    • cookie获取
      cookie.ts
    const cookie = {
      read(name: string): string | null {
        const match = document.cookie.match(new RegExp('(^|;\s*)(' + name + ')(=[^;]*)'))
        return match ? decodeURIComponent(match[3]) : null
      }
    }
    export default cookie
    

    修改xhr.ts

    export default function xhr(config: AxiosRequestConfig): AxiosPromise {
      return new Promise((resolve, reject) => {
        const {
           // ...
          xsrfCookieName,
          xsrfHeaderName
        } = config
        //...
        if ((withCredentials || isURLSameOrigin(url!)) && xsrfCookieName) {
          const xsrfValue = cookie.read(xsrfCookieName)
          headers[xsrfHeaderName!] = xsrfValue
        }
        // ...
      })
    }
    
    demo
    import axios, { Canceler } from '../../src/index'
    const instance = axios.create({
      xsrfCookieName: 'XSRF-TOKEN-D',
      xsrfHeaderName: 'X-XSRF-TOKEN-D'
    })
    
    instance.post('/api/extend/post').then(res => {
      console.log(res)
    })
    

    至此,我们实现了XSRF防御相关功能。接下来我们来实现ts-axios对上传和下载的支持

    相关文章

      网友评论

          本文标题:8-1、axios其他功能实现

          本文链接:https://www.haomeiwen.com/subject/maptnctx.html