golang 源码分析之URL编码规范

首先看一下url编码规范:

      backspace      %08
      tab            %09
      linefeed       %0A
      creturn        %0D
      space          %20
      !              %21
      "              %22
      #              %23
      $              %24
      %              %25
      &              %26
      '              %27
      (              %28
      )              %29
      *              %2A
      +              %2B
      ,              %2C
      -              %2D
      .              %2E
      /              %2F
      0              %30
      1              %31
      2              %32
      3              %33
      4              %34
      5              %35
      6              %36
      7              %37
      8              %38
      9              %39
      :              %3A
      ;              %3B
      <              %3C
      =              %3D
      >              %3E
      ?              %3F
      @              %40
      A              %41
      B              %42
      C              %43
      D              %44
      E              %45
      F              %46
      G              %47
      H              %48
      I              %49
      J              %4A
      K              %4B
      L              %4C
      M              %4D
      N              %4E
      O              %4F
      P              %50
      Q              %51
      R              %52
      S              %53
      T              %54
      U              %55
      V              %56
      W              %57
      X              %58
      Y              %59
      Z              %5A
      [              %5B
      \              %5C
      ]              %5D
      ^              %5E
      _              %5F
      `              %60
      a              %61
      b              %62
      c              %63
      d              %64
      e              %65
      f              %66
      g              %67
      h              %68
      i              %69
      j              %6A
      k              %6B
      l              %6C
      m              %6D
      n              %6E
      o              %6F
      p              %70
      q              %71
      r              %72
      s              %73
      t              %74
      u              %75
      v              %76
      w              %77
      x              %78
      y              %79
      z              %7A
      {              %7B
      |              %7C
      }              %7D
      ~              %7E
      ¢              %A2
      £              %A3
      ¥              %A5
      |              %A6
      §              %A7
      «              %AB
      ¬              %AC
      ¯              %AD
      º              %B0
      ±              %B1
      ª              %B2
      ,              %B4
      µ              %B5
      »              %BB
      ¼              %BC
      ½              %BD
      ¿              %BF
      À              %C0
      Á              %C1
      Â              %C2
      Ã              %C3
      Ä              %C4
      Å              %C5
      Æ              %C6
      Ç              %C7
      È              %C8
      É              %C9
      Ê              %CA
      Ë              %CB
      Ì              %CC
      Í              %CD
      Î              %CE
      Ï              %CF
      Ð              %D0
      Ñ              %D1
      Ò              %D2
      Ó              %D3
      Ô              %D4
      Õ              %D5
      Ö              %D6
      Ø              %D8
      Ù              %D9
      Ú              %DA
      Û              %DB
      Ü              %DC
      Ý              %DD
      Þ              %DE
      ß              %DF
      à              %E0
      á              %E1
      â              %E2
      ã              %E3
      ä              %E4
      å              %E5
      æ              %E6
      ç              %E7
      è              %E8
      é              %E9
      ê              %EA
      ë              %EB
      ì              %EC
      í              %ED
      î              %EE
      ï              %EF
      ð              %F0
      ñ              %F1
      ò              %F2
      ó              %F3
      ô              %F4
      õ              %F5
      ö              %F6
      ÷              %F7
      ø              %F8
      ù              %F9
      ú              %FA
      û              %FB
      ü              %FC
      ý              %FD
      þ              %FE
      ÿ              %FF

下面以golang的编码举例

    t := &url.URL{Path: "www.abc.com/abc/*/abd?a=1&b=\"eee\""}
    fmt.Println(t.String())
    fmt.Println(url.QueryEscape("www.abc.com/abc/*/abd?a=1&b=\"eee\""))

结果如下:
www.abc.com/abc/%2A/abd%3Fa=1&b=%22eee%22
www.abc.com%2Fabc%2F%2A%2Fabd%3Fa%3D1%26b%3D%22eee%22
如果是String方法编码时会略过/ & =等字符,而QueryEscape则是全部转义。首先看golang url stirng方法的实现/usr/local/go/src/net/url/url.go

func (u *URL) String() string {
...
//先解析协议和host,然后解析path
path := u.EscapedPath()
...
}

具体实现

func (u *URL) EscapedPath() string {
    if u.RawPath != "" && validEncodedPath(u.RawPath) {
        p, err := unescape(u.RawPath, encodePath)
        if err == nil && p == u.Path {
            return u.RawPath
        }
    }
    if u.Path == "*" {
        return "*" // don't escape (Issue 11202)
    }
    return escape(u.Path, encodePath)
}

通过validEncodedPath判断是否是一个规范的url通过下面的escape去编码

func escape(s string, mode encoding) string {
    spaceCount, hexCount := 0, 0
    for i := 0; i < len(s); i++ {
        c := s[i]
        if shouldEscape(c, mode) {
            if c == ' ' && mode == encodeQueryComponent {
                spaceCount++
            } else {
                hexCount++
            }
        }
    }

    if spaceCount == 0 && hexCount == 0 {
        return s
    }

    t := make([]byte, len(s)+2*hexCount)
    j := 0
    for i := 0; i < len(s); i++ {
        switch c := s[i]; {
        case c == ' ' && mode == encodeQueryComponent:
            t[j] = '+'
            j++
        case shouldEscape(c, mode):
            t[j] = '%'
            t[j+1] = "0123456789ABCDEF"[c>>4]
            t[j+2] = "0123456789ABCDEF"[c&15]
            j += 3
        default:
            t[j] = s[i]
            j++
        }
    }
    return string(t)
}

上面两个地方需要解释,第一个是shouldEscape判断是否需要转义

case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // §2.2 Reserved characters (reserved)
        switch mode {
        case encodePath:
            return c == '?'

对于path的转义,上面的字符是返回的是false,就是不转义。
第二就是怎么转义escape里面通过

            t[j] = '%'
            t[j+1] = "0123456789ABCDEF"[c>>4]
            t[j+2] = "0123456789ABCDEF"[c&15]

完成 *%2A 的转义。

而对于QueryEscape来说

func QueryEscape(s string) string {
    return escape(s, encodeQueryComponent)

此时的mode为encodeQueryComponent
而此时shouldEscape中:

 case encodeQueryComponent: 
            return true

所以会对所有字符进行转码

你可能感兴趣的:(golang)