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 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""))
结果如下: 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,就是不转义。 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 case encodeQueryComponent:
return true
所以会对所有字符进行转码 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |