12
头图

Front-end er, when do you want to write an HTTP server?

When you first came into contact with an engineered project, you saw that the project console was building. After a while, a URL address suddenly popped up. When you clicked on it, it turned out to be a web page you just wrote. It was amazing.

When you connect to the back-end partner's interface, you bring the data, and the interface returns a 500 error to you; you go to the back-end, and the back-end says that this is not possible. You don't know why it is not. Anyway, change it according to what he said. After that, it returns 200 successfully.

Sometimes your request is inexplicably cross-domain, and the backend says that you can handle it by yourself, so you can find a solution. But why is it cross-domain? You don't know how to configure the backend.

Finally, one day, you learned from the pain and decided to change your past. You must set up an HTTP server yourself, thoroughly sort out the twists and turns, and refuse to be fooled and refuse to be a big soldier who only listens to commands.

But then again, how do you start?

Don't worry, this is all ready for you. Writing an HTTP server requires a back-end language. Needless to say, Node.js is naturally preferred.

Below we build an HTTP server based on the http

http module

An example of a super simple HTTP web server:

const http = require('http')

const server = http.createServer((request, response) => {
  response.statusCode = 200
  response.end('hello world')
})

server.listen(3000)

http module is introduced here, the createServer method is provided, a callback function is passed in, and a server is created.

Now write the code into index.js and run it super simple:

$ node index.js

Open the browser, enter http://localhost:3000 hello world displayed on the web page.

Code analysis

http.createServer method is a callback function, this callback function has two parameters-they are the core of the HTTP server.

The first parameter is the request object request , and the second parameter is the response object response . You can think of them as two bags, one bag contains request-related data, and the other bag contains response-related operations.

request contains detailed request data, which is the data passed by our front-end interface. Through it, you can get request headers, request parameters, request methods, and so on.

response mainly used to respond to related settings and operations. What is a response? I have received a request from the client. I can set the status code to 200 and return the data to the front-end; or set the status code to 500 and return the error to the front-end.

In a word, what the call interface returns is determined by response .

In fact, createServer returns a EventEmitter , so the above writing is equivalent to this:

const http = require('http')
const server = http.createServer()

server.on('request', (request, response) => {
  response.statusCode = 200
  response.end('hello world')
}).listen(3000)

request parsing

The data related to the request initiated by the user is contained in the request object.

These data include commonly used request methods, request headers, url, request body and other data.

const { method, url, headers } = request

method indicates that the request method can be used directly, and headers returns the request header object, which is easier to use:

const { headers } = request
const userAgent = headers['user-agent'] // 请求头全是小写字母

Only the url string is not easy to parse, it contains the protocol, hostname, path, query, etc.

Fortunately, Node.js provides url and querystring parse url strings.

URL parsing

Let's look at an example of the url module:

const url = require('url') // 解析url字符串
var string = 'http://localhost:8888/start?foo=bar&hello=world'

var url_object = url.parse(string)
// { protocol: 'http:', host:'localhost:8888', pathname: '/start', query: 'foo=bar&hello=world' }

As you can see, the url module can split a complete URL address string into an object containing the attributes of each part.

But the fly in the ointment is that other parts are parsed out, except that the query is still a string.

query requires a second analysis. How to do it? At this time the second module querystring out:

const querystring = require('querystring') // 解析query字符串
var string = 'http://localhost:8888/start?foo=bar&hello=world'

var url_object = url.parse(string) // { query: 'foo=bar&hello=world' }
var query_object = querystring.parse(url_object.query)
// { foo: 'bar', hello: 'world' }

It's perfect now. With the combination of url + querystring, you can completely parse your URL.

Request body analysis

For POST or PUT request, we need to receive the data of the request body.

The request body here is special. It is not a one-time transfer of data, but is Stream through the 061a593c7d6858 stream. Therefore, it is necessary to monitor the data and end events to receive a little bit.

The method of obtaining is as follows:

server.on('request', (request, response) => {
  let body = []
  request.on('data', chunk => {
    // 这里的 chunk 是一个 Buffer
    body.push(chunk)
  })
  request.on('end', () => {
    body = Buffer.concat(body)
  })
  console.log(body.toString())
})

response settings

The server receives the client request and needs to set how to respond to the client through response.

Response settings are mainly three parts: status code, response header, and response body.

The first is status code , such as 404:

response.statusCode = 404

Then there is the response header :

response.setHeader('Content-Type', 'text/plain')

Finally, the response body :

response.end('找不到数据')

These three parts can also be combined:

response
  .writeHead(404, {
    'Content-Type': 'text/plain',
    'Content-Length': 49
  })
  .end('找不到数据')

Send http request

In addition to accepting client requests, the http module can also act as a client to send requests.

Sending an http request refers to requesting other interfaces to obtain data in Node.js.

The sending request is mainly realized by the http.request method.

GET

Here is a simple example of sending a GET request:

const http = require('http')
const options = {
  hostname: 'nodejs.cn',
  port: 80,
  path: '/learn',
  method: 'GET'
}

const req = http.request(options, res => {
  console.log(`状态码: ${res.statusCode}`)
  res.on('data', d => {
    process.stdout.write(d)
  })
  res.on('end', () => {})
})

req.on('error', error => {
  console.error(error)
})

req.end()

After using http.request to send a request, it must be displayed to call req.end() to indicate that the request is sent.

POST

GET request is consistent with the above, the difference is to look at request body how to pass :

const http = require('http')
const options = {
  hostname: 'nodejs.cn',
  port: 80,
  path: '/learn',
  method: 'POST'
}

const body = {
  sex: 'man',
  name: 'ruims'
}

const req = http.request(options, res => {
  console.log(`状态码: ${res.statusCode}`)
  res.on('data', d => {
    process.stdout.write(d)
  })
  res.on('end', () => {})
})

req.on('error', error => {
  console.error(error)
})

req.write(JSON.stringify(body)) // 传递 body 参数写法

req.end()

Weirdness

Seeing this, if you don't have a deep understanding of nodejs, you may find a few weird places.

body passed in a POST request under normal circumstances might look like this:

var body = { desc: '请求体参数' }
var req = http.request({
  path: '/',
  method: 'POST',
  data: body
})

And the correct posture mentioned above is this:

var body = { desc: '请求体参数' }
var req = http.request({
  path: '/',
  method: 'POST'
})
req.write(JSON.stringify(body))

The same is true for getting the request body above. It cannot be obtained directly through request.body , it has to be like this:

let body = []
request.on('data', chunk => {
  body.push(chunk)
})
request.on('end', () => {
  body = Buffer.concat(body)
})

These points should be the most confusing place for everyone to understand the http module. Stream , this is not the difficulty of http, but the unique syntax of the 061a593c7d6a83 stream in Node.js.

In fact, the core of the http module- request and response belong to Stream , one is a readable stream and the other is a writable stream.

Therefore, to thoroughly understand the http module, you also need to have a deep understanding of the Stream stream.

Summarize

This article builds a simple HTTP server based on the most basic http module, and implements simple receive requests and send requests .

However, the real application scenarios generally do not match this way. The community has a mature and stable express framework that is more suitable for writing Node.js services; to send requests, you can use the most familiar axios — — Yes, axios can also be used in Node.js.

But you may not know that the core functions of express and axios are based on the http module.

Therefore, the foundation is very important. The foundation is not strong, the ground shakes the mountain. Once you have mastered the http module, even if you see Stream in express, it will not be unclear.

This is the end of this article. In the next article, we will continue to explore the Stream stream, remember to follow me.

Wonderful in the past

This column will long-term output articles on the direction of front-end engineering and architecture, which have been published as follows:

If you like my article, please like and support me! Also welcome to follow my column.

statement: This article is original, if you need to reprint, please add WeChat ruidoc contact for authorization.


杨成功
3.9k 声望12k 粉丝

分享小厂可落地的前端工程与架构