1.达到目的:生成一个URL,将URL放到浏览器上,enter后可下载文件
2.实现关键:
①通过HttpServletResponse response的outputStream返回二进制流;
②response.setContentType("application/octet-stream")
3.实现代码:
public void upload(HttpServletRequest request, HttpServletResponse response) { // 获取参数,GET和POST均可以 String param1 = request.getParameter("param1"); String param2 = request.getParameter("param2"); if ((null == param1 || param1.isEmpty()) || (null == param2 || param2.isEmpty())) { logger.error("error params!"); return; } logger.info("params: param1: {}, param2: {}", param1, param2); InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = getStream(); // 在后台获取文件流 response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("upload.jpg", "UTF-8")); response.setContentType("application/octet-stream"); // 用于下载的二进制流类型 outputStream = response.getOutputStream(); // 写入输出流 byte[] buffer = new byte[1024]; int len; while((len = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } outputStream.flush(); // outputStream.close(); 这里不可以关,会产生Broken pip异常,一旦关闭,其他人将无法读取 } catch (Exception e) { logger.error("failed to get pictures, the reason is ", e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { } } if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { } } } } // 获取文件流,这里只是举了个例子,也可以是从别的地方获取的文件流 private InputStream getStream() throws FileNotFoundException { String fileName = "D:/test.PNG"; FileInputStream inputStream = new FileInputStream(new File(fileName)); return inputStream; }
4.遇到的坑
①response的contentType
一开始查到的样例,使用的是 image/png,发现可以从浏览器读取到图片,但是无法下载,后来百度发现这种格式主要用于html元素展示;后改为application/octet-stream(二进制流格式),可以下载。
具体的contentType,这一篇讲的想对详细,可查看:https://blog.youkuaiyun.com/qq_37651267/article/details/91380351
②可以下载后,因为对流的处理不是很熟悉,导致出现两类错误,虽然其中一类并不是代码原因导致
1)IOException:Broken pip,这个问题是因为我在outputStream写完后就关了,导致没有办法访问到,虽然我仍然有疑惑的点是,1> 放在finally,还是有可能关掉,但是目前代码执行上看来,这样写并没有问题,2> 我也看到工具类中是可以选择不关闭流的,由使用者关闭,但是若使用者未及时关闭,不会导致连接过多,后面的无法连接么?
2)IOException:Connection reset by peer,这个问题简单来说是客户端主动关闭了连接,我这边出现的问题是,因为我这边需要经过网关,但网关对应存储的磁盘快满了,导致大一点的文件写入都会报错,但小一点的文件就不会有问题,这一点也提醒我们需要关注网关本身对传输文件大小的限制以及网关对应存储硬件对传输文件大小的限制。
③如果客户端可以通过一个专门的文件接口获取资源,比如OSS提供的接口,最好不要将这类接口与自身服务接口混淆一起,减少网关的压力。