https post调用以及前端到后台中传输数据encode和decode的自动转化问题

一、环境
web服务器Tomcat7.0.59、开发工具eclipse、web应用采用springMVC架构
https服务器单向认证,keystore为自制,仅供测试使用
二、传输数据(...表示展示部分数据)




KJ881110_CORP_2012121212121200001
KJ881110
TEST00001

KJGGPT
KJGGPT

20121212121212
1.0
待定

PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPEludGVybmF0aW9uYWxUcmFkZT4KCTxIZWFkPgoJCTxNZXNzYWdlSUQ+S0o4ODExMTBfQ09...

三、问题描述

以下问题的发生是基于传输数据中存在特殊字符(例如+,不进行encode的话,网络传输后会变成空格),本人觉得需要对传输数据进行encode。

(1)采用httpspost方式使用HttpURLConnection调用,发现encode后的数据传到后台无需手动decode,却自动转化成原始数据

(2)在jsp页面通过js调用接口,发现前端无需对传输数据进行encode,后台也无需decode

四、详情

(1)https post传输数据,代码如下:
public static String sendPost(String path, String param) {
URL url = null;
OutputStreamWriter out = null;
BufferedReader in = null;
String result = "";
try {
url = new URL(path);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
out = new OutputStreamWriter(httpURLConnection.getOutputStream(), "UTF-8");
out.write(param);
out.flush();
in = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}

public static void main(String[] args) throws DocumentException, UnsupportedEncodingException {
SAXReader reader = new SAXReader();
Document document = reader.read(new File("src/postdata.xml"));
String messageText = document.asXML();
messageText = URLEncoder.encode(messageText, "UTF-8");

// 发送 POST 请求
String sr = HttpRequest.sendPost2("https://localhost:8443/cbtserver/declaretest",
"messageType=123456789&messageText=" + messageText);
System.out.println(sr);
}
postdata.xml即为二中的数据,经编码后为:
%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E%0D%0A%3C!DOCTYPE+html+PUBLIC+%22-%2F%2FW3C%2F%2FDTD+XHTML+1.0+Strict%2F%2FEN%22+%22http%...

后端接收数据方法为:
@RequestMapping(value = "/declaretest", method = RequestMethod.POST)
@ResponseBody
public JSONObject declaretest(String messageType, String messageText,
HttpServletRequest request) {
return internationalTradeService.declaretest(messageType, messageText);
}
加断点调试,发现messageText接收内容如下(内容过长,所以显示不全,除中文显示不对外,其他都对):



KJ881110_CORP_2012121212121200001
KJ881110
TEST00001

KJGGPT
KJGGPT

20121212121212
1.0
待定

PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPEludGVybmF0aW9uYWxUcmFkZT4KCTxIZWFkPgoJCTxNZXNzYWdlSUQ+S0o4ODExMTBfQ09...

这里就有个问题:数据传输前是通过encode的,但是后端方法接收前并没有明确的解码处理,但是数据确实是被解码了,这是如何发生的和在什么阶段发生的呢?

思路过程:
springMVC是交由DispatcherServlet处理各种请求的,所以第一时间考虑是不是DispatcherServlet中是不是对参数做了处理了。断点调试DispatcherServlet中的doService、doDispatch方法,发现request携带的参数数据早已被解码了。DispatcherServlet继承FrameworkServlet,往上溯源,调试FrameworkServlet的doPost方法,继而HttpServletBean、HttpServlet,但是结果都是参数数据已被解码了。

阅读这篇文章有利于更好的理解以下的内容:http://blog.csdn.net/cutesource/article/details/5091732
https post调用以及前端到后台中传输数据encode和decode的自动转化问题_第1张图片

重点关注Request类,发现里面有两个类 org.apache.tomcat.util.http.Parameters和org.apache.tomcat.util.buf.UDecoder,Parameters应该是参数类,UDecoder是解码类了。请看Parameters类里重点代码:
private void processParameters(byte bytes[], int start, int len,
Charset charset) {
...
int pos = start;
int end = start + len;

while(pos < end) {
int nameStart = pos;
int nameEnd = -1;
int valueStart = -1;
int valueEnd = -1;

boolean parsingName = true;
boolean decodeName = false;
boolean decodeValue = false;
boolean parameterComplete = false;

do {
//检查是否含有特殊字符
switch(bytes[pos]) {
case '=':
if (parsingName) {
// Name finished. Value starts from next character
nameEnd = pos;
parsingName = false;
valueStart = ++pos;
} else {
// Equals character in value
pos++;
}
break;
case '&':
if (parsingName) {

// Name finished. No value.

nameEnd = pos;

} else {

// Value finished

valueEnd = pos;

}

parameterComplete = true;

pos++;

break;

case '%':

case '+':

// Decoding required

if (parsingName) {

decodeName = true;

} else {

decodeValue = true;

}

pos ++;

break;

default:

pos ++;

break;

}

} while (!parameterComplete && pos < end);


...


try {

String name;

String value;


if (decodeName) {

//解码参数名称

urlDecode(tmpName);

}

//默认是ISO-8859-1

tmpName.setCharset(charset);

name = tmpName.toString();


if (valueStart >= 0) {

if (decodeValue)

//解码参数值

urlDecode(tmpValue);

}

tmpValue.setCharset(charset);

value = tmpValue.toString();

} else {

value = "";

}


try {

addParameter(name, value);

} catch (IllegalStateException ise) {

...

}

} catch (IOException e) {

...

}

...

}

}

若检查到参数名和参数值含有特殊字符=、&、%、+,则会对其进行urlDecode解码操作,默认解码格式public static final String DEFAULT_ENCODING = "ISO-8859-1";

但是ISO-8859-1对中文产生的乱码问题,解决方法可以是在项目web.xml中配置CharacterEncodingFilter:

characterEncodingFilter

org.springframework.web.filter.CharacterEncodingFilter

encoding

UTF-8

forceEncoding

true

characterEncodingFilter

/*


(2)jsp页面的<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>或已经相当于java.net.URLEncoder.encode(content,"utf-8"),传输数据到了后端,tomcat自然自动解码了。


五、总结
对于传输数据中有特殊字符的,web服务器会预先decode一次。

你可能感兴趣的:(https post调用以及前端到后台中传输数据encode和decode的自动转化问题)