Android APP 在部分华为手机上出现了乱码问题,找了好久了终于找到原因了
前后台post请求体编码和解码时一致的 URL;UTF-8
但是还是出现了乱码,原因如下:
Content-Type:application/x-www-form-urlencoded; charset=UTF-8,application/x-www-form-urlencoded; charset=utf-8
Content-Type:application/x-www-form-urlencoded含义是表示客户端提交给服务器文本内容的编码方式 是URL编码,
即除了标准字符外,每字节以双字节16进制前加个“%”表示,当然还有其他编码方式,如:CONTENT-TYPE:multipart/form-data 。
Content-Type 内容重复了,格式不对,服务器识别不了,所有当发送post请求时请求体里面有中文时服务器解码不正确,所以乱码了
具体问题如下(使用了Volley请求)
1.Volley post请求是请求头会自动加上content-type
详细代码如下:
public static RequestQueuenewRequestQueue(Context context, HttpStack stack) {
File cacheDir = new File(context.getCacheDir(), "volley");
String userAgent = "volley/0";
try {
String network = context.getPackageName();
PackageInfo queue = context.getPackageManager().getPackageInfo(network,0);
userAgent = network + "/" + queue.versionCode;
} catch (NameNotFoundException var6) {
;
}
if(stack == null) {
if(VERSION.SDK_INT>= 9) {
stack = newHurlStack();
} else {
stack = newHttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
BasicNetwork network1 = new BasicNetwork((HttpStack)stack);
RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir),network1);
queue1.start();
return queue1;
}
HurlStack类中
publicHttpResponse performRequest(Request<?> request, Map<String, String>additionalHeaders) throws IOException, AuthFailureError {
String url = request.getUrl();
HashMap map = new HashMap();
map.putAll(request.getHeaders());
map.putAll(additionalHeaders);
if(this.mUrlRewriter != null) {
String parsedUrl =this.mUrlRewriter.rewriteUrl(url);
if(parsedUrl == null) {
throw new IOException("URLblocked by rewriter: " + url);
}
url = parsedUrl;
}
URL parsedUrl1 = new URL(url);
HttpURLConnection connection =this.openConnection(parsedUrl1, request);
//volley使用的是HttpURLConnection
Iterator responseCode =map.keySet().iterator();
while(responseCode.hasNext()) {
String protocolVersion =(String)responseCode.next();
connection.addRequestProperty(protocolVersion,(String)map.get(protocolVersion));
}
setConnectionParametersForRequest(connection, request);//注意这个方法
ProtocolVersion protocolVersion1 = newProtocolVersion("HTTP", 1, 1);
int responseCode1 =connection.getResponseCode();
if(responseCode1 == -1) {
throw new IOException("Couldnot retrieve response code from HttpUrlConnection.");
} else {
BasicStatusLine responseStatus =new BasicStatusLine(protocolVersion1, connection.getResponseCode(),connection.getResponseMessage());
BasicHttpResponse response = newBasicHttpResponse(responseStatus);
response.setEntity(entityFromConnection(connection));
Iterator var12 =connection.getHeaderFields().entrySet().iterator();
while(var12.hasNext()) {
Entry header =(Entry)var12.next();
if(header.getKey() != null) {
BasicHeader h = newBasicHeader((String)header.getKey(), (String)((List)header.getValue()).get(0));
response.addHeader(h);
}
}
return response;
}
}
下面的添加content-type请求头参数的方法
static voidsetConnectionParametersForRequest(HttpURLConnection connection,Request<?> request) throws IOException, AuthFailureError {
switch(request.getMethod()) {
case -1:
byte[] postBody =request.getPostBody();
if(postBody != null) {
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.addRequestProperty("Content-Type", request.getPostBodyContentType());
DataOutputStream out = newDataOutputStream(connection.getOutputStream());
out.write(postBody);
out.close();
}
break;
case 0:
connection.setRequestMethod("GET");
break;
case 1:
connection.setRequestMethod("POST");
addBodyIfExists(connection,request);
break;
case 2:
connection.setRequestMethod("PUT");
addBodyIfExists(connection,request);
break;
case 3:
connection.setRequestMethod("DELETE");
break;
default:
throw newIllegalStateException("Unknown method type.");
}
}
private staticvoid addBodyIfExists(HttpURLConnection connection, Request<?> request)throws IOException, AuthFailureError {
byte[] body = request.getBody();
if(body != null) {
connection.setDoOutput(true);
connection.addRequestProperty("Content-Type",request.getBodyContentType());
DataOutputStream out = newDataOutputStream(connection.getOutputStream());
out.write(body);
out.close();
}
}
默认的请求和自己设置为post请求都会添加一个content-type
protectedString getParamsEncoding() {
return "UTF-8";
}
public String getBodyContentType() {
return"application/x-www-form-urlencoded; charset=" +this.getParamsEncoding();
}
content-type的值为application/x-www-form-urlencoded; charset=UTF-8
2.android 在部分华为手机上乱码
Volley VERSION.SDK_INT>= 9 时使用的是 HttpURLConnection
HttpURLConnection添加请求头参数的代码如下
public synchronized voidaddRequestProperty(String var1, String var2) {
if(!this.connected && !this.connecting) {
if(var1 == null) {
throw newNullPointerException("key is null");
} else {
if(this.isExternalMessageHeaderAllowed(var1, var2)) {
this.requests.add(var1, var2);
if(!var1.equalsIgnoreCase("Content-Type")){
this.userHeaders.add(var1, var2);
}
}
}
} else {
throw new IllegalStateException("Already connected");
}
}
// this.requests.add(var1, var2); 这段代码是加入content-type 的代码
private MessageHeader requests; //requests为MessageHeader 的实例
MessageHeader 是通过数组来存储key和value的
publicsynchronized void add(String var1, String var2) {
this.grow();
this.keys[this.nkeys] = var1;
this.values[this.nkeys] = var2;
++this.nkeys;
}
private voidgrow() {
if(this.keys == null || this.nkeys>= this.keys.length) {
String[] var1 = new String[this.nkeys + 4];
String[] var2 = new String[this.nkeys + 4];
if(this.keys != null) {
System.arraycopy(this.keys, 0,var1, 0, this.nkeys);
}
if(this.values != null) {
System.arraycopy(this.values,0, var2, 0, this.nkeys);
}
this.keys = var1;
this.values = var2;
}
}
正常情况下加两次content-type 会在请求头里面重新两次content-type
如下:
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Content-Type: application/x-www-form-urlencoded;charset=utf-8
但是在部分华为手机上会奇葩的自动拼接到一起
Content-Type:application/x-www-form-urlencoded; charset=UTF-8,application/x-www-form-urlencoded; charset=utf-8
看到上面的奇葩逗号没,格式不对了,服务器无法识别这种格式的请求体了编码方式了,最后出现乱码了。
具体是为什么Content-Type字段的值在部分华为的手机上为什么会拼接到一起,还没有找到原因,求大神们指导一下