字符解码时加号解码为空格问题探究

问题

  最近发现一个问题,后台Java代码使用new URL(url)方式发起一个POST请求,模拟表单提交操作,从后台提交数据到服务器端。当客户端的数据中带加号时,服务器端的Servlet使用request.getParameter('param')得到的数据加号被变为了空格。比如:客户端发送的数据为aa+aa,服务器接收到的数据变为了aa aa

简单写了几句代码验证一下:

String str = "aaa+aaa aaa%2B";
System.out.println("ENCODE="+URLEncoder.encode(str, "utf-8"));
System.out.println("DECODE="+URLDecoder.decode(str,"utf-8"));

运行结果如下:

ENCODE=aaa%2Baaa+aaa%252B
DECODE=aaa aaa aaa+

原因

  通过上面的代码可以看到,编码时,空格被编码成了+号,+号变成了%2b。当未经过编码的带+号的字符串解码时,+号直接转变为了空格。

翻了一下文档是这么说的(地址):

这里写图片描述

接着到application/x-www-form-urlencoded MIME format的说明处(地址):

这里写图片描述

再翻了一下servlet中request.getParameter('param')方法说明,如下:

这里写图片描述

接着看getParameter到底如何取数据的:

这里写图片描述

  从上图可以知道,当在servlet中使用getParameter方法来接收POST数据时,默认是会根据请求头的类型来解码的。这就证实了如果通过后端new URL(url)的方式模拟表单的POST,如果在POST前不对数据进行编码且数据中带有+号,那么服务器端收到的数据必然会是错误的(+号会被自动解码为空格)。

验证

  常规的表单提交content-type有两种:application/x-www-form-urlencodedmultipart/form-data,如果表单提交时不设置任何类型,默认以第一种方式提交数据;第二种属于带附件的表单提交,当表单中有附件时,必须设置表单的enctypemultipart/form-data.

  很多时候,我们用 Ajax 提交数据时,也是使用这种方式。例如 JQuery的 Ajax,Content-Type 默认值为application/x-www-form-urlencoded;charset=utf-8

前端代码

$.ajax({
  url:getServer()+"/TestServlet",
  data:{yiying:"aaa+aa a"},
  type:'post',
  success:function(response){

  }})

HTTP请求情况

这里写图片描述

  由于在chrome的控制台中所显示的数据被优化显示了,所以在Form Date部分,需要点击后面的view source才能看到浏览器发送数据的真实格式是怎么样的。默认优化后的显示应当为yiying:aaa+aa a,

  从上图中可以看到,浏览器实际上的使用Content-Type:application/x-www-form-urlencoded; charset=UTF-8编码规则,实际发送的数据为yiying=aaa%2Baa+a,其中+号变为了%2b,空格被编码为+号。

后端情况

@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    public TestServlet() {
        super();
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("==="+request.getParameter("yiying")+"===");
    }
}
//输出值为
===aaa+aa a===

  从后端的输出值可以看到,后端的servlet自动解码为原始数据。

关于后端中文乱码问题的特别说明:

后端服务器(tomcat 的server.xml)如果没有设置编码规则(URIEncoding=”utf-8”),Servlet默认会以ISO-8859-1来解码中文字符(Servlet规范定义),而前端标识为utg-8,此种情况就会产生乱码,可以用如下3种办法来解决:
1. 在server.xml设置编码规则为utf-8
2. 在调用getParameter之前使用代码设置编码规则,request.setCharacterEncoding("utf-8");
3. 定点处理,String name = new String(request.getParameter("name").getBytes("iso-8859-1"),"utf-8");

结论

  显而易见,如果需要在后端使用new java.net.URL(url)的方式POST提交数据,需要像浏览器那样先给数据编码处理,再发送数据。

欢迎到个人独立博客逛逛:http://muchstudy.com

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值