This is the 31st day of my participation in the August Text Challenge.More challenges in August

Introduction to the

In the last article, we talked about how to download files from an HTTP server and how to set up a download file server, using the GET method. This article will discuss the common POST method for submitting data to the server and how to upload files to the server.

The GET method uploads data

According to the HTTP specification, GET is generally used to GET data from the server, although it is not recommended that you use GET to GET data from the server.

Let’s take a look at some of the issues you need to be aware of when building a GET client.

A GET request is essentially a URI followed by the parameters of the request. Netty provides a QueryStringEncoder to build the parameters:

QueryStringEncoder encoder = new QueryStringEncoder(get); // Add request parameters encoder. AddParam ("method", "GET"); encoder.addParam("name", "flydean"); encoder.addParam("site", "www.flydean.com"); URI uriGet = new URI(encoder.toString());Copy the code

With the request URI, we can create an HttpRequest with the HTTP head as well:

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, useful - TW; Q = 0.7, useful - 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")) );Copy the code

We know that HttpRequest has only two pieces of data, HttpVersion and HttpHeaders. HttpVersion indicates the HTTP version number. HttpHeaders indicates the header content.

For GET requests, since all the content is contained in the URI, no additional HTTPContent is required, just send an HttpRequest to the server.

channel.writeAndFlush(request);
Copy the code

Let’s see what happens when the server receives the GET request.

The server receives an HttpObject MSG and converts it to an HttpRequest object. This is done using protocolVersion(), URI (), and headers().

Netty provides the QueryStringDecoder class to parse parameters in urIs:

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"); }}Copy the code

POST uploads data

For A POST request, it has one more HTTPContent than a GET request, meaning a PostBody is required in addition to the basic HttpRequest data.

If the POST contains a file, it will be more complicated. ENCTYPE=”multipart/form-data” is required.

HttpPostRequestEncoder netty provides an HttpPostRequestEncoder class for quickly coding the request body.

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

Multipart indicates whether the format is multipart/form-data. Charset encoding is charsetutil.utF_8 by default. EncoderMode is the encoding mode, currently there are three encoding modes, namely RFC1738, RFC3986 and HTML5.

The default encoding mode is RFC1738, which is how most forms submit data. However, it does not apply to OAUTH. If OAUTH is to be used, RFC3986 can be used. HTML5 disables mixed-mode multipart/form-data.

Finally, let’s talk about HttpDataFactory. The factory is primarily used to create InterfaceHttpData. It takes a minSize parameter, and if the HttpData created is larger than minSize, it is stored on disk, otherwise it is created directly in memory.

InterfaceHttpData has three types of HttpData: Attribute, FileUpload, and InternalAttribute.

Attribute is the Attribute value passed in in the POST request. FileUpload is the file that’s passed in in the POST request, and InternalAttribute is used inside encoder, which we won’t talk about here.

Therefore, Attribute and FileUpload can be divided into the following types based on the size of the minSize parameter passed in:

MemoryAttribute, DiskAttribute or MixedAttribute MemoryFileUpload, DiskFileUpload or MixedFileUpload

PostBody Encoder (PostBody encoder) HTTP Request PostBody Encoder (PostBody encoder)

Request = new DefaultHttpRequest(httpversion.http_1_1, httpmethod.post, uriSimple.toASCIIString()); HttpPostRequestEncoder bodyRequestEncoder = new HttpPostRequestEncoder(factory, request, false);Copy the code

Add headers to request:

// Add headers for (Entry<String, String> Entry: headers) {request.headers().set(entry.getkey (), entry.getValue()); }Copy the code

Then add the form property to the bodyRequestEncoder:

/ / add the form attribute bodyRequestEncoder. AddBodyAttribute (" method ", "POST"); bodyRequestEncoder.addBodyAttribute("name", "flydean"); bodyRequestEncoder.addBodyAttribute("site", "www.flydean.com"); bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed", false);Copy the code

Notice that we added the method,name, and site attributes to the bodyRequestEncoder. Then a FileUpload is added. But because we’re not encoding “multipart/form-data”, we’re just passing the name of the file, not the whole file.

Finally, we call the finalizeRequest method of the bodyRequestEncoder to return the final request to be sent. During finalizeRequest, transfer-encoding is also set to chunked based on the size of the transferred data.

Transfer-encoding = chunked is required for a large amount of data to be transferred in segments. Otherwise, this parameter is not required.

Send the request last:

// Send the request channel.write(request);Copy the code

On the server side, we also need to construct an HttpDataFactory and use this factory to construct an HttpPostRequestDecoder to decode encoder data:

HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); //POST request decoder = new HttpPostRequestDecoder(factory, request);Copy the code

The message received by the server can be either HttpContent or LastHttpContent, depending on the length of the sent message. If it’s HttpContent, we’ll cache the parsed result in a StringBuilder and send it out with LastHttpContent.

After receiving the HttpContent, we call decoder.offer to decode the HttpContent:

decoder.offer(chunk);
Copy the code

Inside decoder there are two containers for storing HttpData:

List<InterfaceHttpData> bodyListHttpData and Map<String, List<InterfaceHttpData>> bodyMapHttpDataCopy the code

Decoder. offer is to parse chunk and populate the parsed data with bodyListHttpData and bodyMapHttpData.

Once parsed, the parsed data can be read.

You can traverse bodyListHttpData through hasNext and next methods of decoder, so as to obtain the corresponding InterfaceHttpData.

Data.gethttpdatatype () can be used to retrieve the data type of InterfaceHttpData. There are two types, Attribute and FileUpload, described above.

The POST method is used to upload files

To POST the file, the client creates the HttpPostRequestEncoder by passing multipart=true:

 HttpPostRequestEncoder bodyRequestEncoder =
                new HttpPostRequestEncoder(factory, request, true);
Copy the code

Call setBodyHttpDatas and finalizeRequest, respectively, to generate an HttpRequest to the channel:

/ / add body HTTP data bodyRequestEncoder. SetBodyHttpDatas (bodylist); / / finalize request, determine whether need the chunk request. = bodyRequestEncoder finalizeRequest (); // Send the request header channel.write(request);Copy the code

Note that if transfer-encoding = chunked, then the HttpRequest is just the request header information, and we also need to manually write the HttpContent to the channel:

/ / determine whether bodyRequestEncoder Chunked, send the request content if (bodyRequestEncoder. IsChunked ()) {channel. Write (bodyRequestEncoder); }Copy the code

On the server side, check the getHttpDataType of InterfaceHttpData. If the type is FileUpload, it indicates that the file is uploaded.

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

This way we can get the file from the client on the server side.

conclusion

HTTP file upload needs to consider more problems, we do not understand can refer to my example. Or leave a comment for me to discuss.

Learn -netty4 for an example of this article

This article is available at www.flydean.com/21-netty-ht…

The most popular interpretation, the most profound dry goods, the most concise tutorial, many tips you didn’t know waiting for you to discover!

Welcome to pay attention to my public number: “procedures those things”, understand technology, more understand you!