POST请求实现文件传输 您所在的位置:网站首页 mydownloads文件 POST请求实现文件传输

POST请求实现文件传输

#POST请求实现文件传输| 来源: 网络整理| 查看: 265

通过POST请求以form-data形式在前后端以及后端服务间传递文件。

通过设置http请求response的content-type,后端以二进制流传递数据给前端。

1 以form-data传数据给后端 1.1 后端数据接收接口定义

后端接口/form-data定义

@Slf4j @RestController @RequestMapping(value = "/rest") public class FileTransmit {    @PostMapping(value = "/form-data")    public String formData(HttpServletRequest request,                           @RequestParam(value = "email", required = false) String email,                           @RequestParam(value = "file_excel", required = false) MultipartFile multipartFile,                           UserInfo userInfo) {        StandardMultipartHttpServletRequest standardMultipartRequest = (StandardMultipartHttpServletRequest) request; ​        log.info("multipartFile in @RequestParam={}", multipartFile.getOriginalFilename());        MultiValueMap multiFileMap = standardMultipartRequest.getMultiFileMap();        for (String paramKey : multiFileMap.keySet()) {            List multipartFileList = multiFileMap.get(paramKey);            log.info("MultipartFile key={}, size={}", paramKey, multipartFileList.size());            for (MultipartFile curMultipartFile : multipartFileList) {                log.info("MultipartFile key={}, file name={}",                        paramKey, curMultipartFile.getOriginalFilename());                log.info("MultipartFile in request equals to file in @RequestParam={}",                        multipartFile.equals(curMultipartFile));           }       } ​        log.info("email in @RequestParam={}", email);        log.info("userInfo in RequestParam={}", userInfo);        Map paramMap = standardMultipartRequest.getParameterMap();        for (String paramKey : paramMap.keySet()) {            log.info("param key={}, size={}, value={}",                    paramKey, paramMap.get(paramKey).length, paramMap.get(paramKey));       }        return "Form Data processed finished!";   } } 复制代码 1.2 postman调试接口

image-20220103112627238.png

设置请求body为form-data类型,可以同时传递文本数据和文件数据,文件key允许包含多个文件(file_excel),key也允许重复(id, name, email)。

从运行结果来看,@RequestParam注解可以获取form-data中指定key的数据,而HttpServletRequest request则包含了所有的form-data数据。

由于@RequestParam修饰的email和multipartFile不是数组或者List类型,文本类型的email取拼接值,而文件类型的multipartFile则取第1个value值。修改接口定义,改为List multipartFile就可以接收多个文件。

image-20220103113051282.png

image-20220103113405153.png

1.3 前端传递form-data

以简单的html演示在页面填写数据,点击提交时调用1.1节定义的接口并把数据以form-data形式传递给后端。

       Upload FormData                       ID:           ID:           Name:           Name:           Email:           Email:           File:           File:                                     复制代码

image-20220103114333475.png

1.4 后端传递form-data

展示如何后端直接封装form-data格式的数据,然后调用1.1节定义的接口,实现后端服务间的文件数据传递。

通过HttpHeaders设置请求传递的数据类型为form-data,通过HttpEntity封装requset header和request body,通过RestTemplate的postForObject方法调用POST接口。

使用MultiValueMap封装form-data格式的数据,文件类型数据采用FileSystemResource。

public class FileTransmitTest {    private RestTemplate restTemplate;    private final String URL_ROOT = "http://localhost:8080/rest"; ​    @Before    public void init() {        restTemplate = new RestTemplate();   } ​    @Test    public void FormDataTest() {        MultiValueMap requestBody = new LinkedMultiValueMap();        requestBody.add("file_excel",                        new FileSystemResource(new File("E:\dataJava\data\city_info.xlsx")));        requestBody.add("file_excel",                        new FileSystemResource(new File("E:\dataJava\data\user_info.xlsx")));        requestBody.add("file_img",                        new FileSystemResource(new File("E:\dataJava\data\github.png")));        requestBody.add("email", "[email protected]");        requestBody.add("email", "[email protected]");        requestBody.add("id", "123");        requestBody.add("id", "12345");        requestBody.add("name", "zhangsan");        requestBody.add("name", "kuangtu"); ​        HttpHeaders httpHeaders = new HttpHeaders();        httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); ​        HttpEntity requestEntity =            new HttpEntity(requestBody, httpHeaders);        String response = restTemplate.postForObject(URL_ROOT+"/form-data", requestEntity, String.class);        System.out.println(response);   } } 复制代码 1.5 传单个文件给后端

演示后端接收单个文件并保存到指定目录。

接口定义

   @ResponseBody    @PostMapping(value = "/receive/single")    public String receiveSingle(MultipartFile multipartFile) throws IOException {        if (multipartFile == null) {            return "received file is null!";       }        log.info("文件content-type={}", multipartFile.getContentType());        log.info("文件大小={}", multipartFile.getSize());        log.info("文件名={}", multipartFile.getName());        log.info("文件原始名={}", multipartFile.getOriginalFilename());        // 保存接收的文件到本地        File destFile = new File("E:\Download\"+multipartFile.getOriginalFilename());        multipartFile.transferTo(destFile);        return "Form Data processed finished!";   } 复制代码

接口调用

由于接口定义中没有使用@RequestParam注解,当form-data的key不为参数名multipartFile时,变量multipartFile无法初始化,为null。只有当form-data的key设置为multipartFile时,才能正常初始化。

image-20220103120539954.png

如果修改接口定义为

public String receiveSingle(@RequestParam(value = "file") MultipartFile multipartFile) throws IOException 复制代码

那么form-data的key只能设置为file才能完成multipartFile变量的初始化。因此建议@RequestParam中value值和变量名保存一致,接口调用时封装参数的key也用变量名。

1.6 总结 以form-data传输数据给后端,需要设置request header中content-type="multipart/form-data"。 form-data可以同时传递文本和文件给后端。 对于文件类型的form-data数据,后端接口以MultiPartFile类型接收,并可以通过MultiPartFile的transferTo将文件保存到本地。 对于文本类型的form-data数据,可以定义类接收,也可以用基本类型变量逐个接收。 Spring工程后端接口中HttpServletRequest request包含了所有的form-data数据。 2 后端传文件给前端

这里以后端传图片给前端使用为例,方法包括以下3种:

后端把图片保存在文件存储服务器上,返回图片的url给前端,前端设置img标签的src=url即可。这种方式应该是主流,但是不想再搞个存储服务器,没有采用这种方式。 后端以把图片的base64编码以字符串的形式返给前端,前端再解析为图片展示。这种方式虽然存在大图片有可能被截断的肯,但是来得方便,选用了这种方式。 后端以把图片的二进制流以字节数组的形式返给前端,前端再解析为图片展示。返回二进制流不仅适用于图片,还适用于音视频。 2.1 以base64编码传输

后端接口定义

   @CrossOrigin  //允许跨域访问    @GetMapping(value = "/get-img-code")    public String getImageBase64(String imageName) throws IOException {        log.info("request param={}", imageName);        String imgRootPath = "E:\dataJava\data\";        File imgFile = new File(imgRootPath + imageName + ".png");        InputStream inStream =new FileInputStream(imgFile);        byte[] imgBytes = new byte[(int) imgFile.length()]; //创建合适文件大小的数组        inStream.read(imgBytes); //读取文件里的内容到b[]数组        inStream.close();        log.info("image size={}", imgBytes.length);        BASE64Encoder encoder = new BASE64Encoder();        return encoder.encodeBuffer(imgBytes);   } 复制代码 2.2 以二进制流传输

后端接口定义

   @CrossOrigin  //允许跨域访问    @GetMapping(value = "/get-img-byte")    public void getImageByte(HttpServletRequest request, HttpServletResponse response, String imageName) throws IOException {        String imgRootPath = "E:\dataJava\data\";        File imgFile = new File(imgRootPath + imageName + ".png");        InputStream inStream =new FileInputStream(imgFile);        byte imgBytes[] = new byte[(int) imgFile.length()]; //创建合适文件大小的数组        inStream.read(imgBytes); //读取文件里的内容到b[]数组        inStream.close(); ​        response.setContentType("application/octet-stream;charSet=UTF-8");        response.setContentLength(imgBytes.length);        try (InputStream inputStream = new ByteArrayInputStream(imgBytes);            OutputStream outputStream = response.getOutputStream()) {            IOUtils.copy(inputStream, outputStream);            outputStream.flush();       }catch (IOException e) {            log.error("{}", e.getMessage());       }   } 复制代码 2.3 html接收并展示        Title                                base64 image            获取并展示图片                                        byte image                         ​            function getImgBase64() {            $.ajax({                url : "http://localhost:8080/rest/get-img-code?imageName=github",                type : 'GET',                contentType : false,  //必须false才会自动加上正确的Content-Type                success : function(result) {  //jquery请求返回的结果好像都是字符串类型                    console.log("reponse result:", result);                    var src = 'data:image/png;base64,' + result;                    $("#base64_img").attr('src', src);                    $("#base64_img").css("width", "70%");                    $("#base64_img").css("height", "70%");               },                error : function(result) {                    console.log("reponse result:", result);                    alert("Post Faile!");               }           });       }     复制代码

运行效果:

image-20220103143611952.png

附:HTTP Headers

HTTP 消息头允许客户端和服务器通过 request和 response传递附加信息。一个请求头由名称(不区分大小写)后跟一个冒号“:”,冒号后跟具体的值(不带换行符)组成。

根据不同上下文,可将消息头分为:

General headers: 同时适用于请求和响应消息,但与最终消息主体中传输的数据无关的消息头。 Request headers: 包含更多有关要获取的资源或客户端本身信息的消息头。 Response headers: 包含有关响应的补充信息,如其位置或服务器本身(名称和版本等)的消息头。 Entity headers: 包含有关实体主体的更多信息,比如主体长(Content-Length)度或其MIME类型。

Request headers中

Accept:表示浏览器告诉服务端,浏览器可以接收的数据类型。 Accept-Encoding:表示浏览器告诉服务端,浏览器可以接收的数据的编码方式。 Accept-Language:表示浏览器告诉服务端,浏览器可以接收的数据语言,通常用于做国际化。 Content-Type:POST和PUT请求body的文件类型。

Reponse headers中

Content-Type:接口返回的数据类型。 Content-Length:octets (8-bit bytes)中返回body的长度

参考资料:

HTTP Headers

List of HTTP header fields



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有