1. 程式人生 > >Netty4實現HTTP請求、響應

Netty4實現HTTP請求、響應

前言:
我們所編寫的專案多以BS為主,使用者通過瀏覽器訪問我們的伺服器
傳送的請求以HTTP請求為主,本例就以Netty4來實現一個接收HTTP請求的伺服器,並根據使用者請求返回響應

1.Netty中HTTP請求和響應類

  • 請求(FullHttpRequest)
/**
 * Combine the {@link HttpRequest} and {@link FullHttpMessage}, so the request is a <i>complete</i> HTTP
 * request.
 */
public interface FullHttpRequest extends HttpRequest, FullHttpMessage {

可以看到,它結合了HttpRequest、FullHttpMessag,作為一個完整的HTTP請求體。
預設實現為DefaultFullHttpRequest

  • 響應(FullHttpResponse)
/**
 * Combination of a {@link HttpResponse} and {@link FullHttpMessage}.
 * So it represent a <i>complete</i> http response.
 */
public interface FullHttpResponse extends HttpResponse, FullHttpMessage {

同樣,它結合了HttpResponse、FullHttpMessage
預設實現為DefaultFullHttpResponse
*

2.Netty中客戶端、服務端的編解碼器

作為服務端而言:
主要工作就是接收客戶端請求,將客戶端的請求內容解碼;傳送響應給客戶端,並將傳送內容編碼
所以,服務端需要兩個編解碼器
* HttpRequestDecoder(將請求內容解碼)
* HttpResponseEncoder(將響應內容編碼)

作為客戶端而言:
主要工作就是傳送請求給服務端,並將傳送內容編碼;接收服務端響應,並將接收內容解碼;
所以,客戶端需要兩個編解碼器
* HttpResponseDecoder(將響應內容解碼)
* HttpRequestEncoder(將請求內容編碼)

3.Server端編寫Handler類處理客戶請求

建立Handler,命名為HttpHandler,具體內容如下:
import com.alibaba.fastjson.JSONObject;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;
import lombok.Data;

/**
 * 處理HTTP請求
 * @author Administrator
 *
 */
public class HttpHandler extends ChannelInboundHandlerAdapter {

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
	
		if(msg instanceof FullHttpRequest){
			
			FullHttpRequest req = (FullHttpRequest)msg;
			
			try {
				
				// 1.獲取URI
				String uri = req.uri();
				
				// 2.獲取請求體
				ByteBuf buf = req.content();
				String content = buf.toString(CharsetUtil.UTF_8);
				
				// 3.獲取請求方法
				HttpMethod method = req.method();
				
				// 4.獲取請求頭
				HttpHeaders headers = req.headers();
				
				// 5.根據method,確定不同的邏輯
				if(method.equals(HttpMethod.GET)){
					
					// TODO 
				}
				
				if(method.equals(HttpMethod.POST)){
					// 接收使用者輸入,並將輸入返回給使用者
					Content c = new Content();
					c.setUri(uri);
					c.setContent(content);
					
					response(ctx, c);
				}
				
				if(method.equals(HttpMethod.PUT)){
					// TODO 
				}
				
				if(method.equals(HttpMethod.DELETE)){
					// TODO 
				}
			} finally {
				req.release();
			}
		}
	}

	private void response(ChannelHandlerContext ctx, Content c) {

		// 1.設定響應
		FullHttpResponse resp = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
				HttpResponseStatus.OK, 
				Unpooled.copiedBuffer(JSONObject.toJSONString(c), CharsetUtil.UTF_8));
		
		resp.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
		
		// 2.傳送
		// 注意必須在使用完之後,close channel
		ctx.writeAndFlush(resp).addListener(ChannelFutureListener.CLOSE);
	}
}

@Data
class Content{
	String uri;
	String content;
}

注意:
在處理過程中,把msg轉換為FullHttpRequest,可以獲取關於請求的所有內容;
在傳送響應時必須要監聽CLOSE
*

4.測試

  1. 啟動Server類
  2. 使用客戶端傳送請求
    在這裡,筆者不單獨編寫Netty客戶端程式碼,直接使用PostMan來充當客戶端傳送請求,具體如下:
    在這裡插入圖片描述
    傳送一個post請求,並填寫body,點選send,可以看到響應如下所示:
    在這裡插入圖片描述

參考:Netty in Action