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(常 ...
随机推荐
- gevent程序员指南
gevent程序员指南 由Gevent社区编写 gevent是一个基于libev的并发库.它为各种并发和网络相关的任务提供了整洁的API. 介绍 本指南假定读者有中级Python水平,但不要求有其 ...
- 从 <sofa:XXX> 标签开始看 SOFA-Boot 如何融入 Spring
前言 SOFA-Boot 现阶段支持 XML 的方式在 Spring 中定义 Bean,通过这些标签,我们就能从 Spring 容器中取出 RPC 中的引用,并进行调用,那么他是如何处理这些自定义标签 ...
- tensorflow1.0.0 弃用了几个operator写法
除法和取模运算符(/, //, %)现已匹配 Python(flooring)语义.这也适用于 tf.div 和 tf.mod.为了获取强制的基于整数截断的行为,你可以使用 tf.truncatedi ...
- Python函数化编程整理
1.映射函数 items=[1,2,3,4,5] def inc(x): return x+1 list(map(inc,items)) [2, 3, 4, 5, 6] >>> a ...
- 航遇项目react踩坑
1.iconfont应用: a.正常用法如下 <span className='iconfont' > iconfont的代码,例如: </span> b.react不能动态 ...
- python!!!!惊了,这世上居然还有这么神奇的东西存在
第一次接触到python的时候实在看学习3Blue1Brown的视频线性代数的本质的时候.惊奇的是里面的视频操作,例如向量的变化,线性变换等都是由python用代码打出来的.那时的我只是以为pytho ...
- 构建具有用户身份认证的 Ionic 应用
序言:本文主要介绍了使用 Ionic 和 Cordova 开发混合应用时如何添加用户身份认证.教程简易,对于 Ionic 入门学习有一定帮助.因为文章是去年发表,所以教程内关于 Okta 的一些使用步 ...
- Python_sniffer(网络嗅探器)
import socket import threading import time activeDegree=dict() flag=1 def main(): global activeDegre ...
- 安装SQL Server DQS 和 MDS
tep1: 安装特性时选择Data Quality Services 和 Master Data Services Step2: 安装完成之后, 打开 SQL Server 2017 Data ...
- MySQL 各类日志文件介绍
日志文件 1.错误日志 ErrorLog 错误日志记录了MyQLServer运行过程中所有较为严重的警告和错误信息,以及MySQLServer每次启动和关闭的详细信息. 在默认情况下,系统记录错误日志 ...