All of my articles are collected in this article, and will be updated in time: Knowledge is long, the road of the walker will end in no words (My Programming Road)

Zero, preface,

No matter what language, what system, are inseparable from the network, this series to in-depth network is the first to coerse the Lord to make the Http, it holds the lifeblood of the whole network. Everyone must obey it.

This paper mainly focuses on
DNS addressing (domain name resolution) 2. TCP/IP three-way handshake to establish the connection 3. 4. Obtain free SSL certificate from Tencent Cloud, and set HTTPS support based on SpringBoot2Copy the code

Note: The server code for this article is already on Github, if not basic, see my SpringBoot Entry-level series:

If you don’t want to touch the back end, you can also read this article, but it will be somewhat lacking in understanding, after all, HTTP is a matter of client and server, and it is not realistic to look at it from the other side.


1. Domain name resolution

When you type a web address into Chrome and press Enter, the browser will find the server address based on the domain name

Take my website, http://www.toly1994.com/, for example


0. Url Description: Uniform Resource Locator

Before I do that, a quick word about urls

The base URL contains the pattern (or protocol), server name (or IP address), path and file name, protocol: // User name: password @ subdomain name. Domain name Top-level domain name: port number/directory/file name. File suffix? Parameter = value # flag.Copy the code


1. Resolve domain names –Chrome searches its OWN DNS cache

To find the corresponding IP address according to the domain name:

chrome://net-internals/#dns


2. Resolve the domain name — View the DNS cache on the local server

If 1 is not available, check the DNS cache on the local machine, ipconfig/displayDNS


3. Resolve the domain name — Check whether the host file has the corresponding URL IP address

If 2 does not, check whether the host file has a corresponding address, C:\Windows\System32\drivers\etc


4. Resolve the domain name — external query

If no information is displayed in the first three steps, the DNS cache of the website does not exist on the local server. The DNS cache of the website is queried by the server of the broadband carrier

If there is no cache, it will search level by level until it finds the server corresponding to toly1994.com (my server) and finally returns the server IP address to the browser that just typed the url


Second, the client and the server establishTCP/IPConnection:

In order to simple, use http://www.toly1994.com:8080/swords/21

When the client accesses the server, the first step is to query the IP address of the domain name (i.e. where the server lives).


0. TCP packets

It’s a little ugly on the Internet, and I’ve drawn it here, and there’s a summary of TCP/IP,

Two control bits are recognized here: SYN and ACK

SYN: synchronous Sequence number (the Synchronize Sequence Numbers), when the connection is established using | - when the SYN = 1, ACK = 0, says this is a request to establish a connection message; | - when the SYN = 1, the ACK = 1, said the other party agreed to establish a connection. | - SYN = 1, this is a or agreed to establish a connection to establish the connection request message. SYN is set to 1 only in the first two handshakes. ACK: Acknowledge serial number sign (Acknowledgment) : Whether the preceding Acknowledgment field is valid. | - only when the ACK = 1, the confirmation number in front of the field is valid. The value 0 indicates that the packet does not contain acknowledgement information and the acknowledgement number field is ignored. | - TCP regulation, after the connection is established, the ACK must be 1.Copy the code


1. First handshake:Ask if the server is available

The client sends a packet with SYN=1 and SEq =J(J is a random number) to the server

When the server sees SYN=1, it knows that the client is requesting a connection


2. Second handshake:The server says

The server sends the SYN=1,ACK=1, SEq =K(K is a random number),ACK= J+1 packet to the client

When the client sees SYN=1 and ACK =J+1, it knows that the server is calling it back


3. Third handshake:The client says I'm still here

The client sends ACK=1 and ACK= K+1 packets to the server

When the server sees ack=K+1, it knows that the client received the message

This creates a solid TCP/IP connection


Send request and receive response and four waves

Now that the server and client have established a connection, the next step is to request and respond. Before that, let’s take a look at Chrome’s web-related tools


1. The request


2. The server receives the request

Requests are sent by the client, which is the Chrome browser program. See upgrade-insecure Requests for details

The client sends its own situation and requested things to the server using the request header, and the server finds resources based on the request header

| - version resource path HTTP request way GET/swords/HTTP / 1.1 | 21 - the request of the server domain name + port Host: 192.168.10.104:8080 | Connection - the Connection parameters: Keep alive - | - Cache Control parameters cache-control: Max - age = 0 | - Upgrade - not safe - request: Upgrade - Insecure - Requests: | 1 - a User Agent: tell the server status the user-agent: Mozilla / 5.0 (Windows NT 10.0; WOW64) AppleWebKit / 537.36 (KHTML, like Gecko) Chrome / 70.0.3538.110 Safari / 537.36 | - this time request file types can receive the Accept: text/html,application/xhtml+xml,application/xml; Q = 0.9, image/webp image/apng, * / *; Q = 0.8 | - statement client support type of Encoding the Accept - Encoding: gzip, deflate | - statement of browser support Language Accept - Language: useful - CN, useful; Q = 0.9Copy the code

3. Receive the response

Chrome’s debugging tool shows that it’s already been processed, not as it is, so let’s take a look at it here, and we’ll see the native later,

The server sends a response to the client, and the client performs the next action based on the response


4. Four waves


5. Several levels (not deep yet)


Four, deep request and response

You can’t debug Chrome enough here, use PostMan for requests, use Fiddler for packet capture,

The basic use is very simple, just install it. The following test carefully look, this is often used after a lot of Internet or is too abstract, or is too one-sided, here to put some messy point

By default, all network requests are displayed on the left. You can filter them like this:


1.GET: The simplest request:

http://192.168.10.104:8080/swords/21

Request:
GET http://192.168.10.104:8080/swords/21 HTTP / 1.1 cache-control: no - cache Postman - Token: E72160d9-48db-4933-8c10-e0157c0f86db User-Agent: PostmanRuntime/7.4.0 Accept: */* Host: 192.168.10.104:8080 Accept-encoding: gzip, Deflate Connection: keep-aliveCopy the code
Response:

Notice that there is a blank line between the response header and the response body (data)

The content-Length field is important because it represents the size of the response body (data) in bytes (as shown below)

The content-type HTTP / 1.1 200: application/json. charset=UTF-8 Date: Fri, 01 Feb 2019 04:56:35 GMT Content-Length: 406 {"id":21,"name":"Excalibur","info":"Excalibur is the legendary sword that King Arthur of Britain received from the Nymph of the Lake. Forged by the elves in Avalon, the sword was cast in gold and the hilt was studded with gems. And because of its blade very sharp, "" imgurl" : "http://localhost:8080/imgs/timg.jpg", "create_time" : "the 2018-07-17 T08: each. 000 + 0000", "modify_time" : "20 18-07-17T08:29:36.000+0000"," Origin ":" King Arthur "}Copy the code

2.GET: Add request parameters (params) to the request:

Above is the last level, the parameter as the url is a Restful writing standards Here, the request parameters in the url, the url is not itself written specification, and the above basic makes no difference: http://192.168.10.104:8080/swords/id? id=21

Request:
GET http://192.168.10.104:8080/swords/id? Id =21 HTTP/1.1 cache-control: no-cache Postman-token: b7d97A6f-4c97-4651-8ccF-16541e24747c user-agent: PostmanRuntime/7.4.0 Accept: */* Host: 192.168.10.104:8080 Accept-Encoding: gzip, Deflate Connection: keep-aliveCopy the code
Response:
The content-type HTTP / 1.1 200: application/json. charset=UTF-8 Date: Fri, 01 Feb 2019 05:35:24 GMT Content-Length: 406 {"id":21,"name":"Excalibur","info":"Excalibur is the legendary sword that King Arthur of Britain received from the Nymph of the Lake. Forged by the elves in Avalon, the sword was cast in gold and the hilt was studded with gems. And because of its blade very sharp, "" imgurl" : "http://localhost:8080/imgs/timg.jpg", "create_time" : "the 2018-07-17 T08: each. 000 + 0000", "modify_time" : "20 18-07-17T08:29:36.000+0000"," Origin ":" King Arthur "}Copy the code

3.POST: Add request parameters (params) to the request

With GET: Request parameters (params) are added to the request. The only difference is the request method

Use THE POST+ request parameter, the parameter is still in the URL, but not in plain text. Note the difference between the POST form, where the request contains a request body, and the POST+ request parameter, which does not have a request body, and the parameter is still passed through the URL

POST http://192.168.10.104:8080/api/sword? Name = with heavenly sword & imgurl = http://192.168.10.104:8080/imgs/oQttHzCOUqeOatEH.jpg&info= sword, heaven and earth to open the giant & origin = sunny the HTTP / 1.1 towering cache-control: No-cache Postman-token: C60f5455-8263-4928-a2b3-278af9d198fd User-agent: PostmanRuntime/7.6.0 Accept: */* Host: Token: C60f5455-8263-4928-a2B3-278af9d198fd 192.168.10.104:8080 cookies: JSESSIONID = 8 b28a94404ef579b0e246ecd7fd04056 accept - encoding: gzip, deflate the content - length: 0 Connection: keep-aliveCopy the code
Response:
The content-type HTTP / 1.1 200: application/json. charset=UTF-8 Date: Mon, 03 Feb 2019 15:00:35 GMT Content-Length: 227 {" code ": 200," MSG ":" successful ", "data" : {" id ": 70," name ":" qing heavenly sword ", "info", "heaven and earth sword, from the giant", "imgurl" : "http://192.168.10.104:8080/imgs/oQttH Zcouqeoateh.jpg ","create_time":null," MODIfy_time ":null," Origin ":" tianqingren "}}Copy the code

4.POST: Form submission

We’ve all filled out forms, such as the login screen, and forms are submitted by post

This is where the Body is useful, and you can pass some extra data to the server. The advantage of this is that you don’t have to expose the data to the URL. Note how the table data is sent:

Request:
POST http://192.168.10.104:8080/api/sword HTTP / 1.1 cache-control: no - cache Postman - Token: Cf6cb7e3-e66d-4339-9685-54f46af7db12 User-Agent: PostmanRuntime/7.6.0 Accept: */* Host: 192.168.10.104:8080 Cookie: JSESSIONID=8B28A94404EF579B0E246ECD7FD04056 accept-encoding: gzip, deflate content-type: multipart/form-data; boundary=--------------------------789466732494020503103134 content-length: 567 Connection: keep-alive ----------------------------789466732494020503103134 Content-Disposition: form-data; Name = "name" with heavenly sword -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 789466732494020503103134 Content - Disposition: the form - data; Name = "imgurl" http://192.168.10.104:8080/imgs/oQttHzCOUqeOatEH.jpg -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 789466732494020503103134 Content-Disposition: form-data; Name = "info", "heaven and earth sword, from the giant -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 789466732494020503103134 Content - Disposition: the form - data; Name = "origin" sunny asked -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 789466732494020503103134Copy the code
Response:
The content-type HTTP / 1.1 200: application/json. charset=UTF-8 Date: Mon, 04 Feb 2019 05:00:35 GMT Content-Length: 227 {" code ": 200," MSG ":" successful ", "data" : {" id ": 70," name ":" qing heavenly sword ", "info", "heaven and earth sword, from the giant", "imgurl" : "http://192.168.10.104:8080/imgs/oQttH Zcouqeoateh.jpg ","create_time":null," MODIfy_time ":null," Origin ":" tianqingren "}}Copy the code

5.POST- form upload file

Note the format requested for the file upload here, and compare it to the form above

Request:
POST http://192.168.10.104:8080/upload HTTP / 1.1 cache-control: no - cache Postman - Token: C12cd0dc-fbcd-4726-9c97-ebacc6498d26 User-Agent: PostmanRuntime/7.4.0 Accept: */* Host: 192.168.10.104:8080 Accept-encoding: gzip, deflate Content-type: multipart/form-data; boundary=--------------------------131785098353427999614106 content-length: 345 Connection: keep-alive ----------------------------131785098353427999614106 Content-Disposition: form-data; name="file"; Filename =" ying long. TXT "content-type: text/plain When the thunder wind will rain, should take fuyao into the cloud. -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 131785098353427999614106Copy the code
Response:
HTTP / 1.1 200 the content-type: text/plain. Charset = utF-8 content-Length: 24 Date: Fri, 01 Feb 2019 06:53:03 GMTCopy the code

6.POST- Pass native data

That is, the request on the client side carries additional native data on the request (below), which the server can get

Request:

The data in the visible request body is also one line away from the request header

POST http://192.168.10.104:8080/postString HTTP / 1.1 cache-control: no - cache Postman - Token: Content-type: text/plain user-agent: PostmanRuntime/7.4.0 Accept: */* Host: On the other side of the sea there is something I have never witnessed -- the creation of godCopy the code
Response:

In the server, I’m going to return the data as it is, but you can also process it and return it

HTTP / 1.1 200 the content-type: text/plain. Charset = utF-8 content-Length: 53 Date: Fri, 01 Feb 2019 06:19:52 GMTCopy the code

7. Post-binary

Notice the difference between passing binary files and form passing files, native data

| – POST – binary file format with primary data, because be binary stream, can pass any data | – POST – binary files and form can upload files upload a file, but the request body is completely different

Request:
POST http://192.168.10.104:8080/PostFile HTTP / 1.1 cache-control: no - cache Postman - Token: Content-type: Text /plain user-agent: PostmanRuntime/7.4.0 Accept: */* Host: 192.168.10.104:8080 Accept-encoding: gzip, deflate Content-Length: 137 Connection: After two years of swimming in a small pool, he has washed away a few idle dust of the world. When the thunder wind will rain, should take fuyao into the cloud.Copy the code
Response:
HTTP / 1.1 200 the content-type: text/plain. charset=UTF-8 Content-Length: 7 Date: Fri, 01 Feb 2019 07:28:35 GMT SUCCESSCopy the code

For PUT,DELETE equals request and POST are basically the same, so I won’t say much


8. Relearn the form

Here is a simple form with an unoptimized interface to see how multiple fields are requested

Maybe you’ll have a better understanding of forms and a better idea of how to upload multiple files

POST http://192.168.10.104:8080/submit_form HTTP / 1.1 Host: 192.168.10.104:8080 Connection: keep alive - Content - Length: 626 cache-control: Max - age = 0 Origin: http://192.168.10.104:8080 Upgrade - Insecure - Requests: 1 the content-type: multipart/form-data; A boundary = - WebKitFormBoundary7Mqt2T4cA2gNVkCa the user-agent: Mozilla / 5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml; Q = 0.9, image/webp image/apng, * / *; Q = 0.8 Referer: http://192.168.10.104:8080/add_form Accept - Encoding: gzip, deflate the Accept - Language: useful - CN, useful; Q = 0.9 -- -- -- -- -- - WebKitFormBoundary7Mqt2T4cA2gNVkCa Content - Disposition: the form - data; Name = "name" Remus excalibur -- -- -- -- -- - WebKitFormBoundary7Mqt2T4cA2gNVkCa Content - Disposition: the form - data; Name = "info" sword product -- -- -- -- -- - god WebKitFormBoundary7Mqt2T4cA2gNVkCa Content - Disposition: the form - data; Name = "origin" bite "-- -- -- -- -- - WebKitFormBoundary7Mqt2T4cA2gNVkCa Content - Disposition: the form - data; name="file"; Filename =" ying long. TXT "content-type: text/plain When the thunder wind will rain, should take fuyao into the cloud. ------WebKitFormBoundary7Mqt2T4cA2gNVkCa--Copy the code

How to use request headers

That’s a lot of request and response formats, now let’s talk about what they’re useful for

Think of it this way: the browser sends the request to the server, and the phone can act as the client, which is essentially the same as the browser. The server doesn’t distinguish between the browser and the phone, it just recognizes the request header and responds to it

1. The mobile phone posts a string to the server

The client uses the socket to connect to the server and sends the request header to the server through the output stream of the socket

The server sees the request header and responds accordingly, in this case the request header 4-6

** @param IP IP address * @param port Port */ private void connServer(String IP, Int port) {String header = "POST http://192.168.10.105:8080/postString HTTP / 1.1 \ n" + "cache-control: no-cache\n" + "Postman-Token: e532e186-4a4c-4a9f-82bb-8045b1cd9403\n" + "Content-Type: text/plain\n" + "User-Agent: PostmanRuntime/7.4.0\n" + "Accept: */*\n" + "Host: 192.168.10.105:8080\n" + "accept-encoding: Gzip, deflate\n" + "content-length: 53\n" + "Connection: keep-alive\n" + "\n" +" MSocket = new Socket(IP, port); // create a client Socket object (IP, port). MPwOut = new PrintWriter(msocket.getOutputStream (), true); //2. //3. Obtain the byte output stream from the socket object mpwout. write(header); } catch (IOException e) { e.printStackTrace(); }finally { mPwOut.close(); }} | - Android is used in the new Thread (() - > {connServer (" 192.168.10.105 ", 8080); }).start();Copy the code

2. Processing on the server

The input stream is obtained through HttpServletRequest and the request body is obtained

You can define operations such as save, transform and so on based on the input stream

---->[SwordController#postString]---------------------------------- @PostMapping("/postString") public String postString(HttpServletRequest request) { ServletInputStream is = null; try { is = request.getInputStream(); StringBuilder sb = new StringBuilder(); byte[] buf = new byte[1024]; int len = 0; while ((len = is.read(buf)) ! = -1) { sb.append(new String(buf, 0, len)); } System.out.println(sb.toString()); return sb.toString(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (is ! = null) { is.close(); } } catch (IOException e) { e.printStackTrace(); } } return null; }Copy the code

3. Upload binary files

The request header is 4-7, and this is where you upload an image to the server

/** * @param IP IP address * @param port Port */ private void connServerPostFile(String IP, int port) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.pic_22); ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] datas = baos.toByteArray(); The String header = "POST http://192.168.10.105:8080/PostFile HTTP / 1.1 \ n" + "cache-control: no - the cache \ n" + "Postman - Token: 607a26e6-9c84-4b6b-97e9-3f539cf9a150\n" + "Content-Type: text/plain\n" + "User-Agent: PostmanRuntime/7.4.0\n" + "Accept: */*\n" + "Host: 192.168.10.105:8080\n" + "accept-encoding: gzip, deflate\n" + "content-length: " + datas.length + "\n" + "Connection: keep-alive\n" + "\n"; MSocket = new Socket(IP, port); // create a client Socket object (IP, port). mOs = mSocket.getOutputStream(); mOs.write(header.getBytes()); mOs.write(datas); } catch (IOException e) {e.printStackTrace(); } finally { try { mOs.close(); } catch (IOException e) { e.printStackTrace(); }}}Copy the code

In other words, the server only recognizes the request and serves it when the header is correct.

Like staff dining hall, tube you zhang 3 Li 4, have the work card can canteen to provide a meal service. Network framework HttpURLConnection,okHttp bottom layer is necessary to these encapsulation


4. UnderestimateokHttpSplicing of forms

OkHttp also pieces together forms according to the Http request format specification

Wouldn’t it be better to be aware of what your request is going to look like when using okHttp?

public final class MultipartBody extends RequestBody { public static final MediaType MIXED = MediaType.get("multipart/mixed"); public static final MediaType ALTERNATIVE = MediaType.get("multipart/alternative"); public static final MediaType DIGEST = MediaType.get("multipart/digest"); public static final MediaType PARALLEL = MediaType.get("multipart/parallel"); public static final MediaType FORM = MediaType.get("multipart/form-data"); --->private static final byte[] COLONSPACE = {':', ' '}; --->private static final byte[] CRLF = {'\r', '\n'}; --->private static final byte[] DASHDASH = {'-', '-'}; --->private final ByteString boundary; Private final MediaType originalType; private final MediaType contentType; private final List<Part> parts; private long contentLength = -1L; MultipartBody(ByteString boundary, MediaType type, List<Part> parts) { this.boundary = boundary; this.originalType = type; this.contentType = MediaType.get(type + "; boundary=" + boundary.utf8()); this.parts = Util.immutableList(parts); }... public static final class Part { public static Part create(RequestBody body) { return create(null, body); } public static Part create(@Nullable Headers headers, RequestBody body) { if (body == null) { throw new NullPointerException("body == null"); } if (headers ! = null && headers.get("Content-Type") ! = null) { throw new IllegalArgumentException("Unexpected header: Content-Type"); } if (headers ! = null && headers.get("Content-Length") ! = null) { throw new IllegalArgumentException("Unexpected header: Content-Length"); } return new Part(headers, body); Public static Part createFormData(String name, String value) {return createFormData(name, null, String value); RequestBody.create(null, value)); } public static Part createFormData(String name, @Nullable String filename, RequestBody body) { if (name == null) { throw new NullPointerException("name == null"); } ---> StringBuilder disposition = new StringBuilder("form-data; name="); appendQuotedString(disposition, name); if (filename ! = null) { disposition.append("; filename="); appendQuotedString(disposition, filename); } Headers headers = new Headers.Builder() ---> .addUnsafeNonAscii("Content-Disposition", disposition.toString()) .build(); return create(headers, body); }... } public static final class Builder { private final ByteString boundary; private MediaType type = MIXED; private final List<Part> parts = new ArrayList<>(); public Builder() { this(UUID.randomUUID().toString()); } public Builder(String boundary) { this.boundary = ByteString.encodeUtf8(boundary); } /** * Set MIME type */ public Builder setType(MediaType type) {if (type == null) {throw new NullPointerException("type == null"); } if (! type.type().equals("multipart")) { ---> throw new IllegalArgumentException("multipart ! = " + type); } this.type = type; return this; }... }}Copy the code

6. Make your website support Https

1. Access the console


2. Obtain the certificate


3. Fill out a form


4. Download the certificate


5. Configure the SpringBoot project

After the configuration is complete, package and go online


Effect of 6.

OK, so now you can access it over HTTPS, but I don’t want to go into that

This post is quite long, I will leave the response code of cache and server to the next post.


Postscript: Jie wen standard

1. Growth record and Errata of this paper
Program source code The date of The appendix
V0.1, The 2018-3-12 There is no
V0.2, The 2018-3-19 Add four waves

[-http -]

Jiwen link: juejin.cn/post/684490…

2. More about me

Pen name | | QQ WeChat | — – | — – | — – | — – | packer fierce | 1981462002 | jet zdl1994328 |

My github: github.com/toly1994328

I’m Jane books: www.jianshu.com/u/e4e52c116… I’m Jane books: www.jianshu.com/u/e4e52c116… Personal website: www.toly1994.com

3. The statement

1—- This article is originally written by Zhang Fengjie, please note if reproduced

2—- welcome the majority of programming enthusiasts to communicate with each other 3—- personal ability is limited, if there is something wrong welcome to criticize and testify, must be humble to correct 4—- see here, I thank you here for your love and support