提交含Base64图片的联系人数组遇Volley 413错误求助
解决Volley提交带Base64图片的联系人数组时出现413错误的问题
你遇到的413 Unexpected response code错误,核心原因是请求实体过大:当你把Base64编码的图片字符串加入联系人数组后,整个JSON数据体积会急剧膨胀(Base64编码会让原图片体积增加约33%),直接超出了服务器端配置的POST请求大小限制。下面给你分客户端优化和服务器端调整两个方向的具体解决方案:
一、客户端侧优化(优先推荐,从根源减少请求体积)
1. 压缩图片后再进行Base64编码
你现在是直接将原始Bitmap转成Base64,完全没有压缩。可以先缩小图片分辨率+降低质量,大幅减少编码后的字符串长度。修改你的getStringImage方法:
private String getStringImage(Bitmap bitmap) { // 步骤1:缩小图片尺寸(比如限制最大宽度为600px,按比例缩放高度) int maxWidth = 600; int originalWidth = bitmap.getWidth(); int originalHeight = bitmap.getHeight(); int scaledWidth = maxWidth; int scaledHeight = (int) ((float) originalHeight * maxWidth / originalWidth); Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, true); // 步骤2:压缩图片质量(JPEG格式,质量设为50%-70%足够) ByteArrayOutputStream baos = new ByteArrayOutputStream(); scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 60, baos); byte[] imageBytes = baos.toByteArray(); // 回收临时Bitmap,避免内存泄漏 if (scaledBitmap != bitmap) { scaledBitmap.recycle(); } return Base64.encodeToString(imageBytes, Base64.DEFAULT); }
2. 改用Multipart/form-data上传(更高效的文件传输方式)
把Base64图片放到JSON里并不是最优解,Multipart上传可以直接传输二进制图片数据,避免Base64的体积膨胀。你可以自定义一个Volley的MultipartRequest:
public class MultipartRequest extends Request<String> { private final Map<String, String> textParams; private final Map<String, DataPart> fileParams; private final Response.Listener<String> responseListener; public MultipartRequest(int method, String url, Map<String, String> textParams, Map<String, DataPart> fileParams, Response.Listener<String> responseListener, Response.ErrorListener errorListener) { super(method, url, errorListener); this.textParams = textParams; this.fileParams = fileParams; this.responseListener = responseListener; } @Override protected Map<String, String> getParams() throws AuthFailureError { return textParams; } @Override public String getBodyContentType() { return "multipart/form-data; boundary=VolleyMultipartBoundary"; } @Override public byte[] getBody() throws AuthFailureError { ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); try { // 添加文本参数(比如联系人的JSON数组) for (Map.Entry<String, String> entry : textParams.entrySet()) { addTextPart(dos, entry.getKey(), entry.getValue()); } // 添加图片文件(如果需要单独上传,可从联系人数组中提取) if (fileParams != null) { for (Map.Entry<String, DataPart> entry : fileParams.entrySet()) { addFilePart(dos, entry.getKey(), entry.getValue()); } } dos.writeBytes("--VolleyMultipartBoundary--\r\n"); dos.flush(); return bos.toByteArray(); } catch (IOException e) { e.printStackTrace(); return null; } } private void addTextPart(DataOutputStream dos, String key, String value) throws IOException { dos.writeBytes("--VolleyMultipartBoundary\r\n"); dos.writeBytes("Content-Disposition: form-data; name=\"" + key + "\"\r\n\r\n"); dos.writeBytes(value + "\r\n"); } private void addFilePart(DataOutputStream dos, String key, DataPart file) throws IOException { dos.writeBytes("--VolleyMultipartBoundary\r\n"); dos.writeBytes("Content-Disposition: form-data; name=\"" + key + "\"; filename=\"" + file.getFileName() + "\"\r\n"); dos.writeBytes("Content-Type: " + file.getContentType() + "\r\n\r\n"); dos.write(file.getContent()); dos.writeBytes("\r\n"); } @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { try { String responseStr = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success(responseStr, HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.success(new String(response.data), HttpHeaderParser.parseCacheHeaders(response)); } } @Override protected void deliverResponse(String response) { responseListener.onResponse(response); } public static class DataPart { private final String fileName; private final byte[] content; private final String contentType; public DataPart(String fileName, byte[] content) { this(fileName, content, "image/jpeg"); } public DataPart(String fileName, byte[] content, String contentType) { this.fileName = fileName; this.content = content; this.contentType = contentType; } public String getFileName() { return fileName; } public byte[] getContent() { return content; } public String getContentType() { return contentType; } } }
然后修改你的submitContacts方法使用这个请求:
private void submitContacts(){ Gson gson=new Gson(); String contactsJson=gson.toJson(dataArray); final String server_url="http://www.........com/TrueCaller/submit_contacts.php"; // 文本参数:联系人JSON Map<String,String> textParams=new HashMap<>(); textParams.put("array",contactsJson); // 如果需要单独上传图片(示例:假设第一个联系人有图片) Map<String, MultipartRequest.DataPart> fileParams = new HashMap<>(); if (!dataArray.isEmpty()) { Contact_Details firstContact = dataArray.get(0); if (!TextUtils.isEmpty(firstContact.getImage())) { // 这里可以直接传二进制,不需要Base64,所以建议在初始化时保存Bitmap的byte数组,避免重复编码 byte[] imageBytes = Base64.decode(firstContact.getImage(), Base64.DEFAULT); fileParams.put("contact_image", new MultipartRequest.DataPart("contact.jpg", imageBytes)); } } MultipartRequest request=new MultipartRequest(Request.Method.POST, server_url, textParams, fileParams, response -> Log.d("response", "result : "+response), error -> { error.printStackTrace(); Log.e("VolleyError", error.getMessage() != null ? error.getMessage() : "Unknown error"); }); Vconnection.getnInstance(this).addRequestQue(request); }
二、服务器端调整(放开请求大小限制)
如果客户端优化后还是超出限制,需要修改服务器的配置:
1. Apache + PHP环境
修改php.ini文件中的以下参数(根据需求调整数值,比如设为20M):
upload_max_filesize = 20M post_max_size = 20M memory_limit = 128M
修改后重启Apache服务器生效。
2. Nginx环境
在Nginx的配置文件(比如nginx.conf或站点配置文件)的server块中添加:
client_max_body_size 20M;
重启Nginx生效。
三、额外建议
- 测试时先上传单个带图片的联系人,确认请求正常后再批量上传;
- 对于不需要的默认头像或过小的图片,可以直接跳过上传,用空字符串或占位符代替;
- 考虑对图片进行懒加载或分批次上传,避免一次性提交大量数据。
内容的提问来源于stack exchange,提问作者ibad ur rahman
相关产品推荐
相关产品推荐

