This is the second day of my participation in Gwen Challenge
preface
A few days ago a new front little sister, and sat next to me, the mother of the solo OF my excited to say nothing!!!!! Today she suddenly asked me: how to use TCP to write an HTTP service, I meng once, thought: this is my performance of the opportunity 😜, and then I will speak.
What is the HTTP
Without further ado, to write an HTTP service you must first understand what HTTP is. HyperText Transfer Protocol (HTTP) is a Protocol specification that must be followed by both parties. HTTP protocol belongs to the application layer protocol, as shown in Figure 1. It is above the transport layer and carries out data transmission based on transport layer TCP and network layer IP protocols.
Figure 1 TCP/IP transport communication protocol hierarchy
HTTP request packets and response packets
Knowing the definition of HTTP, since HTTP is a protocol specification, it must follow some specification for sending and responding, which is called HTTP request (response) messages. So let’s see what’s in the message.
Figure 2 HTTP request packet -1
- As shown in Figure 2, in HTTP request packetsThe first lineWill define
methods
.URL
.The version number
, separated by a space, followed by a newline character\r\n
- The second line starts with the header field, for example
Host
.User-Agent
.Connection
Such header information, each line with a newline character\r\n
The header field ends with an empty line. - After the header field is finished, the body of the message, which is where we normally put our POST request.
Take a look at a real HTTP request header (Figure 3)
Figure 3 HTTP request packet -2
Figure 4 HTTP response packet
Similarly, the HTTP response packet is roughly the same as the request packet, except that the first line contains the version, status code, phrase, and finally the newline \r\n header field and the body of the packet are roughly the same as the request packet. If you want to learn more about TCP (TCP connection three handshake, disconnection four wave), please poke here
How to write an HTTP service (Node) using TCP?
Write an HTTP service in TCP
1. Establish a TCP connection
First we need to create a TCP service with the following code:
import net from 'net';
const server = net.createServer((socket) = > {
socket.write('hello world');
socket.pipe(socket);
socket.end(); // Close the connection
})
server.listen(9999.() = > {
console.log('tcp server running at 9999');
})
Copy the code
At this point, a simple TCP service is set up and tested using Telnet commands
You can see it’s hello World, so it’s half way there, and now when the browser accesses it, it’s going to say, “This is a bad response, because we didn’t follow the HTTP response to return the value.”
2. Return data in the response packet format
Knowing the problem, let’s go back to the format of the HTTP response message and write the return value, according to the message to construct the return value format
import net from 'net';
const server = net.createServer((socket) = > {
socket.write('HTTP/1.1 200 OK\r\ ncontent-type: text/plain\r\n\r\nhello world');
socket.pipe(socket);
socket.end(); // Close the connection
})
server.listen(9999.() = > {
console.log('tcp server running at 9999');
})
Copy the code
We use the browser to open http://localhost:9999, success! It doesn’t get an error, and it returns the same Hello World we typed in the content entity
3. Final encapsulation
The code above basically implements the HTTP service, but this is how the HTTP module in Node creates the service
const http = require('http');
const server = http.createServer((req, res) = > {
res.end('hello world');
})
server.listen('9999');
Copy the code
Wrap the service in this format (the code may be a bit long, but the source address is posted in the end summary).
// index.ts entry file, external exposure method
import net from 'net';
import { formatRequestMessage, IRequestData } from './req';
import { Res, } from './res';
type handle = (req: IRequestData, res: Res) = > void
/** * create function *@param handler function
*/
export const createServer = function(handler: handle) {
const server = net.createServer((socket) = > {
closeConnection(socket);
handleError(socket);
console.log('user connect');
socket.on('data'.(data) = > {
console.log(data.toString());
const req: IRequestData = formatRequestMessage(data.toString());
const res = new Res({ socket });
handler(req, res)
})
});
function closeConnection(socket: net.Socket) {
socket.on('end'.() = > {
console.log('close connection'); })}function handleError(socket: net.Socket) {
socket.on('error'.(err) = > {
console.log(err);
})
}
server.listen('9999'.() = > {
console.log('tcp server running at 9999');
});
}
Copy the code
// req.ts intercepts the request packet
export type IRequestData = {
method: string
url: string
version: string
reqData: string
[key: string] :any
}
/**
* format request data
* @param requestMsg user request http header
*/
export function formatRequestMessage(requestMsg: string) :IRequestData {
const requestArr = requestMsg.split('\r\n');
const [ method, url, version ] = requestArr.splice(0.1) [0].split(' ');
let header: Record<string.any> = {};
let reqData: string = ' ';
let isHeader = true;
for(let x in requestArr) {
if(requestArr[x] ! = =' ' && isHeader) {
const [ key, value ] = requestArr[x].split(':')
header[ key ] = value;
} else if (isHeader) {
isHeader = false;
} else {
reqData += requestArr[x]
}
}
return Object.assign({ method, url, version, reqData, }, header,);
}
Copy the code
Res. ts Response packet processing method
import net from 'net';
type resData = {
version: string
socket: net.Socket
}
interfaceIConstructorData { version? :string
socket: net.Socket
}
export class Res implements resData {
public version: string;
public socket: net.Socket;
constructor({ version, socket, }: IConstructorData) {
this.version = version || 'HTTP / 1.1';
this.socket = socket;
}
private formatSendData(status: number.message: string | number.header: Record<string.any> = {}) :string {
const statusStr = this.getStatusStr(status);
const resHead = `The ${this.version } ${ status } ${ statusStr }`;
let headerStr = ` `;
for (let x in header) {
headerStr += `${ x }: ${ header[x] }\r\n`;
}
return [ resHead, headerStr, message ].join('\r\n');
}
private getStatusStr(status: number) :string {
switch(status) {
case 200: return 'OK';
case 400: return 'Bad Request';
case 401: return 'Unauthorized';
case 403: return 'Forbidden';
case 404: return 'Not Found';
case 500: return 'Internal Server Error';
case 503: return 'Server Unavailable';
default: return 'Bad Request'; }}// Expose the output method
public end(status: number.message: any.options: { header?: {} } = { header: {} }): void {
const resFormatMsg = this.formatSendData(status, message, options.header);
this.socket.write(resFormatMsg);
this.socket.pipe(this.socket);
this.socket.end(); }}Copy the code
At this point, a simple HTTP service is set up to test it out
createServer((req, res) = > {
console.log(req);
res.end(200.'hello world123');
})
Copy the code
The request packet is successfully intercepted and output in the browserhello world123
!
After listening to the little sister, excited of say: too good, I can go back to teach my boyfriend 😄. Me:?? Thought: RNM refund money!!
summary
This article briefly introduces the content of HTTP protocol, and use Node to use TCP service to write an HTTP service, let us have a deeper understanding of HTTP service.
If you find this article helpful, you can give the author a “like”. If you want to learn more about JavaScript or Node, click here. Please point out any inaccuracies or errors in the comments section.
Refer to the article
- The illustration of HTTP
- MDN HTTP