需求背景
我们在美国服务器上部署了一个site,专门提供美国用户使用,后端服务和文件服务都放在国内。用户经常抱怨我们系统打开文件比较缓慢深圳打不开。我们经过测试发现,一般的service查询在速度上都还是可以接受的,但是一些较大的文件,就会响应比较慢甚至出现打开失败的情况。这是由于跨洲网络出现丢包的现象导致的。
我们最初想到的方案是是开通VPN,通过专线来提高访问速度。但是经过调研发现,VPN的收费太高了,我们小本经营根本承受不起。无奈之下,我们选择通过程序将部分需要用到文件先同步到美国服务器,用户访问时通过nginx直接读取当地的文件。
核心代码
首先我们定义一个service用来接收推送过来的数据
因为我们需要将文件的保存路径与国内服务器一致,这样前端才好处理,所以我们使用form表单+附件流的方式。
@RequestMapping(value = "/attachment",method = RequestMethod.POST)
public ResponseTemplate saveFile(AttachmentFormDto dto){
ResponseTemplate template=new ResponseTemplate();
try{
attachmentService.saveFile(dto);
template.setCode(SUCCESS);
}catch (Exception e){
log.error(e.getMessage(),e);
template.setCode(FAILED);
template.setMsg(e.getMessage());
}
return template;
}
@Data
public class AttachmentFormDto {
/**
* 文件保存路径
*/
private String filePath;
/**
* 文件显示名称
*/
private String showName;
/**
* 文件流
*/
private MultipartFile blFile;
}
保存文件这一块代码比较简单,我们只需要将文件按照国内的路径保存即可
@Override
public boolean saveFile(AttachmentFormDto dto) throws IOException {
String filePath=uploadPath+dto.getFilePath();
log.info("upload file path:{}",filePath);
File file=new File(filePath);
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
MultipartFile mpf=dto.getBlFile();
if(!mpf.isEmpty()){
mpf.transferTo(file);
}
log.info("文件保存路径:{}",filePath);
return true;
}
接下就是客户端的代码,我们需要通过post请求将文件数据推送到远程服务器。
//开始调用方法远程传送文件的到服务器
HttpResponse response=null;
CloseableHttpClient httpclient = HttpClients.custom().disableAutomaticRetries().build();
try{
String filePath=(uploadDir+"/"+x.getRealPath());
File file=new File(filePath);
String url=abroadHost+"/upload/attachment";
Logs.info("url>"+url);
InputStream in = new FileInputStream(file);
HttpPost httpPost = new HttpPost(url);
/**设置 contenttype 以form形式上传文件, 强制使用UTF-8编码**/
ContentType type=ContentType.MULTIPART_FORM_DATA.withCharset("UTF-8");
HttpEntity httpEntity = MultipartEntityBuilder.create()
.addPart("filePath", new StringBody(x.getRealPath(),type))
.addPart("showName",new StringBody(x.getShowName(),type))
.addPart("blFile",new FileBody(file)).build();
httpPost.setEntity(httpEntity);
RequestConfig requestConfig= RequestConfig.custom()
.setSocketTimeout(600000)
.setConnectTimeout(600000)
.build();
httpPost.setConfig(requestConfig);
response = httpclient.execute(httpPost);
int statusCode=response.getStatusLine().getStatusCode();
Logs.info("statusCode: {}",statusCode);
if(statusCode==200){
//更新到数据库,标志文件已经被推送
updateAtt(x);
}
String rsStr = EntityUtils.toString(response.getEntity());
Logs.info("response content is :=======================\n "+rsStr);
}catch (Exception e){
Logs.error(e.getMessage(),e);
}
在这里有一个地方需要注意,为了防止我们推送后的文件有重新修改,所以我们需要对文件信息进行md5,通过md5来判断文件是有已经被推送和被修改过。
美国的site也会根据这个字段来判断是否是读取本地服务器的文件还是读取国内的文件。