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

4 篇文章 0 订阅
4 篇文章 0 订阅

问题产生过程

之前做安卓项目遗留下来的一个问题, 为什么我通过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中携带任何字符的参数了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值