Netty:透明地使用SPDY和HTTP
生活随笔
收集整理的這篇文章主要介紹了
Netty:透明地使用SPDY和HTTP
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
大多數(shù)人已經(jīng)從谷歌那里聽(tīng)說(shuō)過(guò)SPDY,該協(xié)議被提議作為老化的HTTP協(xié)議的替代品。 Web服務(wù)器是瀏覽器正在緩慢地實(shí)現(xiàn)該協(xié)議,并且支持正在增長(zhǎng)。 在最近的文章中,我已經(jīng)寫(xiě)過(guò)SPDY的工作方式以及如何在Jetty中啟用SPDY支持。 由于Netty(最初來(lái)自JBoss)幾個(gè)月以來(lái)也支持SPDY 。由于Netty通常用于高性能協(xié)議服務(wù)器,因此SPDY是合乎邏輯的。 在本文中,我將向您展示如何創(chuàng)建一個(gè)基于Netty的基本服務(wù)器,該服務(wù)器在SPDY和HTTP之間進(jìn)行協(xié)議協(xié)商。 它使用Netty snoop示例中的示例HTTPRequestHandler來(lái)消耗并產(chǎn)生一些HTTP內(nèi)容。 為了使一切正常,我們需要做以下事情: 將NPN lib添加到引導(dǎo)路徑 將SSL上下文連接到NPN Api 將NPN庫(kù)添加到boothpath 首先是第一件事。 從http://repo2.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/8.1.2.v2012下載NPN引導(dǎo)jar,并確保在運(yùn)行服務(wù)器時(shí)像這樣啟動(dòng)它: java -Xbootclasspath/p:<path_to_npn_boot_jar> 通過(guò)這段代碼,Java SSL支持NPN。 但是,我們?nèi)匀恍枰L問(wèn)此協(xié)商的結(jié)果。 我們需要知道我們使用的是HTTP還是SPDY,因?yàn)檫@決定了我們?nèi)绾翁幚斫邮盏降臄?shù)據(jù)。 為此,Jetty提供了一個(gè)API。 為此和所需的Netty庫(kù),我們將以下依賴(lài)項(xiàng)添加到pom中,因?yàn)槲沂褂玫氖莔aven。 <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 現(xiàn)在,我們已啟用NPN并將正確的API添加到項(xiàng)目中,我們可以配置Netty SSL處理程序。 在Netty中配置處理程序是在PipelineFactory中完成的。 對(duì)于我們的服務(wù)器,我創(chuàng)建了以下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;}
} 在此類(lèi)的構(gòu)造函數(shù)中,我們?cè)O(shè)置了基本的SSL上下文。 我們使用的密鑰庫(kù)和密鑰是我使用java keytool創(chuàng)建的,這是常規(guī)的SSL配置。 收到請(qǐng)求后,將調(diào)用getPipeline操作來(lái)確定如何處理該請(qǐng)求。 在這里,我們使用Jetty-NPN-API提供的NextProtoNego類(lèi)將SSL連接連接到NPN實(shí)現(xiàn)。 在此操作中,我們傳遞一個(gè)提供程序,該提供程序用作服務(wù)器的回調(diào)和配置。 我們還將NextProtoNego.debug設(shè)置為true。 這會(huì)打印出一些調(diào)試信息,從而使調(diào)試更加容易。 SimpleServerProvider的代碼非常簡(jiǎn)單: 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;}
} 此代碼幾乎是不言自明的。 沒(méi)有協(xié)議 :可能尚未協(xié)商任何協(xié)議。 在那種情況下,我們沒(méi)有做任何特別的事情,只需正常處理即可。 有一個(gè)http協(xié)議 :我們建立了一個(gè)處理程序鏈來(lái)處理HTTP請(qǐng)求。 有一個(gè)spdy協(xié)議 :我們建立了一個(gè)處理程序鏈來(lái)處理SPDY請(qǐng)求。 有了這個(gè)鏈,我們最終由HttpRequestHandler接收到的所有消息都是HTTP請(qǐng)求。 我們可以正常處理此HTTP請(qǐng)求,然后返回HTTP響應(yīng)。 各種管道配置將正確處理所有這些問(wèn)題。 確保使用HTTP發(fā)送回正確的SPDY標(biāo)頭 我們需要做的最后一步是測(cè)試。 我們將使用最新版本的Chrome進(jìn)行測(cè)試,以測(cè)試SPDY是否正常運(yùn)行,并使用wget測(cè)試正常的http請(qǐng)求。 我提到了鏈中最后一個(gè)處理程序HttpRequestHandler進(jìn)行我們的HTTP處理。 我已經(jīng)使用http://netty.io/docs/stable/xref/org/jboss/netty/example/http/snoop/Http…作為HTTPRequestHandler,因?yàn)槟呛芎玫胤祷亓擞嘘P(guān)HTTP請(qǐng)求的信息,而我卻沒(méi)有做任何事。 如果不做任何更改就運(yùn)行它,則會(huì)遇到問(wèn)題。 為了將HTTP響應(yīng)與正確的SPDY會(huì)話相關(guān)聯(lián),我們需要將傳入請(qǐng)求中的標(biāo)頭復(fù)制到響應(yīng)中:“ X-SPDY-Stream-ID”標(biāo)頭。 我將以下內(nèi)容添加到HttpSnoopServerHandler中,以確保復(fù)制了這些標(biāo)頭(實(shí)際上應(yīng)該在單獨(dú)的處理程序中完成此操作)。 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);} 現(xiàn)在剩下的就是一臺(tái)具有啟動(dòng)所有內(nèi)容的主服務(wù)器的服務(wù)器,并且我們可以測(cè)試SPDY實(shí)現(xiàn)。 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));}
} 啟動(dòng)服務(wù)器,啟動(dòng)Chrome,然后查看是否一切正常。 打開(kāi)https:// localhost:8443 / thisIsATest網(wǎng)址,您應(yīng)該得到如下所示的結(jié)果: 在服務(wù)器的輸出中,您可以看到一些NPN調(diào)試日志記錄: [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] 額外的檢查是使用以下網(wǎng)址查看chrome瀏覽器中打開(kāi)的SPDY會(huì)話:chrome:// net-internals /#spdy 現(xiàn)在讓我們檢查普通的舊HTTP是否仍在工作。 從命令行執(zhí)行以下操作: 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使用標(biāo)準(zhǔn)的HTTPS,我們得到一個(gè)結(jié)果,而chrome使用SPDY,并從同一處理程序中呈現(xiàn)結(jié)果。 在最后的幾天里,我還將發(fā)布有關(guān)如何為Play Framework 2.0啟用SPDY的文章,因?yàn)樗鼈兊腤eb服務(wù)器也基于Netty。 參考:來(lái)自Smart Java博客的JCG合作伙伴 Jos Dirksen 透明地使用Netty使用SPDY和HTTP 。
- 在Java中啟用NPN以確定要使用的協(xié)議。
- 根據(jù)協(xié)商的協(xié)議,確定使用HTTP還是SPDY。
- 確保使用HTTP發(fā)送回正確的SPDY標(biāo)頭。
- 當(dāng)客戶(hù)端不支持NPN時(shí),將調(diào)用不受支持的操作。 在這種情況下,我們默認(rèn)為HTTP。
- protocol()操作返回服務(wù)器支持的協(xié)議
- 服務(wù)器和客戶(hù)端協(xié)商協(xié)議后,將調(diào)用protocolSelected操作
翻譯自: https://www.javacodegeeks.com/2012/05/netty-using-spdy-and-http-transparently.html
總結(jié)
以上是生活随笔為你收集整理的Netty:透明地使用SPDY和HTTP的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 微信自动收款怎么设置(微信自动收款怎么设
- 下一篇: JAXB和未映射的属性