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(常 ...
随机推荐
- 对ManualResetEvent和AutoResetEvent的巩固练习
在多线程编程中,最常用到的就是线程同步问题,前段时间开发地址采集服务器,需要携带经纬度到MapAbc中采集后,返回地址,才可以进行下一条经纬度的采集,因为队列处理和解析不是同一个线程,并且是解析经纬度 ...
- git如何移除某文件夹的版本控制
目录结构如下 project bin lib src ...... 执行如下的操作 git add . git commit -m "add bin/ lib/ src/" git ...
- Oracle 11g一步步安装详解
本文所需的安装包都存放在我网盘中,需要的私聊~ 一.安装VMware tools工具(非必须) 1.虚拟机上点击安装 因为我在虚拟机中做的,后面oracle 安装是图形化安装,需要屏幕大一点,不然有些 ...
- flex 生成多边形时内、外环计算
//顺时钟 var pA:Array = [{x:"2969925.6674000006",y:"476254.4874999998"},{x:"29 ...
- ORA-01658: 无法为表空间 YJXT 中的段创建 INITIAL 区
oracle 用imp导入数据的时候报错:遇到ORACLE 错误1658: 无法为表空间 MAXDATA 中的段创建 INITIAL 区 解决办法:需要添加数据文件而不是新增表空间,代码如下: alt ...
- Linux之SSH密钥认证
1.SSH协议的认识 SSH 为 Secure Shell 的缩写,由 IETF 的网络小组(Network Working Group)所制定:SSH 为建立在应用层基础上的安全协议.SSH 是目前 ...
- JSTL varStatus属性
JSTL核心标签库中c:forEach 的 varStatus属性 varStatus属性 类型:String 描述:循环的状态信息,可以取值index\count\first\last\cur ...
- 敏捷(Agile)——“说三道四”
可以这么理解:一种以人为本.团队合作.快速响应变化和可工作的软件作为宗旨的开发方法.亦可理解为在一个高度协作的环境中,不断地使用反馈进行自我调整和完善,持续交付用户想要的软件的过程.敏捷开发提倡通过多 ...
- 网络Socket编程及实例
1 TCP和UDP介绍 在介绍TCP和UDP之前,有必要先介绍下网络体系结构的各个层次. 1.1 网络体系结构 协议:控制网络中信息的发送和接收.定义了通信实体之间交换报文的格式和次序,以及在报文传 ...
- Javassist字节码增强示例
概述 Javassist是一款字节码编辑工具,可以直接编辑和生成Java生成的字节码,以达到对.class文件进行动态修改的效果.熟练使用这套工具,可以让Java编程更接近与动态语言编程. 下面一个方 ...