Volley 库、MultipartRequest 和 UTF-8 支持

Volley Library, MultipartRequest and UTF-8 Support

我有问题。
我写了一个有服务器端和客户端的应用程序。 客户可以通过应用程序发送包含文本和照片的报告。我使用了 volley 库;所以我为名为 MultipartRequest 的请求创建了自定义 class。 我遇到的问题是,当我发送一份带有图片和一些英文文本的报告时,该程序运行良好。但是当我想用波斯语发短信时,发不出去
我用 Postman 测试了服务器的 PHP classes,即使在波斯语中也能正常工作。
如果你能帮助我,我将不胜感激。

这是我的主要方法:

private void saveRapportToServer() {
    final ProgressDialog progressDialog = new ProgressDialog(context);
    progressDialog.setMessage("Sending...");
    progressDialog.show();

    MultipartRequest multipartRequest = new MultipartRequest(Request.Method.POST, AppConfig.URL_ADD_RAPPORT,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    progressDialog.dismiss();
                    try {
                        JSONObject jObj = new JSONObject(response);
                        if (!jObj.getBoolean("error")) {

                            // Rapport successfully stored in MySQL

                        } else {
                            Log.d(TAG, jObj.getString("error_msg"));
                            // there is some error
                            onError();
                        }
                    } catch (JSONException err) {
                        Log.d(TAG, err.toString());
                    }
                }
            },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    Log.d(TAG, "Error on server --> " + error.toString());
                    progressDialog.dismiss();

                    // on error, storing the rapport to SQLite

                    onError();
                }
            }
    ) {
        /**
        * Here we are passing our string params
        */
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            // Posting params to add rapport url (php)
            Map<String, String> params = new HashMap<>();
            final String subject = _etSubject.getText().toString().trim();
            final String location = _etLocation.getText().toString().trim();
            final String description = _etDescrip.getText().toString().trim();
            final HashMap<String, String> user = db.getUserDetails();
            final String email = user.get("email");

            params.put("email", email);
            params.put("subject", subject);
            params.put("location", location);
            params.put("description", description);

            return params;
        }

        /**
        * Here we are passing image by renaming it with a unique name
        */
        @Override
        protected Map<String, DataPart> getByteData() throws AuthFailureError {
            Map<String, DataPart> params = new HashMap<>();
            long imageName = System.currentTimeMillis();
            params.put("pic", new DataPart(imageName + ".jpg", getFileDataFromDrawable(bitmap)));

            Log.i(TAG, "Data (image) params sent");
            return params;
        }
    };

    // adding request to request queue
    AppController.getInstance().addToRequestQueue(multipartRequest, tag_req);

} // END: saveRapportToServer

/**
 * The method is taking Bitmap as an argument
 * this method will return the byte[] array for the given bitmap
 * and we will send this array to the server
 */
public byte[] getFileDataFromDrawable(Bitmap bitmap) {
    ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 90, baOutputStream);
    return baOutputStream.toByteArray();
}


这里是我的 MultipartRequest class:

public class MultipartRequest extends Request<String> {

private final String twoHyphens = "--";
private final String lineEnd = "\r\n";
private final String boundary = "apiclient-" + System.currentTimeMillis();

private final Response.Listener<String> mListener;
private final Response.ErrorListener mErrorListener;
private final Map<String, String> mHeaders = new HashMap<>();

public MultipartRequest(int method, String url,
                        Response.Listener<String> listener, Response.ErrorListener errorListener) {
    super(method, url, errorListener);
    this.mListener = listener;
    this.mErrorListener = errorListener;
}

@Override
public Map<String, String> getHeaders() throws AuthFailureError {
    return (mHeaders != null) ? mHeaders : super.getHeaders();
}

@Override
public String getBodyContentType() {
    return "multipart/form-data;boundary=" + boundary;
}

@Override
public byte[] getBody() throws AuthFailureError {
    ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream();
    DataOutputStream dOutputStream = new DataOutputStream(baOutputStream);

    try {
        // populate text payload
        Map<String, String> params = getParams();
        if(params != null && params.size() > 0) {
            textParse(dOutputStream, params, getParamsEncoding());
        }

        // populate data byte payload
        Map<String, DataPart> data = getByteData();
        if(data != null && data.size() > 0) {
            dataParse(dOutputStream, data);
        }

        // close multipart form data after text and file data
        dOutputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

        return baOutputStream.toByteArray();
    } catch (IOException ex) {
        ex.printStackTrace();
    }
    return null;
}

/**
 * Custom method handle data payload.
 * @return Map data part label with data byte
 * @throws AuthFailureError
 */
protected Map<String, DataPart> getByteData() throws AuthFailureError {
    return null;
}

@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
    try {
        String utf8String = URLDecoder.decode(URLEncoder.encode(new String(response.data), "iso8859-1"), "UTF-8");
        return Response.success(utf8String,
                HttpHeaderParser.parseCacheHeaders(response));
    } catch (Exception ex) {
        return Response.error(new ParseError(ex));
    }
}

@Override
protected void deliverResponse(String response) {
    mListener.onResponse(response);
}

@Override
public void deliverError(VolleyError error) {
    mErrorListener.onErrorResponse(error);
}

/**
 * Parse string map into data output stream by key and value.
 *
 * @param dataOutputStream data output stream handle string parsing
 * @param params           string inputs collection
 * @param encoding         encode the inputs, default UTF-8
 * @throws IOException
 */
private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException {
    try {
        for(Map.Entry<String, String> entry : params.entrySet()) {
            buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
        }
    }catch (UnsupportedEncodingException ex) {
        throw new RuntimeException("Encoding not supported: " + encoding, ex);
    }
}

/**
 * Parse data into data output stream.
 *
 * @param dataOutputStream data output stream handle file attachment
 * @param data             loop through data
 * @throws IOException
 */
private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException {
    for (Map.Entry<String, DataPart> entry : data.entrySet()) {
        buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
    }
}

/**
 * Write string data into header and data output stream.
 *
 * @param dataOutputStream data output stream handle string parsing
 * @param parameterName    name of input
 * @param parameterValue   value of input
 * @throws IOException
 */
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
    dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
    dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
    dataOutputStream.writeBytes(lineEnd);
    dataOutputStream.writeBytes(parameterValue + lineEnd);
}

/**
 * Write data file into header and data output stream.
 *
 * @param dataOutputStream data output stream handle data parseing
 * @param dataFile         data byte as DataPart from collection
 * @param inputName        name of data input
 * @throws IOException
 */
private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException {
    dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
    dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" +
            inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd);
    if(dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) {
        dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd);
    }
    dataOutputStream.writeBytes(lineEnd);

    ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
    int bytesAvailable = fileInputStream.available();

    int maxBufferSize = 1024 * 1024;
    int bufferSize = Math.min(bytesAvailable, maxBufferSize);
    byte[] buffer = new byte[bufferSize];

    int bytesRead = fileInputStream.read(buffer, 0, bufferSize);

    while(bytesRead > 0) {
        dataOutputStream.write(buffer, 0, bufferSize);
        bytesAvailable = fileInputStream.available();
        bufferSize = Math.min(bytesAvailable, maxBufferSize);
        bytesRead = fileInputStream.read(buffer, 0, bufferSize);
    }
    dataOutputStream.writeBytes(lineEnd);
}

class DataPart {
    private String fileName;
    private byte[] content;
    private String type;

    public DataPart() {        }

    public DataPart(String name, byte[] data) {
        this.fileName = name;
        this.content = data;
    }

    public String getFileName() {
        return fileName;
    }

    public byte[] getContent() {
        return content;
    }

    public String getType() {
        return type;
    }
}}

我知道这是一个老问题,但我在 Google 上找到了它,所以其他人也可以。无论如何,这是一个答案。这应该允许 Volley 发送带有以 UTF-8 编码的附加数据的多部分请求。它是从下面附上的 Oscar 的回答中复制的。

private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.writeBytes(parameterValue + lineEnd); }