最近在做NettyHttp服务相关的东西,发现在网上找各种资料始终不全面或者不准确,最好的方式还是看官方API文档+了解HTTP协议本身的设计:
1:Netty官方API文档:http://netty.io/4.0/api/index.html
2:HTTP协议本身的设计:http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html
我们首先根据HTTP协议本身的设计,看Netty针对HTTP给出的解决方案:
Http
http请求由三部分组成,分别是:请求行、消息报头、请求正文。
Netty中使用类HttpRequest来处理HTTP请求。
- 请求行
请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式如下:Method Request-URI HTTP-Version CRLF
其中 Method表示请求方法;Request-URI是一个统一资源标识符;HTTP-Version表示请求的HTTP协议版本;CRLF表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符)
HttpRequest类有如下get方法,分别用来获取HttpRequest请求的各个部分:
request.getMethod();//获取Method
request.getClass();
request.getProtocolVersion();//获取HTTP-Version
request.getUri();//获取Request-URI
request.getDecoderResult();
Netty的Handler中的参数类型为HttpObject msg;
public void channelRead0(ChannelHandlerContext ctx, HttpObject msg)
我们根据API文档可以知道HttpObject类的派生类有如下:
io.netty.handler.codec.http
Interface HttpObject
All Known Subinterfaces:
FullHttpMessage, FullHttpRequest, FullHttpResponse, HttpContent, HttpMessage, HttpRequest, HttpResponse, LastHttpContent
All Known Implementing Classes:
DefaultFullHttpRequest, DefaultFullHttpResponse, DefaultHttpContent, DefaultHttpMessage, DefaultHttpObject, DefaultHttpRequest, DefaultHttpResponse, DefaultLastHttpContent
可以知道Netty可以在Handler中处理这些HttpObject派生类对象。我们当前仅仅讨论HttpRequest对象的解析而已。
- 消息报头
request.headers();
通过这个函数可以获取到HTTP协议中的消息头。对于消息头有那些解决方案,可以通过函数后面自己详细分析。
HttpResponse
HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文
Netty中HttpResponse相关的类有:
我们以FullHttpResponse来分析Netty对Http回包的支持
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
这是构建一个回包,同时可以通过:
response.getProtocolVersion()
response.getStatus()
分别获取协议版本和响应状态码
1、状态行格式如下:
HTTP-Version Status-Code Reason-Phrase CRLF
其中,HTTP-Version表示服务器HTTP协议的版本;Status-Code表示服务器发回的响应状态代码;Reason-Phrase表示状态代码的文本描述。
状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:
1xx:指示信息--表示请求已接收,继续处理
2xx:成功--表示请求已被成功接收、理解、接受
3xx:重定向--要完成请求必须进行更进一步的操作
4xx:客户端错误--请求有语法错误或请求无法实现
5xx:服务器端错误--服务器未能实现合法的请求
常见状态代码、状态描述、说明:
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
eg:HTTP/1.1 200 OK (CRLF)
我们可以看出,Netty的Http回包里,只有HTTP-Version Status-Code两项,之后就是回包内容了。
2、响应报头后述
Netty中的响应报头相关类有如下:
其中,我们可以通过HttpHeaders这个类(更准确的说是DefaultHttpHeaders)来获取HttpHeaderEntity
对返回消息头的使用一般如下:
Gson gson = new Gson();
ByteBuf buf = copiedBuffer(gson.toJson(outMap), CharsetUtil.UTF_8);
// Decide whether to close the connection or not.
boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request
.headers().get(HttpHeaders.Names.CONNECTION))
|| request.getProtocolVersion().equals(HttpVersion.HTTP_1_0)
&& !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request
.headers().get(HttpHeaders.Names.CONNECTION));
// 构建回包
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
//Content-Encoding:已经被应用到实体正文的附加内容的编码
response.headers().set(HttpHeaders.Names.CONTENT_ENCODING,HttpHeaders.Values.BASE64);
//是否
response.headers().set(HttpHeaders.Names.CACHE_CONTROL,HttpHeaders.Values.NO_CACHE);
//Content-Type:实体报头域用语指明发送给接收者的实体正文的媒体类型
response.headers().set(HttpHeaders.Names.CONTENT_TYPE,"text/plain; charset=UTF-8");
//將回包內容的長度放到Header中
if (!close) {
//Content-Length:实体报头域用于指明实体正文的长度,以字节方式存储的十进制数字来表示
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, buf.readableBytes());
}
3、响应正文就是服务器返回的资源的内容