httpServletRequest.getParameter 参数中存在“&”导致获取不到完整参数的问题

记录最近遇到的坑。

起因

账管有个信用卡绑定接口,我的调用的时候需要传号码、地址等信息,使用的是 HttpURLConnection,发送的时候将参数转为key=value&key=value 的形式,账管那边使用 httpServletRequest.getParameter() 进行获取参数。
问题就是当某些地址中存在 & 符号的时候,因为账管获取参数的时候是通过 & 符号进行截取的,就会导致他们获取参数不全。
如:a=123&b=park&center
本来 b 的 value 应该是 park&center,现在他们那边只能获取到 park,这就导致两边参数不一样,签名也不一样,然后验签失败。

解决方案

以上就是事情的起因,期初我的建议是他们那边能不能换成 json 格式的接收,我们这边直接发送 json 格式的数据,这样应该不会有问题,但是他们死活不愿意改。
后续方案是我们将参数中的 & 进行 URL 编码,将其转化为 %26。

我们实现的方法大概如下:

    public String pay(String url, Map<String, String> params) {
        URL u = null;
        HttpURLConnection con = null;
        // 构建请求参数
        StringBuffer sb = new StringBuffer();
        String strResult = null;
        if (params != null) {
            for (Entry<String, String> e : params.entrySet()) {
                sb.append(e.getKey());
                sb.append("=");                
                sb.append(e.getValue());
                sb.append("&");
            }
            strResult = sb.substring(0, sb.length() - 1);
        }
        
        // 尝试发送请求
        try {
            u = new URL(url);
            con = (HttpURLConnection) u.openConnection();
            // POST 只能为大写,严格限制,post会不识别
            con.setRequestMethod("POST");
            con.setDoOutput(true);
            con.setDoInput(true);
            con.setUseCaches(false);
            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
            osw.write(sb.toString());
            osw.flush();
            osw.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (con != null) {
                con.disconnect();
            }
        }
        // 读取返回内容
        StringBuffer buffer = new StringBuffer();
        try {
            //一定要有返回值,否则无法把请求发送给server端。
            BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
            String temp;
            while ((temp = br.readLine()) != null) {
                buffer.append(temp);
            }
        } catch (Exception e) {
            logger.error("*****报错:", e);
        }

        return buffer.toString();
    }

改造为:

                String value = e.getValue();
                if (value.contains("&")) {
                    try {
                        // URL编码,针对“&”进行处理,防止截取参数不完整导致验签失败
                        value = URLEncoder.encode(value, "UTF-8");
                    } catch (UnsupportedEncodingException e1) {
                        e1.printStackTrace();
                    }
                }
                sb.append(value);
分析原因

使用 httpServletRequest.getParameter 接收post请求参数,发送端 content Type 必须设置为 application/x-www-form-urlencoded;否则会接收不到

使用 httpServletRequest.getParameter 也是获取不到 json 格式的数据的,发送端只能发送 key=value&key=value 格式的数据。所以如果需要发送 json 格式的数据,两边都需要进行改造。

application/x-www-form-urlencoded 通过表单提交,在sevlet实现中,mutipart/form-data 和 application/x-www-form-urlencoded 会被特殊处理,请求参数将被放置于 request.paramter,这是一个map。
我们可以从map中获取参数进行验证,或者其他拦截需求,map的获取类似hibernate的延迟加载,当调用 request.getparamter() 方法,servlet才会从请求流中读取请求参数加载入map。InputStream 也会存有这份数据,但如果这份数据被读取,那么到了controller层将无法读出数据,同样,拦截之后到达controller层时请求数据已经被加载入了controller层方法实参,实参对象需要有set方法,框架会以反射的方式调用属性的set方法注入数据,数据只会被注入到已有的属性。

当以 application/json 的 content-type 传送数据,被传送的对象只需被json序列化。当以 application/x-www-form-urlencoded 的方式传送数据。请求的内容需要以…=…&…=…的格式提交,在请求体内内容将会以”&”和“ = ”进行拆分。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值