我的HttpURLConnection请求出了什么问题?

时间:2019-04-11 14:16:22

标签: java rest spring-boot odata

我正在尝试使用PUT请求调用REST API,但是我收到了400错误代码(错误请求)。有人可以发现我可能在做错什么吗?

我已经使用REST客户端成功调用了此API,以下是使用的标头和正文:

https://imgur.com/dZVyawn https://imgur.com/lMtn2JB

    String credentials = Base64.getEncoder().encodeToString(("wcadmin:wcadmin").getBytes());
    URL url = new URL(getURL());
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("PUT");
    connection.setDoOutput(true);
    connection.setDoInput(true);

    //Set Headers
    String fileUrl = "c:\\0000000050.xml";
    File fileToUpload = new File(fileUrl);
    long length = fileToUpload.length();
    String FORM_DATA_BOUNDARY = "------FormBoundary" + System.currentTimeMillis();
    connection.setRequestProperty("csrf_nonce", getNonceValue());
    connection.setRequestProperty("Accept", "application/xml");
    connection.setRequestProperty("Authorization", "Basic " + credentials);
    connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + FORM_DATA_BOUNDARY);
    connection.setRequestProperty("Content-Length", Long.toString(length));

    //Setup Request Body Writer
    OutputStream requestBodyOutputStream = connection.getOutputStream();
    BufferedWriter requestBodyWriter = new BufferedWriter(new OutputStreamWriter(requestBodyOutputStream));

    //Write Body
    requestBodyWriter.write("\r\n\r\n");
    requestBodyWriter.write(FORM_DATA_BOUNDARY);
    requestBodyWriter.write("\r\n");
    requestBodyWriter.write("Content-Disposition: form-data; name=\"file\"; filename=\"" + fileUrl + "\"");
    requestBodyWriter.write("\r\n");
    requestBodyWriter.write("Content-Type: text/xml");
    requestBodyWriter.write("\r\n\r\n");
    requestBodyWriter.flush();

    FileInputStream uploadFileStream = new FileInputStream(fileToUpload);
    int bytesRead;
    byte[] dataBuffer = new byte[1024];
    while ((bytesRead = uploadFileStream.read(dataBuffer)) != -1) {
        requestBodyOutputStream.write(dataBuffer, 0, bytesRead);
    }
    requestBodyOutputStream.flush();

    requestBodyWriter.write("\r\n");
    requestBodyWriter.write(FORM_DATA_BOUNDARY);
    requestBodyWriter.flush();

    //Close the streams
    requestBodyOutputStream.close();
    requestBodyWriter.close();
    uploadFileStream.close();

    //Read Response
    String inputLine;
    StringBuffer content = new StringBuffer();
    InputStream inputStream = connection.getInputStream();
    if (inputStream != null) {
        BufferedReader responseReader = new BufferedReader(new InputStreamReader(inputStream));
        if (responseReader != null) {
            while ((inputLine = responseReader.readLine()) != null) {
                content.append(inputLine);
            }
            responseReader.close();
        }
    }

    connection.disconnect();

收到错误400错误的请求响应

1 个答案:

答案 0 :(得分:0)

第一个也是最重要的一点:您不能同时写入OutputStream和包装相同的OutputStream的OutputStreamWriter。他们会互相冲突。

完全不使用OutputStreamWriter;而是自己将文本转换为字节:

OutputStream requestBodyOutputStream = connection.getOutputStream();

requestBodyOutputStream.write("\r\n\r\n".getBytes(StandardCharsets.UTF_8));
requestBodyOutputStream.write(FORM_DATA_BOUNDARY.getBytes(StandardCharsets.UTF_8));
// etc.

第二,您正在使用系统的默认字符集在字节和字符串之间进行转换,这意味着确切地编写的内容取决于运行代码的系统。在未指定显式字符集的情况下,请勿调用String.getBytes。通常getBytes(StandardCharsets.UTF_8)是您想要的。

类似地,您需要将一个Charset传递到InputStreamReader的创建中(尽管这不是问题的根源,因为您目前没有收到有效的回复)。不要假设一个字符集;使用响应的Content-Type标头中的charset MIME类型参数。如果您使用的Java版本早于11,则可以使用javax.activation.MimeType类解析Content-Type值,但是请注意,从Java 11开始,javax.activation软件包已从Java SE中删除。对于Java 11及更高版本,将Java Activation can be downloaded作为独立库。另一种选择是使用JavaMail库(特别是其ContentType类)进行解析。

第三,正文部分(边界之间)的内容长度标头 应该使用文件的长度作为内容长度。 整个请求正文的Content-Length必须是您编写的所有内容的长度:边界,正文部分标题和文件内容。

一个好消息是,我认为(尽管我不是很肯定)URLConnection会根据您写入的字节数自动设置请求的整体Content-Length,因此您可能不需要自己计算长度;您可以根本不用设置“ Content-Length”。

当您传递正确的请求时,您会发现您正在响应中删除换行符。如果响应应该是人类可读的文本,则这些换行符可能很重要。如果您使用的是Java 10或更高版本,则可以将Reader.transferTo与StringWriter结合使用:

StringWriter responseBody = new StringWriter();
responseReader.transferTo(responseBody);
String content = responseBody.toString();

如果您使用的Java版本低于10:

  • new BufferedReader 不能返回null,因此检查null是没有意义的。在Java中,new运算符无论如何都会始终返回一个新对象(除非引发异常,在这种情况下,new根本不会返回)。
  • 您应该使用StringBuilder,而不是StringBuffer。它们是相同的,只是StringBuffer是一个较旧的类,它为每种方法提供线程安全性,从而几乎为所有用例带来不必要的开销。

您正在将文件复制到请求中,而没有任何缓冲,这将很慢且效率低下。考虑改用Files.copy(fileToUpload.toPath(), requestBodyOutputStream)