Как построить правильный MultipartEntity для отправки нескольких частей / связанных запросов в Java? - PullRequest
0 голосов
/ 16 января 2019

Я хочу отправить на OCR изображение с локального компьютера, а не какой-нибудь удаленный URL с изображением там (в этом случае отлично работает).Но проблема в том, что я не знаю, как правильно построить полезную нагрузку из нескольких частей.Моя полезная нагрузка должна выглядеть так, как описано ниже.

Это то, что описано в документации API .Декодируйте данные изображения, данные непосредственно в составных / связанных данных.Порядок важен, и первая часть должна быть JSON, которая говорит ему, какой механизм OCR использовать.Схема для этого JSON документирована в конечной точке /ocr.Параметр img_url JSON в этом случае будет игнорироваться.

Вложение изображения должно быть частью секунда , и оно должно работать с любым типом содержимого изображения (например, image /PNG, изображения / JPG, и т. д.).

   Request (multipart/related; boundary=---BOUNDARY)

    -----BOUNDARY
    Content-Type: application/json

    {"engine":"tesseract"}
    -----BOUNDARY

    -----BOUNDARY
    Content-Disposition: attachment;
    Content-Type: image/png
    filename="attachment.txt".

    PNGDATA.........
    -----BOUNDARY

Вот что я пробовал.Для выполнения многочастного / связанного запроса я использую org.apache.httpcomponents

    CloseableHttpClient httpClient = HttpClients.createDefault();

    MultipartEntityBuilder multipartEntityBuilder =
            MultipartEntityBuilder.create().setBoundary(BOUNDARY).setContentType(ContentType.APPLICATION_JSON).addTextBody("engine", "tesseract")
                                                    .setBoundary(BOUNDARY).setBoundary(BOUNDARY);

    multipartEntityBuilder.addBinaryBody("file_upload", new File(fileTextPath), ContentType.create(CONTENT_TYPE), fileTextPath).setBoundary(BOUNDARY);

    HttpEntity entity = multipartEntityBuilder.build();


    HttpPost httpPost = new HttpPost(URL);
    httpPost.setHeader(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_MULTIPART+";boundary="+BOUNDARY);
    httpPost.setEntity(entity);

1 Ответ

0 голосов
/ 18 февраля 2019

Я решил эту проблему несколько недель назад и для удобства создал облегченное веб-приложение на Java для обоих случаев (удаленная загрузка и загрузка файлов).

Вы можете найти конкретный ответ на вопрос выше здесь . Исходный код для составного запроса показан ниже:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public class MultipartUtility {
    private static final Logger logger = LoggerFactory.getLogger(MultipartUtility.class);

    private final String boundary = UUID.randomUUID().toString();
    private static final String LINE_FEED = "\r\n";
    private HttpURLConnection httpConn;
    private String charset;
    private OutputStream outputStream;
    private PrintWriter writer;

    /**
     * This constructor initializes a new HTTP POST request with content type
     * is set to multipart/form-data
     *
     * @param requestURL
     * @param charset
     * @throws IOException
     */
    public MultipartUtility(String requestURL, String charset) {
        this.charset = charset;

        try {
            URL url = new URL(requestURL);
            httpConn = (HttpURLConnection) url.openConnection();
            httpConn.setUseCaches(false);
            httpConn.setDoOutput(true); // indicates POST method
            httpConn.setDoInput(true);
            httpConn.setRequestProperty("Content-Type", "multipart/related; boundary=\"" + boundary + "\"");
            httpConn.setRequestProperty("Accept-Encoding", "gzip");
            outputStream = httpConn.getOutputStream();
            //outputStream = System.out;
            writer = new PrintWriter(new OutputStreamWriter(outputStream, charset), true);
        } catch (IOException ex) {
            logger.error("Error during creation of MultiPart: ", ex);
        }
    }

    /**
     * Adds a form field to the request
     */
    public void addFormField(String jsonBody) {
        writer.append("--").append(boundary).append(LINE_FEED);
        writer.append("Content-Type: application/json;").append(LINE_FEED);
        writer.append(LINE_FEED);
        writer.append(jsonBody).append(LINE_FEED);
        writer.flush();
    }

    /**
     * Adds a upload file section to the request
     *
     * @param uploadFile a File to be uploaded
     * @throws IOException
     */
    public void addFilePart(File uploadFile) {
        String fileName = uploadFile.getName();
        writer.append("--").append(boundary).append(LINE_FEED);
        writer.append("Content-Disposition: attachment;");
        writer.append(" filename=\"" + fileName + "\".").append(LINE_FEED);
        writer.append("Content-Type: image/*").append(LINE_FEED);
        writer.append(LINE_FEED);
        writer.flush();

        try {
            FileInputStream inputStream = new FileInputStream(uploadFile);
            //byte[] buffer = new byte[(int) uploadFile.length()];
            byte[] buffer = Files.readAllBytes(Paths.get(uploadFile.getPath()));
            int bytesRead = -1;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
            inputStream.close();
        } catch (IOException ex) {
            logger.error("File transformation to bytes went wrong: {}", ex);
        }

        writer.append(LINE_FEED);
        writer.flush();
    }

    /**
     * Adds a header field to the request.
     *
     * @param name  - name of the header field
     * @param value - value of the header field
     */
    public void addHeaderField(String name, String value) {
        writer.append(name + ": " + value).append(LINE_FEED);
        writer.flush();
    }

    /**
     * Completes the request and receives response from the server.
     *
     * @return a list of Strings as response in case the server returned
     * status OK, otherwise an exception is thrown.
     * @throws IOException
     */
    public String finish() {
        String response = "";
        int status = 0;

        writer.flush();
        writer.append("--").append(boundary).append("--").append(LINE_FEED);
        writer.println();
        writer.close();

        try {
            // checks server's status code first
            status = httpConn.getResponseCode();

            if (status == HttpURLConnection.HTTP_OK) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));

                String line;
                while ((line = reader.readLine()) != null) {
                    response += line;
                }

                reader.close();
                httpConn.disconnect();
            } else {
                logger.error("OCR API returned error stream: {}", printErrorStream());
                throw new IOException("Server returned non-OK status: " + status + " : " + httpConn.getResponseMessage());
                //logger.error("Server returned non-OK status: " + status + " : " + httpConn.getResponseMessage());
            }
        } catch(IOException ex) {
            logger.error("Response message in Multipart finish has been received with problems: ", ex);
        }

        return response;
    }

    private String printErrorStream() throws IOException {
        //System.out.print("DEBUG System out ocr API error stream: ");
        InputStream errorStream = httpConn.getErrorStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream));
        String errLine = "", tempLine;
        while ((tempLine = reader.readLine()) != null) {
            errLine += tempLine;
        }

        return errLine;
    }

    private void getRequestHeaders(HttpURLConnection httpURLConnection) {
        for (Map.Entry<String, List<String>> entries : httpURLConnection.getRequestProperties().entrySet()) {
            String values = "";
            for (String value : entries.getValue()) {
                values += value + ",";
            }
            System.out.println("Request" + " " + entries.getKey() + " - " +  values );
        }
    }
}
...