- TCP and HTTP
- HTTP Packet Format
- The request message
- The request line
- Request header
- Request body
- The response message
- Response line
- Response headers
- Response body
- About the url
- About the method
- About the Request Body
- About Status codes
- The 2XX request is normal
- 3XX caching and redirection
- 4XX Client error
- 5XX Server error
- The request message
- Get the request packet from node
- Create an HTTP server and client in Node
- Creating a server
- Create a client
- Response Considerations
- About response entities and Content-Types
- Use TCP to implement a simple HTTP server
- Register the response callback
- Parser separates request packets from transmitting requests
- Parsing request headers
- The demo code
- HTTP other
- The short connection
- pipelines
pre-notify
previously:
TCP is the cornerstone of HTTP. For those who are not familiar with TCP, check out NodeJS and TCP: A Book
This article is mainly for personal knowledge review and will probably be long, So we will copy a table of contents specially at the beginning for the link on the lower right and click the sections to read the preferences (your guys are the guy you guys are)
TCP and HTTP
First, HTTP is based on TCP, and only when a TCP connection is successfully established can the browser client send HTTP requests to the server. (See TCP Three-way handshake for details.)
When TCP allows one PC to connect end-to-end to another, data can be exchanged between the two machines, but this data does not undergo any additional processing. It is pure data, that is, whatever data the user enters, the server gets back.
HTTP is slightly different. An HTTP request wraps the user’s input with the browser and sends it to the server. The wrapped data is called an HTTP request. The server responds to the browser as an HTTP response packet and sends the response to the client.
At the transport level, HTTP is just a subset of TCP, a reencapsulation.
HTTP Packet Format
HTTP packet format is the most intuitive interpretation of HTTP and the most efficient way to learn HTTP.
HTTP packets are divided into two types: request packets and response packets. Request packets and response packets are divided into three parts: line, header, and body. The header and body are separated by blank lines.
The request message
The following image is from Android Web Programming Meditation (2)
The request line
The request line is divided into the following three sections, each separated by a space
- Method: Identifies whether to transmit or retrieve data
- Path: indicates the URL address
- Protocol Indicates the HTTP protocol version
Request header
The request header, unlike the request line, is multiple lines, each of which is a set of key-value pairs separated by colons and Spaces.
- Request header: Host:xxx.com
- Common header: both request and response, for example
Connection:keep-alive
- Entity header: to
Content-
At the beginning of - other
Request body
Seriously, the data the user wants to send to the server
The response message
The following image is from Android Web Programming Meditation (2)
Response line
- Protocol Indicates the HTTP version
- StatusCode status code
- StatusCode -reason indicates the explanation of the statusCode
Response headers
With the request header
Response body
With the request body
About the url
The hash is removed from the URL when the client encapsulates the request (the query is retained).
About the method
GET Obtain resources
POST wants to send data to the server, transmitting the entity body
PUT Transfers files. RESTful operations: Updates or modifies files
HEAD Obtains the packet HEAD
DELETE DELETE a file
OPTIONS queries supported methods. Exploratory methods, such as cross-domain, will first ask the server whether cross-domain is possible
TRACE TRACE path
About the Request Body
When the submitted form contains only one piece of data and the form type is default, the request message looks like this
If there are multiple pieces of data, they are separated by blank lines
However, in the case of multipart/form-data encoding, special delimiters are used to separate the data from each other in the request body
Even a single piece of data is wrapped in a special delimiter
Multiple data segments
About Status codes
There are five main types of status codes
- 1xx imformational(Information status code) Websocket
- 2xx Success
- 3xx Redirect
- 4xx Client Error
- 5xx Server Error
2xx
- 200 OK The data sent by the client is processed normally
- 204 Not Content The response is normal, with no entity
- 206 Partial Content Indicates a Partial Content request. The Content specified by content-range is returned
3xx
- 301 Moved Permanently Redirected Permanently
- 302 Found Temporary redirection does not necessarily go to a different location Nginx
- 303 See Other is similar to 302, but the GET method must be used
- This parameter must be used with (if-match, if-modified-since, if-none_match, if-range, if-unmodified-since)
- 307 Temporary Redirect Temporary redirection without changing the request method
4xx
- 400 Bad Request The syntax of the Request packet is incorrect
- 401 Unauthorized Requires authentication
- 403 Forbidden The server denies access to corresponding resources
- 404 Not Found The resource could Not be Found on the server
5xx
- 500 Internal Server Error The Server is faulty
- 503 Service Unavailable The server is overloaded or is being stopped for maintenance
Get the request packet from node
console.log(req.method); // Request method console.log(req.url); / / url address the console log (the req. HttpVersion); // HTTP version console.log(req.headers); / / request headerCopy the code
Req.on ('data'.function(data){
console.log(data.toString());
})
Copy the code
Create an HTTP server and client in Node
Creating a server
let http = require('http');
let server = http.createServer();
server.on('request'.function(req,res){
res.end('ok');
});
server.listen(8080);
Copy the code
You could you could abbreviate it like this
let http = require('http');
let server = http.createServer(function(req,res){
res.end('ok');
});
server.listen(8080);
Copy the code
Create a client
let http = require('http');
let options = {
host:'localhost'
,port:8080
,method:'POST'
,headers:{
'Content-Type':'application/x-www-form-urlencoded'
// ,'Content-Length':15 // Generally this value is calculated automatically}}let req = http.request(options);
req.write('id=999'); // Only calling end actually sends the request to the server req.end(); // When the client receives a response from the server, req.on('response'.function(res){// Only one argument console.log(res.statuscode); console.log(res.headers);let result = [];
res.on('data'.function(data){
result.push(data);
})
res.on('end'.function(data){
letstr = Buffer.concat(result); console.log(str.toString()); })})Copy the code
You can also write request() and on(‘response’) together, but at this point you can’t actively send data beyond the header to the server (write() can only be called if http.request (opt) returns req).
http.get(options,function(res){
...
res.on('data'.function(chunk){
...
});
res.on('end'.function() {... })})Copy the code
Response Considerations
Unable to continue writing after end (writable stream rule)
res.write()
res.end()
<<<
Erorr::write after end!
Copy the code
After setting the status code, the text description of the status code is automatically completed
res.statusCode = 200; / / the defaultCopy the code
We can not only set, but also remove a response header that is ready to be sent to the client
res.setHeader('Content-Type'.'text/plain');
res.setHeader('name'.'ahhh');
res.removeHeader('name'); // Delete a header that is ready to be setCopy the code
Compared to setHead, writeHead can set multiple headers at the same time, along with the status code. But the biggest difference from setHeader is that writeHeader is sent as soon as it is called.
console.log(res.headersSent) //false
res.writeHead(200,{'Content-Type':'text/plain'}); // When writeHead is set, res.setheader cannot be called because writeHead is sent directly.'name'.'zfpx'); //Can't set headers after they are sent.
console.log(res.headersSent) //true
Copy the code
The setHeader header is not sent until the write method is called. Another important point to note is that the header must be set before the write method is called.
console.log('-- -- -- -- -- -- -- -- --')
console.log(res.headersSent); //false
res.setHeader('name'.'ahhh');
console.log(res.headersSent) //false
res.write('ok');
console.log(res.headersSent) //true
res.end('end');
console.log(res.headersSent) //true
console.log('-- -- -- -- -- -- -- -- --')
Copy the code
About response entities and Content-Types
The content-Type header needs to be set when the client sends a request and when the server replies with a response.
For the server, it needs this header to parse the entity data sent by the client (even though there are many cases where requests have no entity part, such as GET requests).
let buffers = [];
req.on('data'.function(chunk){
buffers.push(chunk);
})
req.on('end'.function() {let content = Buffer.concat(buffers).toString();
if(contentType === 'application/json'){
console.log(JSON.parse(content).name);
}else if(contentType === 'application/x-www-form-urlencoded') {let queryString = require('querystring'); console.log(queryString.parse(content).name); }})Copy the code
In practice, this can be complicated if you have a request body (entity data). (Previous request body)
The content-Type is usually associated with the suffix of the resource file to be returned to the client. So we usually use an NPM package to convert it for us.
.let mime = require('mime'); . res.setHeader('Content-type',mime.getType(filepath)+'; charset=utf-8');
Copy the code
Use TCP to implement a simple HTTP server
The HTTP server actually does one more thing than the TCP server, that is, parse the request header, and the rest of the request body should still listen on data.
But notice, when was the data, the body of the request, sent? Well, it was launched after the request header was separated and parsed.
Register the response callback
// http.createServer(function(req,res){})
server.on('request'.function(req,res){
//do somtheing like you are doing at tcp
}
Copy the code
Parser separates request packets from transmitting requests
let server = net.createServer(function(socket){
parser(socket,function(req,res){
server.emit('request',req,res);
});
});
server.listen(3000);
Copy the code
Here, the separation of the request message refers to the request body and the other two parts (request line, request header) divided into two parts, how to divide? Well, as mentioned earlier, the request body and the request header are separated by a blank line, i.e. \r\n\ R \n or 0x0d 0x0A 0x0d 0x0A.
B: well.. That’s how it works, but there’s a catch.
Socket, as a duplex stream, has the same default read value as normal readable streams when reading data from clients, So, which may cause you to read many times before you get the separator \r\n\r\n.
And we may end up reading \r\n\r\n with some extra data that is not part of the “request header”. We also need to push back the extra data that is part of the request body so that we can get the full request body data when we send the requsET event.
B: well.. Pit more, here will not be ugly paste code, interested partners can achieve the following, there are two points to pay attention to
-
Use readable pause mode to read (in order to push back excess data) when reading
-
It is recommended to use the buffer level 0x0d 0x0A rather than the character level \r\n, because characters may cause garbled characters that are difficult to judge and require more processing.
Parsing request headers
The request header here includes the request line and the request header
function parseHeader(head){
let lines = head.split(/\r\n/);
let start = lines.shift();
let lr = start.split(' ');
let method = lr[0];
let url = lr[1];
let httpVersion = lr[2].split('/') [1];let headers = {};
lines.forEach(line=>{
let col = line.split(':'); Col [0]] = col[1]; });return {url,method,httpVersion,headers};
}
Copy the code
The demo code
Warehouse: Click me click me!
HTTP other
The short connection
Although HTTP is not as persistent as TCP, we said that it is tcp-based and therefore has the ability to persist connections.
The response header usually contains a Connection:keep-alive field to keep the browser connected for a certain amount of time (about, uh, 2 minutes?), even after the response is received.
pipelines
If an HTTP request contains multiple requests, the next request can be sent without waiting.
The number of concurrent requests is about 6 for Chrome and 4 for Firefox.
To be Continue…