前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >facebook/swift:构建thrift http server(1)

facebook/swift:构建thrift http server(1)

作者头像
10km
发布2019-05-25 20:37:02
1.1K0
发布2019-05-25 20:37:02
举报
文章被收录于专栏:10km的专栏10km的专栏

版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433449

如何基于facebook/swift构建一个支持HTTP访问的thrift服务?说来话长。我将用分几篇博客介绍这个问题的解决思路和具体实现。

背景说明

我有一个项目facelog,是基于facebook/swift框架(java)开发的。在实际的项目应用时,需要从浏览器端能调用facelog的接口方法,要实现这个功能,一个笨办法就是专门写一个java web应用,相当于一个二传手,对浏览器需要访问的facelog方法,提供GET/POST调用接口供浏览器调用,现在我们就是这么干的,这么做无疑增加了开发工作量,能不能让浏览器直接调用facelog服务的接口方法呢?

如果能这样实现将好处多多:

不需要java web应用设计作为转发用途的POST/GET接口,减少了开发工作量同时也减少了系统的响应延迟及复杂度。

Node.js方案

facebook/swift是基于thrift的java平台的RPC框架。thrift是一种支持广泛开发语言的RPC框架,自然也是支持javascript访问的。

thrift的官方网站的《Javascript Tutorial》详细介绍了如何用在浏览器上用javascript访问thrift服务。参照这个教程可以就可以构建一个node.js服务,浏览器则通过javascript访问node.js提供的thrift接口,在这个tutor中,前端使用javascript,服务端则是用Node.js实现的。

所以参照上面的教程在浏览器上用javascript访问facelog服务是完全可以实现的。然而仔细评估之后,觉得《Javascript Tutorial》提供的这个方案对于我的facelog项目并不是最佳解决方案,原因嘛,总得来说就是更麻烦,如下:

  1. 开发工作量更大 《Javascript Tutorial》方案中,后端是一个node.js服务。而facelog是一个java平台的服务。如果采用这个方案,我需要重写一个node.js服务作为代理服务转所有的HTTP请求到facelog(java)。对于拥有100多个接口方法的facelog服务,再重写一个一样的node.js转发服务也是不小的工作量,这同样增加了项目的复杂度和系统响应延迟,后续维护的工作量也相应增加。
  2. 部署运维更复杂 facelog(java)的部署很简单,系统依赖很简单,只需要java虚拟机就可以在命令行直接运行,如果增加一个node.js服务,就需要多一个node的运行平台。对于项目部署和运维都增加了难度和工作量。

所以对于我来说,理想的方案就是运行一个支持XHR(XML Http Request)访问的facelog(java)服务,它占用一个新的端口号,web端通过javascript用浏览器的XMLHttpRequest对象直接调用这个XHR服务。这样对于facelog来说只是增加一个新的端口号而已,新的XHR服务还是在java平台运行。没有中间商赚差价,web端的系统响应迟延与java client是一样的。

TServlet方案

那么thrift的java框架有没有提供HTTP访问能力呢?答案是有的。

请关注org.apache.thrift.server.TServlet这个类。

下面是TServlet的部分代码

代码语言:javascript
复制
public class TServlet extends HttpServlet {
	private final TProcessor processor;
	private final TProtocolFactory inProtocolFactory;
	private final TProtocolFactory outProtocolFactory;
	private final Collection<Map.Entry<String, String>> customHeaders;

	public TServlet(TProcessor processor, TProtocolFactory inProtocolFactory, TProtocolFactory outProtocolFactory) {
		this.processor = processor;
		this.inProtocolFactory = inProtocolFactory;
		this.outProtocolFactory = outProtocolFactory;
		this.customHeaders = new ArrayList<Map.Entry<String, String>>();
	}

	public TServlet(TProcessor processor, TProtocolFactory protocolFactory) {
		this(processor, protocolFactory, protocolFactory);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		TIOStreamTransport inTransport = null;
		TIOStreamTransport outTransport = null;
		try {
			TIOStreamTransport transport;
			response.setContentType("application/x-thrift");
			if (null != this.customHeaders) {
				for (Map.Entry<String, String> header : this.customHeaders) {
					response.addHeader(header.getKey(), header.getValue());
				}
			}
			ServletInputStream in = request.getInputStream();
			ServletOutputStream out = response.getOutputStream();
			inTransport = transport = new TIOStreamTransport((InputStream) in, (OutputStream) out);
			outTransport = transport;
			TProtocol inProtocol = this.inProtocolFactory.getProtocol((TTransport) inTransport);
			TProtocol outProtocol = this.outProtocolFactory.getProtocol((TTransport) outTransport);
			this.processor.process(inProtocol, outProtocol);
			out.flush();
		} catch (TException te) {
			throw new ServletException((Throwable) te);
		}
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doPost(request, response);
	}
}

如果你熟悉thrift,在TServlet类的代码中看到TProcessorTProtocol类就明白,这个类继承自javax.servlet.http.HttpServlet,可以将一个thrift接口服务(TProcessor)封装为一个Servlet。有了Servlet,就可以在所有支持Servlet的web容器(比如tomcat)上运行thrift服务了.

当初看到这个类,我好一阵兴奋,庆幸自己这么容易就找到了答案。但深入了解之后,得出一个令人沮丧的结论,TServlet方案也不是适合我的方案。

  1. TProcessorThriftServiceProcessor 对,org.apache.thrift.TProcessorcom.facebook.swift.service.ThriftServiceProcessor,前一个是thrift(java)定义的接口,后者则是facebook/swift定义的接口,我的facelog项目基于facebook/swift设计,服务接口封装为ThriftServiceProcessor实例,并不能直接作为参数被TServlet封装为Servlet
  2. 额外的Servlet容器 就算想办法将ThriftServiceProcessor封装为TProcessor丢进TServlet封装为Servlet,也需要tomcat这样的Servlet容器才能运行。原本facelog只需要一个standalone的jar包就能在JVM上运行,项目部署极简单,现在凭空多了个tomcat,配置运行tomcat对于项目部署运维就增加了很多的工作量,所以tomcat对于我来说太重了。 那么jetty呢?Jetty 是一个开源的servlet容器,可以将Jetty容器实例化成一个对象,可以迅速为一些独立运行(stand-alone)的Java应用提供网络和web连接。但同样要增加一些依赖包不是么?我对jetty并不熟悉,为了解决问题学习jetty的成本也要考虑进去。风险也不小。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年05月04日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景说明
    • Node.js方案
      • TServlet方案
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档