URL编码问题
问题描述
需求:上传的文件不能重名,我的接口API定义为[GET] /v0.1/files?$filter=name eq xxx
。
问题:如果文件名称包含空格、不安全的字符、特殊的保留字符的话,后端java接收到的字符并不等价于所要传递的参数。如果文件名为a%20b.doc,那么java后台收到的name值为a b.doc,这就和预期的不一致。
解决办法
前端用encodeURIComponent编码2次,后端用URLDecoder解码两次。因为前端encodeURIComponent的一次编码是框架自己做的,后端一次URLDecoder解码是Spring做的,所以实际上只需前后端各自编码、解码一次即可。
java自带的URLEncoder是遵循RFC1738的,所以空格编码后是+而不是%20,如需转化,试用replaceAll(+,%20)即可。encodeURIComponent(” “) = %20。
原理
URLDecoder
package java.net;
public class URLEncoder extends Object
HTML表单编码的工具类。 该类包含将字符串转换为application / x-www-form-urlencoded MIME格式的静态方法。 有关HTML表单编码的更多信息,请参阅HTML规范。
编码字符串时,遵循下列规则:
- 字母数字字符[a-zA-Z0-9]保持不变。
- 特殊字符” 。”,” - “,” * “和” _ “保持不变。
- 空格字符” “被转换成加号”+”。
- 所有其他字符都是不安全的,首先使用某种编码方案将其转换为一个或多个字节。 然后每个字节由3个字符的字符串”%xy”表示,其中xy是该字节的两位十六进制表示。 推荐使用的编码方案是UTF-8。 但是,出于兼容性原因,如果未指定编码,则使用平台的默认编码。
For example using UTF-8 as the encoding scheme the string “The string ü@foo-bar” would get converted to “The+string+%C3%BC%40foo-bar” because in UTF-8 the character ü is encoded as two bytes C3 (hex) and BC (hex), and the character @ is encoded as one byte 40 (hex).
URLEncoder
package java.net;
public class URLDecoder extends Object
HTML表单解码的实用工具类。 该类包含解码application / x-www-form-urlencoded MIME格式String的静态方法。转换过程与URLEncoder类编码的过程相反。 假定编码字符串中的所有字符是下列之一:[a-zA-Z0-9
],” 。”,” - “,” * “和” _ “。 字符”%”是允许的,但被解释为特殊转义序列的开始。
html规范摘录#application/x-www-form-urlencoded
这是默认的内容类型。 使用此内容类型提交的表单必须遵循以下方式进行编码:
- Control names and values are escaped.
- Space characters are replaced by
+
。 - reserved characters are escaped as described in [RFC1738], section 2.2。
- Non-alphanumeric characters are replaced by `%HH’, a percent sign and two hexadecimal digits representing the ASCII code of the character.
- 换行符被编码成
encodeURIComponent("\r\n")="%0D%0A"
。
The control names/values are listed in the order they appear in the document. The name is separated from the value by =
and name/value pairs are separated from each other by &
.
This attribute specifies the content type used to submit the form to the server (when the value of method is “post”). The default value for this attribute is “application/x-www-form-urlencoded”. The value “multipart/form-data” should be used in combination with the INPUT element, type=”file”.
RFC1738规范
URL字符编码问题
URL是字符的序列,即字母([a-zA-Z]
)、数字([0-9]
)和特殊符号。一个URL可能拥有不同的表现形式。一个URL的解释取决于所用字符的特性。
多数的URL方案中,URL内不同部分的字符序列被用来表示Internet协议中使用的八字节(octet,指八个比特bit为一组的单位或一个具有八个比特的实体)序列。一个八字节可以由在US-ASCII编码字符集中具有该八字节作为其代码的字符表示。
此外,八字节可通过三元组(即%号起头,紧接着是2个十六进制的数字)的字符进行编码。
如果八字节在US-ASCII编码的字符集中没有相应的图形字符(目的是用来书写、打印或以某种方式展示的可被人类阅读的任意字符),或者使用的字符不安全,或者相应的字符被某些特定URL方案保留用于其他解释则八字节必须被编码。
没有相应的US-ASCII图形字符:URL只能用US-ASCII编码字符集内的图形打印字符编写。在US-ASCII内,八字节80-FF十六进制没有被使用,00-1F十六进制代表控制字符,这些都是必须被编码的。
不安全(unSafe):出于多种理由,字符可以是不安全的。
- 空格是不安全的,因为有意义的空格可能会消失或当URL被抄写或排版或接受文字处理程序的处理时会引入无意义的空格。
< 或 >
是不安全的,因为在自由文本中它们充当了分隔符。- 双引号(
"
)是不安全的,因为在某些系统中,它被充当分隔符。 - 井号
#
是不安全的,因为在万维网中或其他一些系统用它被用做片段或者锚点的分隔符。 - 百分号
%
是不安全的,因为它别用于编码其他字符。 { , } , | , \ , ^ , ~ , [ , ]
和`是不安全的,因为网关或者传输代理会修改这些字符。
在URL内的所有不安全的字符必须被编码。
保留的,预留的(Reserved):许多URL方案为特殊的意义保留了某些字符:它们在部分URL指定方案中出现。如果相应八字节的字符是方案内部的保留字,那它必须被编码。字符; , / , ? , : , @ , = &
可能被某个方案预留用作特殊意义。在其他方案中不能保留其他字符。
当一个八字节由一个字符表示并且被编码时,URL通常具有相同的解释。 但是,对于保留字符而言,这不是真的:编码一个为特定方案保留的字符可能会改变URL的语义。
因此,在URL中数字、字母、特殊字符$ -_。+!*()
以及保留字符要经过解码(unencoded)后才使用。
另一方面,只要它们不用于保留目的,可以在URL指定方案中编码不需要编码的字符(包括字母数字)。