1. 程式人生 > >netty實現http api功能

netty實現http api功能

無可致疑,netty是java的網路通訊框架,支援高併發。本文掃描使用netty完成簡單的http的能力,不涉及安全,業務過濾等內容。

片段1

	/**
	 * 啟動http伺服器
	 * @throws InterruptedException
	 */
	private void runHttpServer(final EventProducer evtProducer) throws InterruptedException {
		
		// 配置TCP伺服器.
		EventLoopGroup bossGroup = new NioEventLoopGroup(ServerBootOption.Parent_EventLoopGroup_ThreadNum);
		EventLoopGroup workerGroup = new NioEventLoopGroup(ServerBootOption.Child_EventLoopGroup_ThreadNum);
		try {

			ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup)
					.channel(NioServerSocketChannel.class)
					.option(ChannelOption.SO_BACKLOG, 10240)
					.option(ChannelOption.TCP_NODELAY, true)
					.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
					.option(ChannelOption.SO_REUSEADDR, true)
					.option(ChannelOption.SO_KEEPALIVE, true)
					.option(ChannelOption.SO_LINGER, 0)
					//.childOption(ChannelOption.SO_TIMEOUT, ServerBootOption.SO_TIMEOUT)
					// .handler(new LoggingHandler(LogLevel.INFO))
					.childHandler(new ChannelInitializer<SocketChannel>(){
						 @Override 
					 	 protected void initChannel(SocketChannel ch) throws Exception {
							 ChannelPipeline p = ch.pipeline();
							 p.addLast("idleStateHandler", new IdleStateHandler(60, 60, 30));<span style="color:#FF0000;">//讀通道空閒60s,寫通道空閒60s,讀,寫通道空閒30s</span>
							 p.addLast("http_server_codec", new HttpServerCodec());//<span style="color:#FF0000;">http訊息轉換</span>
						         p.addLast("http_server_handler",new HttpProxyServerHandler(manager,evtProducer));//<span style="color:#FF0000;">訊息處理器</span>
						 }
			  
					});
			 
			// Start the tcp server.
			ChannelFuture f = b.bind(new InetSocketAddress(ip, port)).sync();//<span style="color:#FF0000;">啟動http服務程序</span>
			logger.info("start http server ok");
			// Wait until the server socket is closed.
			f.channel().closeFuture().sync();
		} finally {
			// Shut down all event loops to terminate all threads.
			logger.info("Shut down all event loops to terminate all threads.");
                         bossGroup.shutdownGracefully();//關閉服務程序
			workerGroup.shutdownGracefully();//關閉服務程序
		}
	}
片段2HttpProxyServerHandler
/**
 * 
 * @author 
 * http 請求事件處理器,負責分發http請求事件
 */
public class HttpProxyServerHandler extends ChannelHandlerAdapter{
	private static final Logger logger = Logger.getLogger(HttpProxyServerHandler.class);
	private SessionContextManager manager;<span style="color:#FF0000;">//會話管理</span>
	private final AttributeKey<Long> timestamp = AttributeKey.valueOf("timestamp");
	private final StringBuilder buf = new StringBuilder();
	public HttpProxyServerHandler(SessionContextManager manager){
		this.manager=manager;
	}
	@Override
    public void handlerAdded(final ChannelHandlerContext ctx)
            throws Exception{
    	 logger.info("["+ctx.channel().id().asLongText()+" ] is Added ");
    }
	@Override <span style="color:#FF0000;">會話關閉,失效事件</span>
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		 manager.getSession().remove(ctx.channel().id().asLongText());
		 super.channelInactive(ctx);
	}
	@Override <span style="color:#FF0000;">讀訊息</span><span style="color:#FF0000;">事件,業務處理的入口</span>
    public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
    	logger.info("HttpProxyServerHandler[channelRead] ");
    	Attribute<Long> attr_timestamp = ctx.channel().attr(timestamp);
    	attr_timestamp.set(System.currentTimeMillis());//<span style="color:#FF0000;">測試通道中儲存狀態訊息</span>,<span style="color:#FF0000;">如訊息處理的開如時間</span>
        SessionContext sctx=new SessionContext();
    	sctx.setCtx(ctx);
    	sctx.setChannelId(ctx.channel().id());
    	sctx.setSessionActiveTime(""+System.currentTimeMillis());
    	manager.getSession().put(sctx.getChannelId().asLongText(), sctx);//<span style="color:#FF0000;">manager.getSession() 為併發Map結構,用於會話保持</span>
    	logger.info(sctx.getChannelId().asLongText()+" req time "+System.currentTimeMillis());
    	try {
    		dispatchMeesage(ctx,manager ,msg);
        } finally {
         	 ReferenceCountUtil.release(msg);
        }

    }
	private QueryStringDecoder qdecoder =   null;
	private String uri="";//http uri
	private String url="";//http url
	private Map<String,List<String>> httpReqParams=null;//http請求引數
	/**
	 * 訊息分發
	 * @param ctx
	 * @param manager
	 * @param msg 訊息
	 * @return
	 * @throws Exception
	 */
	private String  dispatchMeesage(final ChannelHandlerContext ctx,
			final SessionContextManager manager, final Object msg) 
			throws Exception{
		String decode_message = "";
		HttpResponseUtils util = new HttpResponseUtils();
		String result_code="1";
		
		if (msg instanceof HttpRequest) {// http請求頭
			HttpRequest req = (HttpRequest) msg;
			url = req.getUri();
			if (url.equals("/favicon.ico")) {
	        	ctx.close();
	            return "0";
			}
			if(!url.equals("/billing")){
				ctx.close();
				return "0";
			}
			//if (is100ContinueExpected(req)) {
	           // ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
	       // }
			qdecoder = new QueryStringDecoder(url);
			httpReqParams = qdecoder.parameters();
			uri = qdecoder.path();
			/* TODO:身份認證
			 * if(qdecoder.parameters().containsKey("crendial")){
			 * crendial=(String
			 * )qdecoder.parameters().get("crendial").get(0).toUpperCase(); }
			 */
			
		} else if (msg instanceof HttpContent) { // http請求體
			
			HttpContent httpContent = (HttpContent) msg;
			ByteBuf content = httpContent.content();
			if (content.isReadable()) {
				String chunk_message=content.toString(CharsetUtil.UTF_8);
		                 buf.append(chunk_message);
			}
			
		       if (!(msg instanceof LastHttpContent)) {//<span style="color:#FF0000;">不是最後一個chunk包塊,此項非常 重要,當http分多片傳輸時,需要將多塊內容合併</span>
	       		return "0";
	       	       }else{
	       		decode_message= buf.toString(); //
	       		logger.info(decode_message);
	       	      }
	         
			if (msg instanceof LastHttpContent) {
				//LastHttpContent trailer = (LastHttpContent) msg;
				
				String sessionId=ctx.channel().id().asLongText();
				System.out.println("請求"+decode_message);
				System.out.println("請求引數"+httpReqParams);
				System.out.println("請求地址"+uri);
				System.out.println("會話Id"+sessionId);
				//<span style="color:#FF0000;">TODO:模擬傳送請求訊息給後端處理,可以放入訊息佇列,ctx物件進入會話保持(Map物件)中,等訊息佇列中處理完成後,恢復會話,並完成訊息應答。</span>
				
			}
			
		}
		return result_code;
	}
	private static AtomicInteger counter = new AtomicInteger(0);
	@Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		manager.getSession().remove(ctx.channel().id().asLongText());
        cause.printStackTrace();
        ctx.close();
        
    }
	@Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    	logger.error("HttpProxyServerHandler[userEventTriggered] ");
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.ALL_IDLE) {
            	logger.error("ALL_IDLE");

            } else if (e.state() == IdleState.READER_IDLE){
            	logger.error("READER_IDLE");
    
            }else if (e.state() == IdleState.WRITER_IDLE){
            	logger.error("WRITER_IDLE");
            }
        	
        	ctx.close();
        }else if(evt instanceof ErrorEvent){
        	logger.error(((ErrorEvent) evt).getErrorCode());
        	
        	ctx.close();
        }
        
    }
}

SessionContext
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
/**
 * http請求會話
 * @author wanghao
 *
 */
public class SessionContext {
	private ChannelId channelId =null ;/**會話 channel ID*/
	private ChannelHandlerContext ctx;/**會話*/
	private String sessionActiveTime;/**會話建立時間*/
	private String sessionUnActiveTime;/**會話失效時間*/
	
	public String getSessionActiveTime() {
		return sessionActiveTime;
	}
	public void setSessionActiveTime(String sessionActiveTime) {
		this.sessionActiveTime = sessionActiveTime;
	}
	public String getSessionUnActiveTime() {
		return sessionUnActiveTime;
	}
	public void setSessionunActiveTime(String sessionUnActiveTime) {
		this.sessionUnActiveTime = sessionUnActiveTime;
	}

	
	public ChannelHandlerContext getCtx() {
		return ctx;
	}
	public void setCtx(ChannelHandlerContext ctx) {
		this.ctx = ctx;
	}
	
	
	public ChannelId getChannelId() {
		return channelId;
	}
	public void setChannelId(ChannelId channelId) {
		this.channelId = channelId;
	}
	
}



http請求會話管理器

import java.util.Map;
/**
 * http請求會話管理器
 * @author 
 *
 */
public interface SessionContextManager {
	abstract Map<String,SessionContext> getSession();
}


相關推薦

netty實現http api功能

無可致疑,netty是java的網路通訊框架,支援高併發。本文掃描使用netty完成簡單的http的能力,不涉及安全,業務過濾等內容。 片段1 /** * 啟動http伺服器 * @throws InterruptedException */ private

基於netty實現http伺服器

匯入netty4的依賴 <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>

使用Netty實現HTTP伺服器

使用Netty實現HTTP伺服器,使用Netty實現httpserver。 Netty是一個非同步事件驅動的網路應用程式框架用於快速開發可維護的高效能協議伺服器和客戶端。Netty經過精心設計,具有豐富的協議,如FTP,SMTP,HTTP以及各種二進位制和基於文字的傳統協議。 Java程式設計師在開發we

Springboot2(24)整合netty實現http服務(類似SpingMvc的contoller層實現

原始碼地址 springboot2教程系列 其它netty檔案有部落格 Springboot2(24)整合netty實現http服務(類似SpingMvc的contoller層實現) Springboot2(25)整合netty實現檔案傳輸 Springb

unittest實現HTTP介面功能測試

作者:vickygui 一、背景 目前主流的H5頁面動態獲取內容的方式是採用ajax非同步請求後臺資料實現實時重新整理,實際上就是用GET/POST的HTTP請求後臺介面,再將返回的資料(一般是json或xml格式)渲染在頁面上,因此保證H5頁面介面的功能正

MicroPython TPYBoard v702實現HTTP應用功能

[Micropython]TPYBoard v702 HTTP應用功能 轉載請註明文章來源,更多教程可自助參考docs.tpyboard.com,QQ技術交流群:157816561,公眾號:MicroPython玩家匯 什麼是TPYBoard v702 TPYBoard v702是山東蘿蔔電子科技有限公

C#簡單的JPush(極光推送) API實現推送功能(來自mojocube的博客)

size 返回 log c# api live str -s 周期 APP推送功能大家應該都了解了,目前主要的有百度、極光等幾家公司提供推送服務,下面說一下極光推送API的簡單實現推送通知功能。 註冊完極光的賬號後,就可以創建應用,建好後會得到AppKey和Master

百度地圖API開發一——仿照現有測距實現測量面積功能

poi 樣式 鼠標 mage 移動 block 客戶 mar area   最近做了一個百度地圖API的開發項目,裏面有測量距離和測量面積的功能需求。測量距離百度給出了封裝好的javascript包——BMapLib.DistanceTool,效果如下: 這個效果體驗

QGIS在ANDRIOD上利用高德API實現道路導航功能

qgisQGIS在ANDRIOD上利用高德API實現道路導航功能

【C++】純C++實現http打開網頁下載內容的功能

instance cat load The tco n) app nbsp his #include "stdafx.h" #include <windows.h> #include <iostream> #include "Wininet

基於netty實現單聊、群聊功能

擴容 單例模式 輔助類 數據包 字節 等等 byte 良好的 解碼 學習資料 https://juejin.im/book/5b4bc28bf265da0f60130116/section/5b6a1a9cf265da0f87595521 收獲: 1. Netty 是什

四、Netty實現webSocket,實現伺服器與瀏覽器(HTML)線上聊天功能

        由於http協議有一個缺陷:通訊只能由客戶端發起。如果伺服器有連續的狀態變化,客戶端要獲知只能使用"輪詢":每隔一段時候,就發出一個詢問,瞭解伺服器有沒有新的資訊。輪詢的效率低,非常浪費資源(因為必須不停連線,或者 HTTP 連線始終開啟)

Java實現是否為節假日、工作日判斷(呼叫“http://api.goseek.cn/Tools/holiday”介面)

工具類: package com.ai.rai.group.system; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.TypeReference; import org.apache.common

使用百度分享api實現網頁分享功能

百度官方文件:http://share.baidu.com/code/advance#toid 首先先引入外部檔案: with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('sc

Netty 實現 WebSocket 聊天室功能

WebSocket 是 H5 的一種技術,目前有很多語言都有相應的實現,之前有用 WebSocket 實現過 Java 和安卓,IOS 通訊的專案。想來也該分享一下,看過不少專案要實現頁面資料實時更新的操作,有用輪詢有用 Socket 連結的,當然也不排除有很多前端其他技術可以實現,WebSocke

ArcGIS API for Silverlight實現地圖測距功能

問題:如何實現地圖測距功能? 地圖工具欄 <Grid x:Name="gToolMenu" Height="100" VerticalAlignment="Top" Opacity="0.8" HorizontalAlignment="Right" Width="467

Netty實現簡單HTTP代理伺服器

自上次使用Openresty+Lua+Nginx的來加速自己的網站,用上了比較時髦的技術,感覺算是讓自己的網站響應速度達到極限了,直到看到了Netty,公司就是打算用Netty來替代Openresty這一套,所以,自己也學了好久,琢磨了好一趟才知道怎麼用,現在用來寫一套HTTP代理伺服器吧,之後再測試一下效能

Netty實現高效能的HTTP伺服器

16:58:59.130 [nioEventLoopGroup-3-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxSharedCapacityFactor: 2 16:58:59.130 [nioEventLoopGroup-3-1

Java servlet 簡單實現http檔案下載斷點續傳功能

斷點續傳,聽上去似乎是個比較高階的話題,本文只講述一下http版的斷點續傳,其他協議的大家可以自行研究。 http協議中,服務端實現斷點續傳首先需要讀取客戶端傳送的Range頭資訊,比如“Range: bytes=12583394-”這個就是指原來正在下載的檔案需要從第12

Netty實現簡單的Http伺服器

之前在upload伺服器的時候,由於tomcat效能瓶頸的的問題,qps無法達到要求,瞭解到Netty.io的高效能,覺得自己寫一個Http接受資料的伺服器來處理客戶段上報的資料,比較簡單,直接貼程式碼了: package com.bonree.browser