基本原理
HTTP消息结构
请求结构

HTTP 请求结构
- HttpRequest: http请求头
- HttpContent:包含http请求的一块数据
- LastHttpContent:HttpContent子类,标识Http请求结束,同时包含trailing headers
这样服务器接收到的客户端请求在HttpRequestDecoder作用下,变为一个HttpRequest、若干个HttpContent、一个LastHttpContent的结构。
GET:请求获取Request-URI所标识的资源。仅包含HttpRequest,不包含HttpContent,只需要解析URI找URI所标识的资源,并构造适合的Http响应返回客户端。
POST:在Requst-URI所标识的资源后附加新的提交数据。对于POST请求,netty需要使用HttpPostRequestDecoder对请求体进行解析。
在获取POST的HttpRequest时,需要初始化HttpPostRequestDecoder
HttpRequest request;
if (httpObject instanceof HttpRequest) {
request = (HttpRequest) httpObject;
}
public static final HttpDataFactory factory = new DefaultHttpDataFactory(Configuration.DISKSIZE);
HttpPostRequestDecoder httpDecoder = new HttpPostRequestDecoder(factory, request);
之后需要使用httpDecode根据数据的类型
enum HttpDataType { Attribute, FileUpload, InternalAttribute }
对所有数据进行解析。
HTTP响应结构

HTTP 响应结构
- HttpResponse: http响应头
public static void writeResponseJSON(HttpRequest request, Channel channel, String returnMsg) {
logger.info("writeResponse ...");
ByteBuf buf = copiedBuffer(returnMsg, CharsetUtil.UTF_8);
boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.headers().get(CONNECTION))|| request.getProtocolVersion().equals(HttpVersion.HTTP_1_0) && !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.headers().get(CONNECTION));
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
response.headers().set(CONTENT_TYPE, "application/json; charset=UTF-8");
setResponseHeader(response);
if (!close) { //若该请求响应是最后的响应,则在响应头中没有必要添加'Content-Length'
response.headers().set(CONTENT_LENGTH, buf.readableBytes());
}
ChannelFuture future = channel.writeAndFlush(response); future.addListener(ChannelFutureListener.CLOSE);
}
// 设置跨域响应头
private static void setResponseHeader(HttpResponse response) {
response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
response.headers().set(ACCESS_CONTROL_ALLOW_CREDENTIALS, true);
response.headers().set(ACCESS_CONTROL_MAX_AGE, 86400);}
如果返回大文件,可以使用下面的语句
ChannelFuture writeFuture = ctx.write(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)), ctx.newProgressivePromise());
在我的实验中,返回60M的zip文件,在前端总收到没有传递完的zip文件,不可解压。原来是由于netty的NIO特性,文件会异步传输给前端,如果你在文件的传输过程中,错误地写入了其它的响应,前端得到此响应认为文件已经传输完毕,终止了异步文件的传送,导致不完整Zip文件地产生。因此,在编程过程中,推荐正常地流程只有一个response,对于异常流程,推荐使用异常地方式,在外层捕捉。
在了解HTTP请求和响应结构之后,根据对应地结构就可以对Http进行处理。