URI 包含特殊字符 返回404
问题描述
在开发过程中, API采用restful的定义风格,所有的参数都放到了URL 里面,GET v1/order/{deviceId}, 由于没有考虑到目标参数可能包含特殊字符, 所以当QA测试的时候就会发现这个scenario是failed。 调用API会返回404。其实当时设计的时候也有相关的顾虑,只是偷了一下懒, 觉得deviceId应该是标准的数据格式,不会包含特殊字符。此处略显不专业。
原因
RFC 2396标准 规定有些特殊字符在URL中是不能直接传递的.
允许的字符 | 保留字符 | 禁止字符 |
---|---|---|
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;= |
/?#[]@ RFC 3986中定义的URI的泛型语法的一部分 !$&'()*+,;= 用于特定URI方案的语法组件 % 用于转义字符的编码 |
"<>^`{|} |
解决方案
如果要在URI中传递这些特殊符号,那么就要使用他们的编码,编码的格式为百分比编码:%加字符的ASCII码,即一个百分号%,后面跟对应字符的ASCII(16进制)码值。例如 空格的编码值是"%20"。
1. 尝试直接在URL中编码 例如Url是v1/order/mydeviceid+information,进行URL编码后是v1/order/deviceId/mydeviceid%2Binformation, 似乎不工作, POSTMAIN 调用这个API 依旧报404. 网上说此处可以改配置文件去实现, 我觉得这不是一个好的注意,改config可能会引起系统安全性问题。所以pass了这种方案。
2. 尝试用queryString方式传参 v1/order?deviceid=mydeviceid+information, 进行URL编码后是v1/order?deviceid=mydeviceid%2Binformation, 这个solution是工作的,后台也能正确解析。此方法工作良好。问题解决
下面是调用API时,对参数进行URL编码,下面是常用的一些编码
Character | Code Points (Hexadecimal) | Code Points (Decimal) |
---|---|---|
Dollar ("$") | 24 | 36 |
Ampersand ("&") | 26 | 38 |
Plus ("+") | 2B | 43 |
Comma (",") | 2C | 44 |
Forward slash/Virgule ("/") | 2F | 47 |
Colon (":") | 3A | 58 |
Semi-colon (";") | 3B | 59 |
Equals ("=") | 3D | 61 |
Question mark ("?") | 3F | 63 |
'At' symbol ("@") | 40 | 64 |
补充
16 进制
逢16进1 一般用0-9和A-F表示, A-F相当于十进制的10-15
十六进制 | 十进制 | 二进制 |
---|---|---|
A | 10 | 1010 |
B | 11 | 1011 |
C | 12 | 1100 |
D | 13 | 1101 |
E | 14 | 1110 |
F | 15 | 1111 |
一字节可以表示两个连续的十六进制数字
十进制转十六进制,可以采用余数定理方法转换
1. 把十进制数除以16,保留余数部分
2. 写下余数部分,在右下角标上16
3. 把之前的整数商再除以16,得到余数部分,然后再在这个余数右下角标上16
4. 重复以上步骤,直到得到一个小于16的商。每一次都把余数右下方标上16
5. 把余数和最后的商从左到右按顺序写下,最右是商。得到的十六进制就是这个数,从右往左读。比如读作2F34,实际上的值是43F2。
例如将4877下标10转成十六进制
4877÷16=304....13(D)
304÷16=19....0
19÷16=1....3
1÷16=0....1
4877下标10=130D下标16
十六进制转二进制
将一位十六进制数分解成四位二进制数,用四位二进制按权相加去凑这位十六进制数
例如D(7)H
D -> 1101
7 -> 0111
D(7)H=(11010111)B
H 代表十六进制
B 代表二进制