专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

HttpClient模拟文件上传

  • 本例使用的是springboot,具体的springboot依赖就不贴了,只贴httpclient请求需要的依赖.需要注意的是,httpcore的版本和httpclient的版本并不一致.
 <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.13</version>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpmime</artifactId>
            <version>4.5.12</version>
        </dependency>

  • 在Java代码中模拟文件服务器端
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;

@RestController
@RequestMapping("/file")
public class FileUploadController {
    private String path ="D://data//";
    @RequestMapping(value = "/upload",method = RequestMethod.POST)
    public Object upload(@RequestParam("file") MultipartFile file){
        if(!file.isEmpty()){
            String fileName = file.getOriginalFilename();
            File dest = new File(path + fileName);
            try {
                file.transferTo(dest);
                return "上传成功";
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return "上传失败!";
    }
}

  • 启动工程,通过Postman工具测试,本例使用的Chrome浏览器插件Talend API Free Edition.效果截图

70_1.png

  • 测试成功,开始通过HttpClient模拟文件上传,本例通过junit测试类进行验证
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.Test;

import java.io.File;
import java.io.IOException;

public class FileUploadTest {

    @Test
    public void test01() throws IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();

        HttpPost httpPost = new HttpPost("http://localhost:8080/file/upload");
        httpPost.setHeader("Content-type", ContentType.MULTIPART_FORM_DATA.getMimeType());

        File file = new File("D://data.docx");

        FileBody bin = new FileBody(file);
        StringBody comment = new StringBody(file.getName(), ContentType.TEXT_PLAIN);
        HttpEntity reqEntity = MultipartEntityBuilder.create().addPart("file", bin).build();
        httpPost.setEntity(reqEntity);
        System.out.println("executing request " + httpPost.getRequestLine());
        CloseableHttpResponse response = httpClient.execute(httpPost);
        try {
            System.out.println(response.getStatusLine());
            HttpEntity resEntity = response.getEntity();
            if (resEntity != null) {
                String responseEntityStr = EntityUtils.toString(response.getEntity());
                System.out.println(responseEntityStr);
            }
            EntityUtils.consume(resEntity);
        } finally {
            response.close();
        }

    }
}

  • 美滋滋的写完,开始测试,结果报错了
org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found

  • 网上搜下问题,找到了如下内容

stackoverflow.com/questions/1…

You should NEVER set that header yourself. We set the header properly with the boundary. If you set that header, we won't and your server won't know what boundary to expect (since it is added to the header). Remove your custom Content-Type header and you'll be fine

大体的意思就是去掉header中的Content-type,它会自动给加上;我在测试类中去掉header关于Content-type的配置后,发现果然可以了.

  • 那么问题来了,为什么加上去就不可以了呢.我大概翻了几个网上的文章,好像是和boundary这个属性有关,因为在网页请求的时候,会在Content-type:multipart/form-data 后面跟上boundary一串内容.

引自 tech.souyunku.com/fighter007/…

boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 mutipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 --boundary 开始,紧接着内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。
如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 --boundary-- 标示结束。这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。

文章永久链接:https://tech.souyunku.com/36142

未经允许不得转载:搜云库技术团队 » HttpClient模拟文件上传

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们