简体   繁体   English

如何使用 JDK 11 java.net.http.HttpClient 上传文件?

[英]How to upload files using JDK 11 java.net.http.HttpClient?

I recently encountered some problems with java.net.http.HttpClient that comes with JDK 11. I don't know how to use file upload.最近遇到JDK 11自带的java.net.http.HttpClient的一些问题,不知道怎么用文件上传。 Found the ofInputStream() in java.net.http.BodyPublishers.在 java.net.http.BodyPublishers 中找到了 ofInputStream()。 I don't know if I using this method file upload.我不知道我是否使用这种方法文件上传。 Here are the examples I wrote.以下是我写的例子。

    public HttpResponse<String> post(String url, Supplier<? extends InputStream> streamSupplier, String... headers) throws IOException, InterruptedException {
        HttpRequest.Builder builder = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .headers(headers)
                .POST(null == streamSupplier ?
                        HttpRequest.BodyPublishers.noBody() : HttpRequest.BodyPublishers.ofInputStream(streamSupplier));
        HttpRequest request = builder.build();
        log.debug("Execute HttpClient Method:『{}』, Url:『{}』", request.method(), request.uri().toString());
        return client.send(request, HttpResponse.BodyHandlers.ofString());
    }

The HttpRequest type provide factory method for creating request publisher for handling body type such as file: HttpRequest 类型提供工厂方法来创建请求发布者以处理文件等主体类型:

HttpRequest.BodyPublishers::ofFile(Path)

You can update your method:您可以更新您的方法:

public HttpResponse<String> post(String url, Path file, String... headers) throws IOException, InterruptedException {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(url))
            .headers(headers)
            .POST(null == file ? HttpRequest.BodyPublishers.noBody() : 
                HttpRequest.BodyPublishers.ofFile(file))
            .build();

        log.debug("Execute HttpClient Method:『{}』, Url:『{}』", request.method(), 
            request.uri().toString());
        return client.send(request, HttpResponse.BodyHandlers.ofString());
}

The java.net.http.HttpClient handles bytes supplied through the BodyPublisher as raw body data, without any interpretation. java.net.http.HttpClient将通过BodyPublisher提供的字节作为原始正文数据进行处理,无需任何解释。 Whether you use HttpRequest.BodyPublishers::ofFile(Path) or HttpRequest.BodyPublishers::ofByteArray(byte[]) is therefore semantically irrelevant: what changes is simply how the bytes that will be transmitted are obtained.因此,无论您使用HttpRequest.BodyPublishers::ofFile(Path)还是HttpRequest.BodyPublishers::ofByteArray(byte[])在语义上都是无关紧要的:变化只是如何获得将要传输的字节。 In case of file upload - your server probably expects that the request body will be formatted in certain ways.在文件上传的情况下 - 您的服务器可能希望请求正文将以某些方式格式化。 It might also expect some specific headers to be transmitted with the request (such as Content-Type etc).它还可能期望一些特定的标头与请求一起传输(例如Content-Type等)。 The HttpClient will not do that magically for you. HttpClient不会为您神奇地做到这一点。 This is something you need to implement at the caller level.这是您需要在调用者级别实现的东西。

I tried this method, but I still found it unworkable, my God, this is too difficult, this is my demo.这个方法我试过了,还是不行,天哪,太难了,这是我的demo。

    @PostMapping("/upload")
    public ApiResult upload(@RequestParam("file") MultipartFile file) throws IOException, InterruptedException {
        HttpResponse<String> response;
        Supplier<? extends InputStream> streamSupplier = () -> {
            try {
                return file.getInputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        };
        response = httpClientSyncUtils.post("http://example.com/upload", streamSupplier ,
                "Content-Type", "multipart/form-data");
        return ApiResult.success(response.body());
    }

you may use the method by:您可以通过以下方式使用该方法:

public void uploadLocalFileToRemote(String notEncodedUrlStr, String remoteFilename, String localSourceDir, String localFilename) {
    
    Path sourcePath = Path.of(localSourceDir, localFilename);
    if(!sourcePath.toFile().canRead())
    {
        System.err.println("please check the local file existance/readability: " + sourcePath.toAbsolutePath());
        return;
    }
    
    FileInputStream ins = null;
    try {
        ins = new FileInputStream(sourcePath.toFile());//FileNotFoundException extends IOException
        BufferedInputStream buf_ins = new BufferedInputStream(ins);
        Supplier<? extends InputStream> streamSupplier = new Supplier<BufferedInputStream>() {
            @Override
            public BufferedInputStream get() {
                return buf_ins;
            }
        };
        
        //HttpResponse<String> response = post(notEncodedUrlStr, streamSupplier, 
        HttpResponse<String> response = post(notEncodedUrlStr, () -> buf_ins, 
                "User-Agent", "Java 11 HttpClient Bot", "Content-type", "application/octet-stream",
                "accept", "*/*", "fileName", remoteFilename);
        
        // print response:
        System.out.println(response.version().name() + " " + response.statusCode());
        // print response headers
        HttpHeaders headers = response.headers();
        headers.map().forEach((k, v) -> System.out.println(k + ":" + v));
        
        // print response body
        String body = response.body();
        System.out.println(body);
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
}

another consideration is how your server side is implemented.另一个考虑因素是您的服务器端是如何实现的。 here assume the server side will using http 1.1 "chunked".这里假设服务器端将使用 http 1.1 “分块”。 and configured a directory for remoteFilename.并为 remoteFilename 配置了一个目录。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM