HTTP协议上传文件

基本原理

HTTP消息结构

请求结构

HTTP协议上传文件_第1张图片
HTTP 请求结构
  1. HttpRequest: http请求头
  2. HttpContent:包含http请求的一块数据
  3. 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协议上传文件_第2张图片
HTTP 响应结构
  1. 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进行处理。

你可能感兴趣的:(HTTP协议上传文件)