URL编码传输问题(特殊字符)

URL编码传输问题(特殊字符)

问题产生过程

之前做安卓项目遗留下来的一个问题, 为什么我通过Http请求传输的中文到服务端(Java) 获取参数时, 总是出现各种问题, 莫名其妙就出现了乱码? 各种设置UFT-8 都不管用??

我们必须从去了解具体URL编码的过程.

浏览器环境

浏览器的导航栏输入包含中文URL后.

浏览器会自动将中文进行URL编码.(我们打开F12开发者工具查看)

那么我此时会产生好奇,URL编码是在什么阶段开始编码的?什么适合开始解码的?

安卓环境

我尝试在非浏览器环境下(比如Android的HttpURLConnection和OkHttp)用Get 请求访问 http://IP:port/getMS?name=邓洲

此时会发生什么?

结果在服务端接通过request.getParams()获取并打印了

好像也自动进行了URL编码

Nodejs环境

然后是nodejs环境使用fetch或者axios访问会怎么样?

const fetch = require('node-fetch')

fetch("http://localhost:8080/EncodeTest/URLEncode?name=邓大帅")

.catch(err => console.log(err))

.then(res => console.log(res))

好家伙,直接报错,请求根本发不出去

原因是URL不能携带中文,需要先手动URL编码才能访问

服务端也接收到了

URL编码特殊字符

字符解释转码+URL 中+号表示空格%2B空格URL中的空格可以用+号或者编码%20/分隔目录和子目录%2F?分隔实际的URL和参数%3F%指定特殊字符%25#表示书签%23&URL 中指定的参数间的分隔符%26=URL 中指定参数的值%3D一次性测试这些符号(注意打印结果是服务器端的打印结果)

encodeURI("邓大+帅/?%=&#")

//邓大 帅/?%=

//+号变成了空格,最后两个不显示

encodeURI("邓大 帅/?%=#")

//邓大 帅/?%=

//去掉&后,#仍然不显示;+号换空格仍然是空格

encodeURI("邓&大+帅/?%=#")

//邓

//说明&会截断后面的内容

encodeURI("邓#大+帅/?%=")

//邓

//说明#也会截断后面的内容

发现只有 + & # 三个符号无法通过URL编码正常显示,因此在传输之前就得使用replace()来替换所有这三个字符.

const fetch = require('node-fetch')

fetch("http://localhost:8080/EncodeTest/URLEncode?name=" +

encodeURI("邓+大&帅#太 帅/?%=")

.replace("+", "%2B")

.replace("#", "%23")

.replace("&", "%26")

)

.then(res => res.text())

.then(res => console.log(res))

服务端接收并打印

完美!!!

不过我们还是得认真分析一下这中间发生了什么.

首先进行encodeURI(“邓+大&帅#太 帅/?%=”)

然后再进行替换的.

那么就得知道这三个符号在函数执行后输出什么.

console.log(encodeURI("+&#"))

// +&#

console.log(encodeURI("+&#/"))

// +&#/

console.log(encodeURI("%"))

// %25

// % 能够正常编码

console.log(encodeURI("+ %"))

// +%20%25

//空格也能正常编码

console.log(encodeURI("?"))

// ?

console.log(encodeURI("="))

// =

结论是在编码阶段

符号encodeURI编码服务端接收(来自Node)服务端接收(来自浏览器)服务端接收(来自安卓)++空格空格空格空格%20空格空格空格/////?????%%25%nullnull##当前及后面字符全部失效当前及后面字符全部失效当前及后面字符全部失效&&当前及后面字符全部失效当前及后面字符全部失效当前及后面字符全部失效=====可以看出服务端接收的内容与发送端环境几乎无关.

那为什么Node环境的 % 会不一样?

因为Node环境是事先通过encodeURI 将%编码成%25,

而其他环境(浏览器导航、Android的HttpUrlConneciton等未经encodeURI()) 的URL则会编码成

这样

没错,根本就没编码.

所以才会产生不同的结果.

那么针对两种不同的场景(Node的encodeURI 和 浏览器等直接传URL自动编码)所遇到的问题,我们需要区分讨论。

最佳解决方案

首先我们要了解一个概念,不是所有的字符都必须编码才能解码,比如 = $ @ / ? ( ) [ ] ~ - _* 和空格等等以及所有的数字.

以上这些默认不编码,也不用解码.

另外还有一些是我们必须认识的不安全的字符,必须进行编码(encodeURI会自动编码):

^ { } ` \ |

这六个,不编码直接报错400 Bad Request,发都发不出去.

还有一些虽然可传但是对数据完整性造成影响的: + # & ,同样也必须编码(并且这三个不会被encodeURI编码).

另外 % 与转移字符前缀相同,所以不可以重复编码。否则%转移成%25下一次就是%2525(对应服务器拿到的就是”%25“),所以有的人提出的先encodeURI()再escape()编码明显不可行,因为会对%重复编码。

使用encodeURI() 可以解决大部分问题,但是

有些字符仍然不编码,我们需要手动替换.

encodeURI(url)

.replaceAll("#", "%23")

.replaceAll("&", "%26")

.replaceAll("+", "%2B")

//注意Node环境没有replaceAll()函数,各位自行去百度怎么实现replaceAll(通过正则)

这样一来,你可以在URL中携带任何字符的参数了!

相关数据

「覃」说文解字
必发365手机版下载

「覃」说文解字

⌛ 08-03 👁️ 7158
(足+尃)组成的字怎么读?
下载365App

(足+尃)组成的字怎么读?

⌛ 06-29 👁️ 9325