Netty:透明地使用SPDY和HTTP

大多数人已经从谷歌那里听说过SPDY,该协议被提议作为老化的HTTP协议的替代品。 Web服务器是浏览器正在缓慢地实现该协议,并且支持正在增长。 在最近的文章中,我已经写过SPDY的工作方式以及如何在Jetty中启用SPDY支持。 由于Netty(最初来自JBoss)几个月以来也支持SPDY 。由于Netty通常用于高性能协议服务器,因此SPDY是合乎逻辑的。 在本文中,我将向您展示如何创建一个基于Netty的基本服务器,该服务器在SPDY和HTTP之间进行协议协商。 它使用Netty snoop示例中的示例HTTPRequestHandler来消耗并产生一些HTTP内容。
为了使一切正常,我们需要做以下事情:
  • 在Java中启用NPN以确定要使用的协议。
  • 根据协商的协议,确定使用HTTP还是SPDY。
  • 确保使用HTTP发送回正确的SPDY标头。
SPDY使用TLS扩展来确定要在通信中使用的协议。 这称为NPN。 我写了一个更完整的说明,并显示了文章中有关如何在Jetty上使用SPDY的消息,因此,有关该文章的更多信息,请参见。 基本上,此扩展的作用是在TLS交换期间,服务器和客户端也会交换它们支持的传输级别协议。 对于SPDY,服务器可以同时支持SPDY协议和HTTP协议。 然后,客户端实现可以确定要使用的协议。
由于这不是标准Java实现中可用的功能,因此我们需要使用NPN扩展Java TLS功能。
在Java中启用NPN支持
到目前为止,我发现了两个可以用来在Java中添加NPN支持的选项。 其中一个来自https://github.com/benmmurphy/ssl_npn ,他的回购中也有一个基本的SPDY / Netty示例,他使用自己的实现。 我将要使用的另一个选项是Jetty提供的NPN支持。 Jetty提供了一个易于使用的API,可用于将NPN支持添加到Java SSL上下文中。 再次,在关于码头的文章中,您可以找到关于此的更多信息。 要为Netty设置NPN,我们需要执行以下操作:
  1. 将NPN lib添加到引导路径
  2. 将SSL上下文连接到NPN Api
将NPN库添加到boothpath
首先是第一件事。 从http://repo2.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/8.1.2.v2012下载NPN引导jar,并确保在运行服务器时像这样启动它:
java -Xbootclasspath/p:<path_to_npn_boot_jar>
通过这段代码,Java SSL支持NPN。 但是,我们仍然需要访问此协商的结果。 我们需要知道我们使用的是HTTP还是SPDY,因为这决定了我们如何处理接收到的数据。 为此,Jetty提供了一个API。 为此和所需的Netty库,我们将以下依赖项添加到pom中,因为我使用的是maven。
<dependency><groupId>io.netty</groupId><artifactId>netty</artifactId><version>3.4.1.Final</version></dependency><dependency><groupId>org.eclipse.jetty.npn</groupId><artifactId>npn-api</artifactId><version>8.1.2.v20120308</version></dependency>
将SSL上下文连接到NPN API
现在,我们已启用NPN并将正确的API添加到项目中,我们可以配置Netty SSL处理程序。 在Netty中配置处理程序是在PipelineFactory中完成的。 对于我们的服务器,我创建了以下PipelineFactory:
package smartjava.netty.spdy; 
import static org.jboss.netty.channel.Channels.pipeline;import java.io.FileInputStream;
import java.security.KeyStore;import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;import org.eclipse.jetty.npn.NextProtoNego;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.ssl.SslHandler;public class SPDYPipelineFactory implements ChannelPipelineFactory {private SSLContext context;public SPDYPipelineFactory() {try {KeyStore keystore = KeyStore.getInstance("JKS");keystore.load(new FileInputStream("src/main/resources/server.jks"),"secret".toCharArray());KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");kmf.init(keystore, "secret".toCharArray());context = SSLContext.getInstance("TLS");context.init(kmf.getKeyManagers(), null, null);} catch (Exception e) {e.printStackTrace();}}public ChannelPipeline getPipeline() throws Exception {// Create a default pipeline implementation.ChannelPipeline pipeline = pipeline();// Uncomment the following line if you want HTTPSSSLEngine engine = context.createSSLEngine();engine.setUseClientMode(false);NextProtoNego.put(engine, new SimpleServerProvider());NextProtoNego.debug = true;pipeline.addLast("ssl", new SslHandler(engine));pipeline.addLast("pipeLineSelector", new HttpOrSpdyHandler());return pipeline;}
}
在此类的构造函数中,我们设置了基本的SSL上下文。 我们使用的密钥库和密钥是我使用java keytool创建的,这是常规的SSL配置。 收到请求后,将调用getPipeline操作来确定如何处理该请求。 在这里,我们使用Jetty-NPN-API提供的NextProtoNego类将SSL连接连接到NPN实现。 在此操作中,我们传递一个提供程序,该提供程序用作服务器的回调和配置。 我们还将NextProtoNego.debug设置为true。 这会打印出一些调试信息,从而使调试更加容易。 SimpleServerProvider的代码非常简单:
public class SimpleServerProvider implements ServerProvider {private String selectedProtocol = null;public void unsupported() {//if unsupported, default to http/1.1selectedProtocol = "http/1.1";}public List<String> protocols() {return Arrays.asList("spdy/2","http/1.1");}public void protocolSelected(String protocol) {selectedProtocol = protocol;}public String getSelectedProtocol() { return selectedProtocol;}
}
此代码几乎是不言自明的。
  • 当客户端不支持NPN时,将调用不受支持的操作。 在这种情况下,我们默认为HTTP。
  • protocol()操作返回服务器支持的协议
  • 服务器和客户端协商协议后,将调用protocolSelected操作
getSelectedProtocol是一种用于从Netty管道中的其他处理程序获取所选协议的方法。
根据协商的协议确定使用HTTP还是SPDY
现在,我们需要配置Netty,使其为HTTPS请求和SPDY请求运行特定的管道。 为此,让我们回顾一下管道工厂的一小部分。
pipeline.addLast("ssl", new SslHandler(engine));
pipeline.addLast("pipeLineSelector", new HttpOrSpdyHandler());
该管道的第一部分是配置了NPN支持的SslHandler。 下一个将被调用的处理程序是HttpOrSpdyHandler。 该处理程序根据协议确定要使用的管道。 接下来列出此处理程序的代码:
public class HttpOrSpdyHandler implements  ChannelUpstreamHandler {public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e)throws Exception {// determine protocol typeSslHandler handler = ctx.getPipeline().get(SslHandler.class);SimpleServerProvider provider = (SimpleServerProvider) NextProtoNego.get(handler.getEngine());if ("spdy/2".equals(provider.getSelectedProtocol())) {ChannelPipeline pipeline = ctx.getPipeline();pipeline.addLast("decoder", new SpdyFrameDecoder());pipeline.addLast("spdy_encoder", new SpdyFrameEncoder());pipeline.addLast("spdy_session_handler", new SpdySessionHandler(true));pipeline.addLast("spdy_http_encoder", new SpdyHttpEncoder());// Max size of SPDY messages set to 1MBpipeline.addLast("spdy_http_decoder", new SpdyHttpDecoder(1024*1024)); pipeline.addLast("handler", new HttpRequestHandler());// remove this handler, and process the requests as spdypipeline.remove(this);ctx.sendUpstream(e);}  else if ("http/1.1".equals(provider.getSelectedProtocol())) {ChannelPipeline pipeline = ctx.getPipeline();pipeline.addLast("decoder", new HttpRequestDecoder());pipeline.addLast("http_encoder", new HttpResponseEncoder());pipeline.addLast("handler", new HttpRequestHandler());// remove this handler, and process the requests as httppipeline.remove(this);ctx.sendUpstream(e);} else {// we're still in protocol negotiation, no need for any handlers// at this point.}}
}
使用NPN API和当前的SSL上下文,我们可以检索之前添加的SimpleServerProvider。 我们检查是否已设置selectedProtocol,如果已设置,则设置一条链进行处理。 我们在此类中处理三个选项:
  1. 没有协议 :可能尚未协商任何协议。 在那种情况下,我们没有做任何特别的事情,只需正常处理即可。
  2. 有一个http协议 :我们建立了一个处理程序链来处理HTTP请求。
  3. 有一个spdy协议 :我们建立了一个处理程序链来处理SPDY请求。
有了这个链,我们最终由HttpRequestHandler接收到的所有消息都是HTTP请求。 我们可以正常处理此HTTP请求,然后返回HTTP响应。 各种管道配置将正确处理所有这些问题。
确保使用HTTP发送回正确的SPDY标头
我们需要做的最后一步是测试。 我们将使用最新版本的Chrome进行测试,以测试SPDY是否正常运行,并使用wget测试正常的http请求。 我提到了链中最后一个处理程序HttpRequestHandler进行我们的HTTP处理。 我已经使用http://netty.io/docs/stable/xref/org/jboss/netty/example/http/snoop/Http…作为HTTPRequestHandler,因为那很好地返回了有关HTTP请求的信息,而我却没有做任何事。 如果不做任何更改就运行它,则会遇到问题。 为了将HTTP响应与正确的SPDY会话相关联,我们需要将传入请求中的标头复制到响应中:“ X-SPDY-Stream-ID”标头。 我将以下内容添加到HttpSnoopServerHandler中,以确保复制了这些标头(实际上应该在单独的处理程序中完成此操作)。
private final static String SPDY_STREAM_ID = = "X-SPDY-Stream-ID";private final static String SPDY_STREAM_PRIO = "X-SPDY-Stream-Priority";// in the writeResponse method addif (request.containsHeader(SPDY_STREAM_ID)) {response.addHeader(SPDY_STREAM_ID,request.getHeader(SPDY_STREAM_ID));// optional header for prioresponse.addHeader(SPDY_STREAM_PRIO,0);}
现在剩下的就是一台具有启动所有内容的主服务器的服务器,并且我们可以测试SPDY实现。
public class SPDYServer {public static void main(String[] args) {// bootstrap is used to configure and setup the serverServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),Executors.newCachedThreadPool()));bootstrap.setPipelineFactory(new SPDYPipelineFactory());bootstrap.bind(new InetSocketAddress(8443));}
}
启动服务器,启动Chrome,然后查看是否一切正常。 打开https:// localhost:8443 / thisIsATest网址,您应该得到如下所示的结果:
在服务器的输出中,您可以看到一些NPN调试日志记录:
[S] NPN received for 68ce4f39[SSLEngine[hostname=null port=-1] SSL_NULL_WITH_NULL_NULL]
[S] NPN protocols [spdy/2, http/1.1] sent to client for 68ce4f39[SSLEngine[hostname=null port=-1] SSL_NULL_WITH_NULL_NULL]
[S] NPN received for 4b24e48f[SSLEngine[hostname=null port=-1] SSL_NULL_WITH_NULL_NULL]
[S] NPN protocols [spdy/2, http/1.1] sent to client for 4b24e48f[SSLEngine[hostname=null port=-1] SSL_NULL_WITH_NULL_NULL]
[S] NPN selected 'spdy/2' for 4b24e48f[SSLEngine[hostname=null port=-1] SSL_NULL_WITH_NULL_NULL]
额外的检查是使用以下网址查看chrome浏览器中打开的SPDY会话:chrome:// net-internals /#spdy
现在让我们检查普通的旧HTTP是否仍在工作。 从命令行执行以下操作:
jos@Joss-MacBook-Pro.local:~$ wget --no-check-certificate https://localhost:8443/thisIsATest
--2012-04-27 16:29:09--  https://localhost:8443/thisIsATest
Resolving localhost... ::1, 127.0.0.1, fe80::1
Connecting to localhost|::1|:8443... connected.
WARNING: cannot verify localhost's certificate, issued by `/C=NL/ST=NB/L=Waalwijk/O=smartjava/OU=smartjava/CN=localhost':Self-signed certificate encountered.
HTTP request sent, awaiting response... 200 OK
Length: 285 
Saving to: `thisIsATest'100%[==================================================================================>] 285         --.-K/s   in 0s      2012-04-27 16:29:09 (136 MB/s) - `thisIsATest' saved [285/285]jos@Joss-MacBook-Pro.local:~$ cat thisIsATest 
WELCOME TO THE WILD WILD WEB SERVER
===================================
VERSION: HTTP/1.1
HOSTNAME: localhost:8443
REQUEST_URI: /thisIsATestHEADER: User-Agent = Wget/1.13.4 (darwin11.2.0)
HEADER: Accept = */*
HEADER: Host = localhost:8443
HEADER: Connection = Keep-Alivejos@Joss-MacBook-Pro.local:~$
而且有效! Wget使用标准的HTTPS,我们得到一个结果,而chrome使用SPDY,并从同一处理程序中呈现结果。 在最后的几天里,我还将发布有关如何为Play Framework 2.0启用SPDY的文章,因为它们的Web服务器也基于Netty。
参考:来自Smart Java博客的JCG合作伙伴 Jos Dirksen 透明地使用Netty使用SPDY和HTTP 。

翻译自: https://www.javacodegeeks.com/2012/05/netty-using-spdy-and-http-transparently.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/373152.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

selenium 等待页面加载完成

一、隐形加载等待&#xff1a; file:///C:/Users/leixiaoj/Desktop/test.html 该页面负责创建一个div <html> <head><title>Set Timeout</title><style>.red_box {background-color: red; width 20%; height:100px; border: none;}</style&…

linux nfsnobody用户,处理CentOS 5.5 x64 配置NFS服务过程中nfsnobody用户造成的问题

4、我们编译一下这个NFS的配置文件。[rootNFS /]# vi /etc/exports/share 192.168.60.0/24(rw,sync,all_squash,root_squash) (我们允许这个共享对192.168.60.0/24网段可读可写&#xff0c;且将所有访问者包括root的身份都改为nfsnobody)[rootNFS /]# /etc/init.d/nfs resta…

c语言空格有什么作用,空格在c语言中怎么表示 C语言中的空格字符怎么表示

c语言中表示空格的是什么代码&#xff1f;分析如下&#xff1a; 不是所有字符都需要转义的&#xff0c;空格直接就敲空格&#xff0c;或者使用ASCII码值赋值为32。 空格没有转义字符。合法转义字符如下&#xff1a;\a 响铃(BEL) 、\b 退格(BS)、\f 换页(FF)、\n 换行(LF)、\r 回…

StringMVC 中如何做数据校验

步骤一&#xff1a;引入四个jar包 步骤二&#xff1a;注册类型转换器 <context:component-scan base-package"cn.happy.controller"></context:component-scan><!-- 配置验证器 --><bean id"myvalidator" class"org.springframe…

ibm+x3650+m4+linux+raid驱动,IBM X3650M4阵列卡驱动下载

ibm X3650M4raid阵列卡驱动适合安装windowsserver2008,windowsserver2008R2,系统问题&#xff0c;服务器问题&#xff0c;可以联系我们也可以到5分享论坛发帖求助。IBM System x3650 M4服务器是一款应用最为广泛的2U机架服务器&#xff0c;支持Xeon E5-2600机架服务器的所有产品…

UML类图与类的关系详解

在画类图的时候&#xff0c;理清类和类之间的关系是重点。类的关系有泛化(Generalization)、实现&#xff08;Realization&#xff09;、依赖(Dependency)和关联(Association)。其中关联又分为一般关联关系和聚合关系(Aggregation)&#xff0c;合成关系(Composition)。下面我们…

python之路-SQLAlchemy

SQLAchemy SQLAlchemy是Python编程语言下的一款ORM框架&#xff0c;该框架建立在数据库API之上&#xff0c;使用关系对象映射进行数据库操作&#xff0c;简言之便是&#xff1a;将对象转换成SQL&#xff0c;然后使用数据API执行SQL并获取执行结果。 安装&#xff1a; pip3 inst…

Linux中vim编辑器的缩进的功能键

vim编程时,经常需要对代码进行缩进处理,以增加程序的可读性和后期的代码维护. 可以采用多种方式达到缩进的目的: 1) 命令模式(command mode) 2) Visual模式&#xff08;visual mode&#xff09; 2) 输入模式(entry mode) 3) 末行模式(last-line mode) 4) 在/etc/vimrc有给予vim…

JSF 2,PrimeFaces 3,Spring 3和Hibernate 4集成项目

本文展示了如何集成JSF2&#xff0c;PrimeFaces3&#xff0c;Spring3和Hibernate4技术。 它为Java开发人员提供了一个通用的项目模板。 另外&#xff0c;如果Spring不用于业务和数据访问层&#xff0c;则可以提供JSF – PrimeFaces和Hibernate集成项目。 二手技术&#xff1a…

初识openstack

一、 什么是openstack&#xff1f; OpenStack是一个由NASA&#xff08;美国国家航空航天局&#xff09;和Rackspace合作研发并发起的&#xff0c;以Apache许可证授权的自由软件和开放源代码项目。 二、openstack前世今身 openstack是一个跟Eucalyptus,AWS(Amazon web Service)类…

Arquillian 1.0.0.Final正式发布! 准备使用GlassFish和WebLogic! 杀死所有虫子!

红帽公司和JBoss社区今天宣布的1.0.0.Final发布的Arquillian &#xff0c;其屡获殊荣的建在Java虚拟机&#xff08;JVM&#xff09;运行测试平台。 Arquillian大大减少了编写和执行Java中间件集成和功能测试所需的工作。 它甚至使测试工程师能够解决以前认为无法测试或测试成本…

qq五笔linux,QQ五笔 - 五笔小字典 QQ绑定很实用

九、 智能调频、空码检索、词序固定在QQ五笔中还有一些小亮点&#xff0c;比如它可以根据“最近输入”、“输入次数”对候选词排序。同时为了加快检索速度&#xff0c;默认只在常用字库(GB2312)中检索&#xff0c;只有出现空码后才会继续搜索容量更大的GBK字库&#xff0c;很好…

android 关闭蓝牙打电话功能,Android蓝牙开发【八】hfp接听、挂断电话

继续研究hfp相关功能。蓝牙耳机可以控制手机接听、拒接、挂断电话&#xff0c;拨打电话等功能。本文主要分析下起这些操作的大致流程。在系统应用Bluetooth中com_android_bluetooth.cpp提供了多个回调方法&#xff0c;由hardware、协议栈回调过来。蓝牙耳机的一些控制命令都会发…

将状态机模式实现为流处理器

在我的上一个博客中&#xff0c;我说我真的以为某些“四人行”&#xff08;GOF&#xff09;模式已经过时了&#xff0c;如果不是过时的话肯定不受欢迎。 特别是我说过StateMachine不是那么有用&#xff0c;因为您通常会想到另一种更简单的方式来执行您正在执行的事情&#xff0…

android 自定义actionbar,如何让android的actionbar浮动且透明

如上图所示&#xff0c;谷歌地图的actionbar是透明的&#xff0c;且浮动在整个布局之上&#xff0c;没有占用布局空间。其实要做到这样的效果&#xff0c;我们首先想到的是两个方面&#xff1a;1.将让actionbar浮动起来。2.给actionbar一个背景&#xff0c;可以为颜色也可以为图…

Ajax与CustomErrors的尴尬

在ASP.NET程序中&#xff0c;为了给用户显示友好的错误信息&#xff0c;通常在web.config中进行如下的设置&#xff1a; <customErrors mode"RemoteOnly" defaultRedirect"/error/error.htm"> </customErrors> 但如果是一个ajax请求在服务端发…

Java创建WebService服务及客户端实现

简介 WebService是一种服务的提供方式&#xff0c;通过WebService&#xff0c;不同应用间相互间调用变的很方便&#xff0c;网络上有很多常用的WebService服务&#xff0c;如&#xff1a;http://developer.51cto.com/art/200908/147125.htm&#xff0c;不同的语言平台对…

Java静态方法可能会产生代码异味

代码气味的定义 &#xff08;来自维基百科&#xff09;&#xff1a; “程序源代码中任何可能表明存在更深层问题的症状。” 在Java中&#xff0c; 静态方法允许您在“类范围”内执行代码&#xff0c;而不是像成员方法这样的实例范围。 这意味着&#xff0c;它们依赖于类级别的变…

Node Express4.x 片段视图 partials

1.在Express 4.x使用片段视图&#xff0c;需要引入partials模块 步骤&#xff1a; 1.在全局中安装express-partials模块&#xff1a; 2.在本地模块中安装express-partials,将模块安装到package.json中&#xff1a; 3.在入口文件(如&#xff1a;app.js)中引入模块&#xff1a; v…

bzoj1690:[Usaco2007 Dec]奶牛的旅行(分数规划+spfa判负环)

PS:此题数组名皆引用&#xff1a;戳我 题目大意&#xff1a;有n个点m条有向边的图&#xff0c;边上有花费&#xff0c;点上有收益&#xff0c;点可以多次经过&#xff0c;但是收益不叠加&#xff0c;边也可以多次经过&#xff0c;但是费用叠加。求一个环使得收益和/花费和最大&…