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 definemethods.URL.The version number, separated by a space, followed by a newline character\r\n
  • The second line starts with the header field, for exampleHost.User-Agent.ConnectionSuch header information, each line with a newline character\r\nThe 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

  1. The illustration of HTTP
  2. MDN HTTP