共计 3907 个字符,预计需要花费 10 分钟才能阅读完成。
这是转载的文章,之所以转载,是因为原作者漏了一个 hutool 的 import,导致我浪费了 5 个小时,而原作者的文章不能评论,特此转载 + 说明。
就是这行代码坑了我 5 个小时:
import cn.hutool.core.io.resource.InputStreamResource;
最近很多朋友在 go-fastdfs 的微信群里面问道,go-fastdfs 什么时候支持流上传?其实一直都支持的!为什么这样子说呢?因为 go-fastdfs 本身就是基于 http 协议进行传输的,那么如果有读者对 Java 的 HttpURLConnection 的源码研究过的话,会发现其内部也是可以通过 conn.getInputStream()和 conn.getOutputStream()获取其输入输出流,通常可以直接往 outputStream 里面写入符合 http 协议的数据。那么根据这个特点,在 Java 里面,直接通过流的形式 (通常是从 MultipartFile 里面获取 InputStream) 再上传到 go-fastdfs 是没问题的。跟 http 协议相关的知识点包括 http 协议报文格式和上传二进制数据等如果不了解可以先自行百度一下。这里不会细讲的哦。
引发认为 go-fastdfs 不能直接流上传的原因
经过本人的分析认为,让广大读者认为不能直接使用流上传的原因应该是 go-fastdfs 的 github 的代码示例造成一些误会。不过官方的代码示例并没有错误,只是直接从本地读取文件系统的文件,形成 File 对象进行上传。针对使用 Spring 等框架接收前端上传过来的文件再进行转发上传到 go-fastdfs 的用户,就可能会有疑惑。因为获取到的是 MultipartFile,而非 java.io.File。
Hutool-http、HttpClient、OkHttp3 多种方式流式文件上传
由于有不少人问到上面的问题,现在本人总结了一个常用的几种 http 客户端文件流式上传的方式,相当于给自己做下记录,同时也给有这方面疑问的朋友一个借鉴。废话不多说,直接上代码吧。代码是基于 springboot 的 maven 工程。
Hutool-http 方式
先在 pom 中添加 hutool 的依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.5.1</version>
</dependency>
接着在 Controller 中代码示例
import cn.hutool.core.io.resource.InputStreamResource;
@RequestMapping("/upload")
public String upload(MultipartFile file) {
String result = "";
try {InputStreamResource isr = new InputStreamResource(file.getInputStream(),
file.getOriginalFilename());
Map<String, Object> params = new HashMap<>();
params.put("file", isr);
params.put("path", "86501729");
params.put("output", "json");
String resp = HttpUtil.post(UPLOAD_PATH, params);
Console.log("resp: {}", resp);
result = resp;
} catch (IOException e) {e.printStackTrace();
}
return result;
}
HttpClient 方式
pom 依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
</dependency>
接着在 Controller 中代码示例
@RequestMapping("/upload1")
public String upload1(MultipartFile file) {
String result = "";
try {CloseableHttpClient httpClient = HttpClientBuilder.create().build();
CloseableHttpResponse httpResponse = null;
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(200000)
.setSocketTimeout(2000000)
.build();
HttpPost httpPost = new HttpPost(UPLOAD_PATH);
httpPost.setConfig(requestConfig);
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.setCharset(Charset.forName("UTF-8"))
.addTextBody("output", "json")
.addBinaryBody("file", file.getInputStream(),
ContentType.DEFAULT_BINARY, file.getOriginalFilename());
httpPost.setEntity(multipartEntityBuilder.build());
httpResponse = httpClient.execute(httpPost);
if (httpResponse.getStatusLine().getStatusCode() == 200) {String respStr = EntityUtils.toString(httpResponse.getEntity());
System.out.println(respStr);
result = respStr;
}
httpClient.close();
httpResponse.close();} catch (Exception e) {e.printStackTrace();
}
return result;
}
OkHttp3 上传示例
pom 文件依赖
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.9.1</version>
</dependency>
接着在 Controller 中代码示例
@RequestMapping("/upload2")
public String upload2(MultipartFile file) {
String result = "";
try {OkHttpClient httpClient = new OkHttpClient();
MultipartBody multipartBody = new MultipartBody.Builder().
setType(MultipartBody.FORM)
.addFormDataPart("file", file.getOriginalFilename(),
RequestBody.create(MediaType.parse("multipart/form-data;charset=utf-8"),
file.getBytes()))
.addFormDataPart("output", "json")
.build();
Request request = new Request.Builder()
.url(UPLOAD_PATH)
.post(multipartBody)
.build();
Response response = httpClient.newCall(request).execute();
if (response.isSuccessful()) {ResponseBody body = response.body();
if (body != null) {result = body.string();
System.out.println(result);
}
}
} catch (Exception e) {e.printStackTrace();
}
return result;
}
总结
上面给出了几个示例,是不是都挺简单的?通过这种方式,就可以在 Controller 中做中转了,还是挺方便的。顺便提一下,上面几种方式中,我个人觉得 Hutool 的是最简单的,最方便的,对于 HttpClient 而言,概念比较多,显得相对复杂,OkHttp 也一样,不过比 HttpClient 显得优雅点。针对一般的并发量,个人觉得 hutool 的 Http 已经够用了,底层是基于 jdk 的 HttpUrlConnection 实现的。如果对性能有特殊要求的,可以考虑 httpclient 或者 OKHttp,后两者相对而言,更推荐使用 OkHttp。