加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

golang 源码分析之URL编码规范

发布时间:2020-12-16 09:40:34 所属栏目:大数据 来源:网络整理
导读:首先看一下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 ; %3

首先看一下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 o %B0 ± %B1 a %B2,%B4 μ %B5 ? %BB ? %BC ? %BD ? %BF à %C0 á %C1 ? %C2 ? %C3 ? %C4 ? %C5 ? %C6 ? %C7 è %C8 é %C9 ê %CA ? %CB ì %CC í %CD ? %CE ? %CF D %D0 ? %D1 ò %D2 ó %D3 ? %D4 ? %D5 ? %D6 ? %D8 ù %D9 ú %DA ? %DB ü %DC Y %DD T %DE ? %DF à %E0 á %E1 a %E2 ? %E3 ? %E4 ? %E5 ? %E6 ? %E7 è %E8 é %E9 ê %EA ? %EB ì %EC í %ED ? %EE ? %EF e %F0 ? %F1 ò %F2 ó %F3 ? %F4 ? %F5 ? %F6 ÷ %F7 ? %F8 ù %F9 ú %FA ? %FB ü %FC y %FD t %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

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读