本人在中间件研发组(主要开发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支持文件上传下载的更多相关文章

  1. 基于Spring Mvc实现的Excel文件上传下载

    最近工作遇到一个需求,需要下载excel模板,编辑后上传解析存储到数据库.因此为了更好的理解公司框架,我就自己先用spring mvc实现了一个样例. 基础框架 之前曾经介绍过一个最简单的spring ...

  2. 基于tcp协议的登录,文件上传和下载

    ​ [1]先登录,登录不成功循环登录,直到成功.登录成功后可以选择上传或者下载,上传有对应的文件,可选择上传哪个:下载有对应的文件,可选择下载哪个 ​ [2]登录,上传,下载时最好设置状态码,客户端和 ...

  3. Python实现简单的HTTP服务器(支持文件上传下载)

    1.python内置模块 SimpleHTTPServer  (支持下载功能) 在对应的工作目录下,运行命令python -m SimpleHTTPServer 即可把当前目录下以共享服务的形式共享出 ...

  4. 转:【专题十一】实现一个基于FTP协议的程序——文件上传下载器

    引言: 在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信 ...

  5. 专题十一:实现一个基于FTP协议的程序——文件上传下载器

    引言: 在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信 ...

  6. java nio 写一个完整的http服务器 支持文件上传 chunk传输 gzip 压缩 使用过程 和servlet差不多

    java nio 写一个完整的http服务器  支持文件上传   chunk传输    gzip 压缩      也仿照着 netty处理了NIO的空轮询BUG        本项目并不复杂 代码不多 ...

  7. Python 基于Python实现Ftp文件上传,下载

    基于Python实现Ftp文件上传,下载   by:授客 QQ:1033553122 测试环境: Ftp客户端:Windows平台 Ftp服务器:Linux平台 Python版本:Python 2.7 ...

  8. 艺萌文件上传下载及自动更新系统(基于networkComms开源TCP通信框架)

    1.艺萌文件上传下载及自动更新系统,基于Winform技术,采用CS架构,开发工具为vs2010,.net2.0版本(可以很容易升级为3.5和4.0版本)开发语言c#. 本系统主要帮助客户学习基于TC ...

  9. 【FTP】FTP文件上传下载-支持断点续传

    Jar包:apache的commons-net包: 支持断点续传 支持进度监控(有时出不来,搞不清原因) 相关知识点 编码格式: UTF-8等; 文件类型: 包括[BINARY_FILE_TYPE(常 ...

随机推荐

  1. SpringBoot使用Maven插件打包部署

    [问题] 之前一直用SpringBoot做一些小项目,想打包部署在环境上,总是少依赖包jar.百度下可以通过Spring Boot Maven plugin插件,把Maven配置的依赖包都打到项目包里 ...

  2. 163邮箱 SMTP发送邮件注意点

    在之前163邮箱注册的时候默认开通SMTP服务的,之后需要自己手动开始. 在配置的时候服务器的地址固定 用户名称就是你的邮箱 密码需要注意的是有的是你邮箱的密码,如果不对需要填写你的授权码!

  3. C游新官网总结

    从2017年9月18号,我开始独立做C游新官网项目.第一次独立完成项目,压力还是挺大的,毕竟还要自己去写前端,前端我已经忘了差不多了. 做这个网站主要是公司开始转型,开始自己建立渠道倒量,这样网站的S ...

  4. ASP.NET MVC中的路由IRouteConstraint方法应用实例

    在如下代码的写法中: public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { ro ...

  5. cxf webservice生成客户端代码及调用服务端遇到的问题

    1.  从网上下载cxf开发的工具 apache-cxf-3.1.4.zip, 解压文件,找到apache-cxf-3.1.4\bin目录,里面包含一个wsdl2java文件 2. 设置环境变量 1. ...

  6. 架构之微服务设计(Nginx + Upsync)

    Upsync,微博开源基于Nginx容器动态流量管理方案 . Nginx 以其超高的性能与稳定性,在业界获得了广泛的使用,微博的七层就大量使用了 Nginx .结合 Nginx 的健康检查模块,以及动 ...

  7. springmvc 请求经过controller后静态资源无法访问的问题

    经过RequestMapping(“xx”)后 转发请求时会在url里面附带地址, 导致访问静态资源文件失败, 解决办法是在 spring-mvc.xml文件中加上 <mvc:default-s ...

  8. 树莓派配置watchdog

    安装watchdog apt install watchdog 编辑/etc/modules,添加bcm2708_wdog 编辑/etc/watchdog.conf watchdog-device = ...

  9. Vue路由学习心得

    GoodBoy and GoodGirl~进来了就看完点个赞再离开,写了这么多也不容易的~ 一.介绍  1.概念:路由其实就是指向的意思,当我们点击home按钮时,页面中就要显示home的内容,点击l ...

  10. 使用jekyll和Github搭建个人博客

    一.使用jekyll和Github三步搭建个人博客 在 Github 上建一个库,库的名字是xxx.github.com,其中的xxx是你的github的账号名(图中标注的不要勾选) 注:如果没有Gi ...