You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

提交含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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:29:54