golang 源码分析之URL编码规范

前端之家收集整理的这篇文章主要介绍了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

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

原文链接:https://www.f2er.com/go/187527.html

猜你在找的Go相关文章