服务器上传文件一般用什么 服务器上传文件用的方法

简介在上一篇文章中,我们谈到了如何从HTTP服务器下载文件,搭建下载服务器应该注意的问题,以及使用的GET方法。本文将讨论向服务器提交数据的常见POST方法以及如何向服务器上传

本文最后更新时间:  2023-02-28 22:19:13

简介

在上一篇文章中,我们谈到了如何从HTTP服务器下载文件,搭建下载服务器应该注意的问题,以及使用的GET方法。本文将讨论向服务器提交数据的常见POST方法以及如何向服务器上传文件。

GET方法上传数据。

根据HTTP的规范,PUT一般会将数据上传到服务器。虽然不推荐,但是GET也可以用来将数据上传到服务器。

下面我们来看看GET客户端建设中需要注意的问题。

GET实际上是一个URI,后跟请求的参数。netty提供了一个QueryStringEncoder来构建参数内容:

// HTTP请求 QueryStringEncoder encoder = new QueryStringEncoder(get); // 添加请求参数 encoder.addParam("method", "GET"); encoder.addParam("name", "flydean"); encoder.addParam("site", "www.flydean.com"); URI uriGet = new URI(encoder.toString());

使用请求URI,您可以创建一个HttpRequest。当然,这个HttpRequest也需要相应的HTTP头数据:

HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString()); HttpHeaders headers = request.headers(); headers.set(HttpHeaderNames.HOST, host); headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE); headers.set(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP + "," + HttpHeaderValues.DEFLATE); headers.set(HttpHeaderNames.ACCEPT_LANGUAGE, "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2"); headers.set(HttpHeaderNames.REFERER, uriSimple.toString()); headers.set(HttpHeaderNames.USER_AGENT, "Netty Simple Http Client side"); headers.set(HttpHeaderNames.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); headers.set( HttpHeaderNames.COOKIE, ClientCookieEncoder.STRICT.encode( new DefaultCookie("name", "flydean"), new DefaultCookie("site", "www.flydean.com")) );

我们知道HttpRequest中只有两部分数据,即HttpVersion和HttpHeaders。Version是HTTP协议的版本号,HttpHeaders是set头的内容。

对于GET请求,因为所有内容都包含在URI中,所以不需要额外的HTTPContent。只需将HttpRequest直接发送到服务器。

channel.writeAndFlush(request);

然后看看服务器收到GET请求后是如何处理的。

服务器收到HttpObject的msg后,需要将其转换成HttpRequest对象,然后通过protocolVersion()、uri()和headers()获取相应的信息。

对于URI中的参数,netty提供了QueryStringDecoder类,它可以很容易地解析URI中的参数:

//解析URL中的参数 QueryStringDecoder decoderQuery = new QueryStringDecoder(request.uri()); Map<String, List<String>> uriAttributes = decoderQuery.parameters(); for (Entry<String, List<String>> attr: uriAttributes.entrySet()) { for (String attrVal: attr.getValue()) { responseContent.append("URI: ").append(attr.getKey()).append('=').append(attrVal).append("\r\n"); } }

POST方法上传数据

对于POST请求,它比GET请求多了一个HTTPContent,也就是说除了基本的HttpRequest数据之外,还需要一个PostBody。

如果只是普通的帖子,也就是帖子的内容都是key=value的形式,那就比较简单了。如果帖子包含文件,会比较复杂,需要使用enctype = "multipart/form-data "。

Netty提供了一个HttpPostRequestEncoder类,用于快速编码请求体。让我们先来看一下HttpPostRequestEncoder类的完整构造函数:

public HttpPostRequestEncoder( HttpDataFactory factory, HttpRequest request, boolean multipart, Charset charset, EncoderMode encoderMode)

请求是要编码的HttpRequest,multipart表示是否为“multipart/form-data”格式。字符集编码方法是CharsetUtil。默认为UTF_8。EncoderMode是一种编码模式。目前有三种编码模式,分别是RFC1738、RFC3986和HTML5。

默认情况下,编码模式是RFC1738,这也是大多数表单提交数据的编码模式。但是,它不适用于OAUTH。如果要使用OAUTH,可以使用RFC3986。HTML5禁用多部分/表单数据的混合模式。

最后说一下HttpDataFactory。工厂主要用于创建InterfaceHttpData。它有一个minSize参数。如果创建的HttpData大于minSize,则存储在磁盘中,否则直接在内存中创建。

InterfaceHttpData有三种类型的HttpData,即Attribute、FileUpload和InternalAttribute。

是在属性POST请求中传入的属性值。FileUpload是POST请求传入的文件,在编码器内部使用InternalAttribute,这里不讨论。

因此,根据传入的minSize参数的大小,可以将Attribute和FileUpload分为以下几类:

MemoryAttribute、DiskAttribute或mixed attribute
memory file upload、DiskFileUpload或MixedFileUpload

本节我们先来看看POST请求中不上传文件的处理方法。首先,创建HTTP请求和PostBody编码器:

// 构建HTTP request HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriSimple.toASCIIString()); HttpPostRequestEncoder bodyRequestEncoder = new HttpPostRequestEncoder(factory, request, false);

向请求添加标题:

// 添加headers for (Entry<String, String> entry : headers) { request.headers().set(entry.getKey(), entry.getValue()); }

然后将form属性添加到bodyRequestEncoder:

// 添加form属性 bodyRequestEncoder.addBodyAttribute("method", "POST"); bodyRequestEncoder.addBodyAttribute("name", "flydean"); bodyRequestEncoder.addBodyAttribute("site", "www.flydean.com"); bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed", false);

注意,在上面,我们已经向bodyRequestEncoder添加了方法、名称和站点的属性。然后添加了FileUpload。但是,因为我们的编码方法不是“multipart/form-data”,所以这里只传递文件名,而不是整个文件。

最后,我们将调用bodyRequestEncoder的finalizeRequest方法来返回要发送的最终请求。在finalizeRequest过程中,transfer-encoding是否分块将根据传输数据的大小来设置。

如果传输的内容很大,需要分段传输。这时它需要设置transfer-encoding = chunked,否则不会设置。

上次发送请求:

// 发送请求 channel.write(request);

在服务器端,我们还需要构造一个HttpDataFactory,然后使用这个工厂构造一个HttpPostRequestDecoder来解码来自编码器的数据:

HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);//POST请求decoder = new HttpPostRequestDecoder(factory, request);

因为服务器收到的消息根据发送消息的长度可以是HttpContent也可以是LastHttpContent。如果是HttpContent,我们会将解析的结果缓存在一个StringBuilder中,然后在接收到LastHttpContent后一起发送出去。

收到HttpContent后,我们调用decoder.offer方法对HttpContent进行解码:

decoder.offer(chunk);

解码器中有两个容器用于存储HttpData数据,它们是:

List<InterfaceHttpData> bodyListHttpData和Map<String, List<InterfaceHttpData>> bodyMapHttpData

Decoder.offer是解析chunk,然后把解析后的数据填入bodyListHttpData和bodyMapHttpData。

解析后,可以读取解析后的数据。

可以通过decoder的hasNext和Next方法遍历bodyListHttpData,从而获得对应的InterfaceHttpData。

可以通过data.getHttpDataType()获取InterfaceHttpData的数据类型。如上所述,有两种类型:属性和文件上传。

POST方法上传文件。

如果您想要发布一个文件,客户端可以在创建HttpPostRequestEncoder时传入multipart=true:

HttpPostRequestEncoder bodyRequestEncoder = new HttpPostRequestEncoder(factory, request, true);

然后分别调用setBodyHttpDatas和finalizeRequest方法,生成可以写入通道的HttpRequest:

// 添加body http data bodyRequestEncoder.setBodyHttpDatas(bodylist); // finalize request,判断是否需要chunk request = bodyRequestEncoder.finalizeRequest(); // 发送请求头 channel.write(request);

注意,如果是transfer-encoding = chunked,那么这个HttpRequest只是请求头的信息,我们还需要手动将HttpContent写入通道:

// 判断bodyRequestEncoder是否是Chunked,发送请求内容 if (bodyRequestEncoder.isChunked()) { channel.write(bodyRequestEncoder); }

在服务器端,通过判断InterfaceHttpData的getHttpDataType,如果是FileUpload类型,则表示获取了上传的文件,可以通过以下方法读取文件的内容:

FileUpload fileUpload = (FileUpload) data;responseContent.append(fileUpload.getString(fileUpload.getCharset()));

这样,我们可以在服务器端从客户端获取文件。

摘要

上传HTTP文件要考虑很多问题。如果你不明白,请参考我的例子。或者给我留言讨论。

温馨提示:内容均由网友自行发布提供,仅用于学习交流,如有版权问题,请联系我们。