转码后,客户收到请求,前台通知成功验签成功,后台通知验签失败。
问题查找:
写了个callbackAction回显代码
String body= JSON.toJSONString(getRequest().getParameterMap()); getResponse.setContentType("text/html;charset=utf-8"); Writer writer=getResponse.getWriter(); writer.write("QeryString:"+getRequest().getQueryString()+"\n"); writer.write("Body:"+body); writer.flush(); wirter.close();
参数mac值为: abc==,urlEncode编码后abc%3d%3d。
1、前台跳转时,自己拼接路径callbackurl=url?name1=value1&name2=value2
,跳转到自己的系统的页面,在页面停留几秒,然后跳转到商户的提供的地址上。
GET请求测试:浏览器输入
http://127.0.0.1:8080/merchant-mock/callback.do?mac=abc%3d%3d
结果:页面上显示
QueryString:mac=abc%3d%3d Body:["mac":["abc=="]]
说明:GET请求里面参数进行urlEnCode编码后会自动会被Decode回来。
但是为什么POST参数,解析后验签失败呢?带着问题找答案
2、代码中POST请求检查
代码中,将参数value进行urlEncode编码放入map中,然后通过apache的httpClient进行POST请求。
mac=URLEncoder.encode(mac,"UTF-8"); params.put("mac",mac);
httpClient hc=new DefaultHttpClient(); httpPost httpPost=new httpPost(httpUrl); UrlEncodeFormEntity entity=new UrlEncodeFormEntity(params,encoding); httpPost.setEntity(entity); ... HttpResponse response=hc.execute(httpPost);
打开httpClient的源码org.apache.http.client.entity.UrlEncodeFormEntity
public UrlEncodeFormEntity(final List extends NameValuePair> parameters,final String charset){ super(URLEncodedUtils.format(parameters,charset,ContentType.create(URLEncodedUtils.ContentType,charset))) }
httpClient源码类org.apache.http.client.utils.URLEncodeUtils
public Class URLEncodeUtils{ public static final String CONTENT_TYPE="application/x-www-form-urlencoded"; public static final char QP_SEP_A='&'; public static final String NAME_VALUE_SEPARATOR="="; public static final int RADIX =16; ... public static String format(List parameters,String charset){ return format(parameters,QP_SEP_A,charset) } public static String format(List parameters,char separator,String charset){ final StringBuilder result=new StringBuilder(); for(NameValuePair parameter:parameters){ final String encodedName=encodeFormFields(parameter.getName(),charset); final String encodedValue=encodeFormFields(parameter.getValue(),charset); if(result.length()>0){ result.append(separator); } result.append(encodedName); if(encodedValue!=null){ result.append(NAME_VALUE_SEPARATOR); result.append(encodedValue); } } return result.toString(); } //encodeFormFormFields进行了urlEncode编码,调用urlEncode方法 public static String urlEncode(String content,Charset charset,BitSet safechars,boolean blankAsPlus){ if(content== null){ return null; } StringBuilder buf=new StringBuilder(); ByteBuffer bb=charset.encode(content); while(bb.hasRemaining()){ final int b = bb.get() & oxff; if(safechars.get(b)){ buf.append((char) b); }else if(blankAsPlus && b ==' '){ buf.append('+'); }else{ buf.append("%"); char hex1=Character.toUpperCase(Character.forDigist((b>>4)&0xf,RADIX)); char hex2=Character.toUpperCase(Character.forDigist(b & 0xf,RADIX)); buf.append(hex1); buf.append(hex2); } } return buf.toString(); }
结果:我们发现对参数做了两次urlEncoding,httpClient的UrlEncodeFormEntity自己自己拼装name1=value1&name2=vlaue2的时候已经对name和value都进行了urlEncode。使用这种方式的时候不需要主动进行urlEncoding。