RPC基于http协议通过netty支持文件上传下载
本人在中间件研发组(主要开发RPC),近期遇到一个需求:RPC基于http协议通过netty支持文件上传下载
经过一系列的资料查找学习,终于实现了该功能
通过netty实现文件上传下载,主要在编解码时处理,具体的代码如下:
①文件上传
@Override
public RPCRequest doDecodeRequest(FullHttpRequest request) {
RPCRequest rpcRequest = new RPCRequest();
String biz_prefix = BIZ_PREFIX;
String rpc_prefix = RPC_PREFIX;
if("true".equals(request.headers().get(RPCParamType.header_compatible.getName()))){
biz_prefix = "";
rpc_prefix = "";
}
for (Entry<String, String> entry : request.headers().entries()) {
if(entry.getKey().startsWith(rpc_prefix)){
rpcRequest.addRpcHeader(entry.getKey().substring(rpc_prefix.length()), entry.getValue());
}
if(entry.getKey().startsWith(biz_prefix)){
rpcRequest.addBizHeader(entry.getKey().substring(biz_prefix.length()), entry.getValue());
}
}
QueryStringDecoder decoderQuery = new QueryStringDecoder(request.uri());
// serviceId
String serviceId = decoderQuery.path();
if (serviceId.startsWith(RPCConstant.PATH_SEPARATOR)) {
serviceId = serviceId.substring(1);
}
if (serviceId.endsWith(RPCConstant.PATH_SEPARATOR)) {
serviceId = serviceId.substring(0, serviceId.length() - 1);
}
rpcRequest.addRpcHeader(RPCParamType.service_id.getName(), serviceId); // requestId
String requestId = request.headers().get(rpc_prefix + RPCConstant.RequestId);
if (null == requestId || "".equals(requestId)) {
requestId = "0";
}
rpcRequest.setId(Long.valueOf(requestId));
// add by wangzp in 2017/3/30
if (HttpMethod.GET == request.method()) {
rpcRequest.addBizHeader("HTTP_METHOD", "GET");
Map<String, String> map = new HashMap<String, String>();
for (Map.Entry<String, List<String>> paramsEntry : decoderQuery.parameters().entrySet()) {
map.put(paramsEntry.getKey(), paramsEntry.getValue().get(0));
rpcRequest.getBizHeader().put(paramsEntry.getKey(), paramsEntry.getValue().get(0));
}
//TODO 需要引入序列化机制,否则data部分找不到相匹配的序列化
//TODO 暂时用json
rpcRequest.setData(JSON.toJSONString(map));
} else {
try {
decoder = new HttpPostRequestDecoder(factory, request);
readingChunks = HttpUtil.isTransferEncodingChunked(request);
if(decoder != null && readingChunks){
HttpContent chunk = (HttpContent) request;
try{
decoder.offer(chunk);
} catch (ErrorDataDecoderException e) {
decoder.destroy();
}
}
File file = readHttpDataChunkByChunk(); //从解码器decoder中读出数据
rpcRequest.addBizHeader(RPCParamType.upload_file.getName(), file.getPath());
} catch (Exception e) {
decoder.destroy();
}
}
return rpcRequest;
}
②文件下载
@Override
public FullHttpResponse doEncodeResponse(RPCResponse response) {
FullHttpResponse httpResponse ;
String biz_prefix = BIZ_PREFIX;
String rpc_prefix = RPC_PREFIX;
if(response.getBizHeader(RPCParamType.header_compatible.getName()) == null ? RPCParamType.header_compatible.getBooleanValue()
: Boolean.parseBoolean(response.getBizHeader(RPCParamType.header_compatible.getName()))){
biz_prefix = "";
rpc_prefix = "";
}
String downloadFile = response.getBizHeader(RPCParamType.download_file.getName());
if(!StringUtils.isEmpty(downloadFile)){
File file = new File(downloadFile);
String fileName = file.getName();
ByteBuf buffer;
try {
buffer = Unpooled.copiedBuffer(Files.readAllBytes(file.toPath()));
httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK,buffer);
} catch (IOException e) {
throw new RuntimeException(fileName + "is not exist");
}
httpResponse.headers().add(HttpHeaderNames.CONTENT_TYPE, "application/octet-stream; charset=utf-8");
try {
httpResponse.headers().add(HttpHeaderNames.CONTENT_DISPOSITION, "attachment; filename=\"" + new String(fileName.getBytes("gb2312"),"ISO-8859-1") + "\"");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(fileName + "download fail");
}
}else{
//serialize
byte[] body = (byte[]) SerializerUtils.serialize(getProtocolUrl().getParameter(RPCParamType.serializer_name.getName(), RPCParamType.serializer_name.getValue()), response.getData()); String reasonPhrase = response.getBizHeader(RPCParamType.http_reasonPhrase.getName());
response.getBizHeader().remove(RPCParamType.http_reasonPhrase.getName()); //reasonPhrase不需要放入RPCResponse中传输
httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
new HttpResponseStatus(Integer.valueOf(response.getBizHeader(RPCConstant.Code) == null ? response.getRpcHeader(RPCConstant.Code) : response.getBizHeader(RPCConstant.Code)),
reasonPhrase == null ? RPCParamType.http_reasonPhrase.getValue() : reasonPhrase),
Unpooled.wrappedBuffer(body));
}
for (Entry<String, String> entry : response.getBizHeader().entrySet()) {
httpResponse.headers().add(biz_prefix + entry.getKey(), entry.getValue());
}
for (Entry<String, String> entry : response.getRpcHeader().entrySet()) {
httpResponse.headers().add(rpc_prefix + entry.getKey(), entry.getValue());
}
httpResponse.headers().add(rpc_prefix + RPCConstant.RequestId, response.getRequestId());
httpResponse.headers().add(CLZNAME, response.getClzName());
httpResponse.headers().add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
httpResponse.headers().add(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content().readableBytes());
return httpResponse;
}
③其他辅助方法
public class HTTPExCodec extends HTTPCodec { private boolean readingChunks;
private static final HttpDataFactory factory =
new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE) ; private HttpPostRequestDecoder decoder; //此处包含上面两个方法
。。。。
private File readHttpDataChunkByChunk() {
try {
while (decoder.hasNext()) {
InterfaceHttpData data = decoder.next();
if (data != null) {
try {
File file = writeHttpData(data);
return file;
} finally {
data.release();
}
}
}
} catch (EndOfDataDecoderException e1) {
throw new RuntimeException("write file error");
}
return null;
} private File writeHttpData(InterfaceHttpData data) {
String uploadFileName = getUploadFileName(data);
FileUpload fileUpload = (FileUpload) data;
if (fileUpload.isCompleted()) {
File dir = new File(System.getProperty("user.dir") + File.separator);
if (!dir.exists()) {
dir.mkdir();
}
File dest = new File(dir, uploadFileName);
try {
fileUpload.renameTo(dest);
return dest;
} catch (IOException e) {
throw new RuntimeException("write file error");
}
}
return null;
} private String getUploadFileName(InterfaceHttpData data) {
String content = data.toString();
String temp = content.substring(0, content.indexOf("\n"));
content = temp.substring(temp.lastIndexOf("=") + 2, temp.lastIndexOf("\""));
return content;
}
}
RPC基于http协议通过netty支持文件上传下载的更多相关文章
- 基于Spring Mvc实现的Excel文件上传下载
最近工作遇到一个需求,需要下载excel模板,编辑后上传解析存储到数据库.因此为了更好的理解公司框架,我就自己先用spring mvc实现了一个样例. 基础框架 之前曾经介绍过一个最简单的spring ...
- 基于tcp协议的登录,文件上传和下载
[1]先登录,登录不成功循环登录,直到成功.登录成功后可以选择上传或者下载,上传有对应的文件,可选择上传哪个:下载有对应的文件,可选择下载哪个 [2]登录,上传,下载时最好设置状态码,客户端和 ...
- Python实现简单的HTTP服务器(支持文件上传下载)
1.python内置模块 SimpleHTTPServer (支持下载功能) 在对应的工作目录下,运行命令python -m SimpleHTTPServer 即可把当前目录下以共享服务的形式共享出 ...
- 转:【专题十一】实现一个基于FTP协议的程序——文件上传下载器
引言: 在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信 ...
- 专题十一:实现一个基于FTP协议的程序——文件上传下载器
引言: 在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信 ...
- java nio 写一个完整的http服务器 支持文件上传 chunk传输 gzip 压缩 使用过程 和servlet差不多
java nio 写一个完整的http服务器 支持文件上传 chunk传输 gzip 压缩 也仿照着 netty处理了NIO的空轮询BUG 本项目并不复杂 代码不多 ...
- Python 基于Python实现Ftp文件上传,下载
基于Python实现Ftp文件上传,下载 by:授客 QQ:1033553122 测试环境: Ftp客户端:Windows平台 Ftp服务器:Linux平台 Python版本:Python 2.7 ...
- 艺萌文件上传下载及自动更新系统(基于networkComms开源TCP通信框架)
1.艺萌文件上传下载及自动更新系统,基于Winform技术,采用CS架构,开发工具为vs2010,.net2.0版本(可以很容易升级为3.5和4.0版本)开发语言c#. 本系统主要帮助客户学习基于TC ...
- 【FTP】FTP文件上传下载-支持断点续传
Jar包:apache的commons-net包: 支持断点续传 支持进度监控(有时出不来,搞不清原因) 相关知识点 编码格式: UTF-8等; 文件类型: 包括[BINARY_FILE_TYPE(常 ...
随机推荐
- git merge 与 rebase
git merge git rebase merge V.S. rebase 参考材料 写在开始: 对merge和rebase的用法总有疑惑,好像两个都能完成"获取别的branch的comm ...
- Android的颜色值转换
Android的颜色int值比较变态,是个负值,用计算机术语讲叫补码,手工转换比较麻烦,首先看看文档 https://developer.android.com/reference/android/g ...
- Django升级1.8的一些问题
1.最明显的问题当然是Settings设置中关于模板的设置数据结构发生变化,这个就不细说了,你开个Django的1.8的新项目就知道怎么改了 2.migrations问题,这个问题是1.8最主要的修改 ...
- GitHub学习笔记:本地操作
安装过程略,假设你已经注册好了Github, 已经有了一个准备好的程序.我们的一切工作都是基于Git Shell,与GUI客户端无关. 在使用前你先要配置好config中的几个内容,主要是你自己的个人 ...
- 《T-SQL查询》读书笔记Part 2.执行计划
一.关于执行计划 执行计划是优化器生成的用于确定如何处理一个给定查询的“工作计划”.一个计划包含一组运算符,通常按照特定的顺序来应用这些运算符.此外,一些运算符可以在它们之前的运算符还在处理时被应用( ...
- Node.js 专题
前提电脑中已经安装过NodeJS, npm.现在需要进行升级操作.1.查看当前的npm和NodeJs的版本: C:\Users\Administrator>node -v v4.4.3 C:\U ...
- Oracle12c中功能及性能新特点之with子句的增强
1. 设置创建测试表.DROP TABLE test PURGE; CREATE TABLE test ASSELECT 1 AS idFROM dualCONNECT BY level < ...
- Nagios安装、配置、问题记录
http://youyizhimen.blog.163.com/blog/static/170917267201201745523276/ 本文描述了我在使用Nagios的过程中遇到的一些问题.解决办 ...
- Linux 上一些常用命令
切换权限: sudo chown -R 权限名: 文件 tar -zcvf 文件夹.tar 文件夹--exclude=要过滤的文件夹路径 重启crontab :service crond restar ...
- css3 绘制图形
星形: .star-six { width:; height:; border-left: 50px solid transparent; border-right: 50px solid trans ...