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

Time:2022-5-18

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

When you first came into contact with an engineering project, you saw that the project console was building. After a while, a URL address suddenly popped up. You click it to open the web page you just wrote. It’s amazing.

When you connect to the back-end partner’s interface, you bring the data, and the interface returns 500 errors to you; You go to the back end and the back end says it can’t pass like this. You don’t know why not. Anyway, after changing according to what he said, it returns to 200 successfully.

Sometimes your request is inexplicably cross domain. The back end says you can handle it by yourself, so you can find a solution. But why cross domain? You don’t know how the backend is configured.

Finally, one day, you learn from the bitter experience and decide to change the past. You must build an HTTP server by yourself and thoroughly sort out the twists and turns in it. From then on, you refuse to be fooled and refuse to be a big soldier who only listens to orders.

But then again, how to start?

Don’t worry, it’s all ready for you. Writing an HTTP server requires a back-end language. Needless to say, node is naturally preferred js。

Next, we are based on node JShttpModule to build a new HTTP server together.

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)

Introduced herehttpModule that providescreateServerMethod, pass in a callback function and create a server.

Now write the code intoindex.js, and then run it super simply:

$ node index.js

Open the browser and enterhttp://localhost:3000, you can see the display of the web pagehello worldYes.

Code analysis

http.createServerThe parameter of the method is a callback function, which has two parameters — they are the core of the HTTP server.

The first parameter is the request objectrequest, the second parameter is the response objectresponse。 You can think of them as two bags, one containing request related data and the other containing response related operations.

requestIt contains detailed request data, that is, the data passed from our front-end interface. Through it, you can get the request header, request parameters, request methods and so on.

responseIt is mainly used to respond to relevant settings and operations. What is response? When I receive the request from the client, I can set the status code to 200 and return it to the front-end data; Or set the status code to 500 and return it to the front-end error.

In a word, what is returned by calling the interface is determined byresponseDecided.

In fact, createserver returns aEventEmitterTherefore, the above wording 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 relevant data of the user initiated request is contained in the request object.

These data include common request methods, request headers, URLs, request bodies and so on.

const { method, url, headers } = request

Method means that the request method can be used directly. Headers returns the request header object, which is also easy to use:

const { headers } = request
Const useragent = headers ['user-agent '] // request headers are all lowercase letters

Only the URL string is not easy to parse. It contains protocol, hostname, path, query and so on.

Fortunately, node JS providesurlandquerystringThe two modules parse the URL string.

URL resolution

Let’s take a look at an example of the URL module:

Const url = require ('url ') // parse URL string
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' }

See,urlThe module can split a complete URL address string into an object containing the attributes of each part.

But the beauty is flawed. Other parts have been resolved, except that query is still a string.

querySecondary parsing is required. What shall I do? This is the second modulequerystringHere we go:

Const querystring = require ('querystring ') // parse query string
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' }

That’s perfect. With the combination of URL + querystring, you can completely parse your URL.

Request body resolution

aboutPOSTperhapsPUTRequest, we need to receive the data of the request body.

The request body here is special. It is not the data transmitted at one time, but throughStreamThe method of streaming is transmitted by streaming, so it should be monitoreddataandendReceive events bit by bit.

The acquisition method is as follows:

server.on('request', (request, response) => {
  let body = []
  request.on('data', chunk => {
    //The chunk here is a buffer
    body.push(chunk)
  })
  request.on('end', () => {
    body = Buffer.concat(body)
  })
  console.log(body.toString())
})

Response settings

When the server receives a client request, it should set how to respond to the client through response.

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

The first isStatus codeFor example, 404:

response.statusCode = 404

What’s moreResponse header

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

FinallyResponder

response. End ('data not found ')

These three parts can also be combined:

response
  .writeHead(404, {
    'Content-Type': 'text/plain',
    'Content-Length': 49
  })
  . end ('data not found ')

Send HTTP request

In addition to accepting the request from the client, the HTTP module can also send the request as a client.

Sending an HTTP request refers to sending an HTTP request on the node JS to request other interfaces to obtain data.

Send request mainly throughhttp.requestMethod.

GET

The following 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 ('status Code: ${res.statuscode} ')
  res.on('data', d => {
    process.stdout.write(d)
  })
  res.on('end', () => {})
})

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

req.end()

Use HTTP After the request is sent, the call must be displayedreq.end()To indicate completion of request sending.

POST

It is basically the same as the above get request. The difference is thatHow is the request body transmitted

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 ('status Code: ${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)) // pass the body parameter writing method

req.end()

Weird place

See here, if you don’t understand nodejs deeply, you may find several strange places.

For example, under normal circumstances, post request deliverybodyThe parameters may be as follows:

Var body = {desc: 'request body parameter'}
var req = http.request({
  path: '/',
  method: 'POST',
  data: body
})

The correct posture mentioned above is as follows:

Var body = {desc: 'request body parameter'}
var req = http.request({
  path: '/',
  method: 'POST'
})
req.write(JSON.stringify(body))

The same is true for the above request body. Can’t pass directlyrequest.bodyGet, you have to:

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

These should be the most confusing places for everyone to understand the HTTP module. In fact, this is not the difficulty of HTTP, but node JSStreamStream specific syntax.

In fact, the core of HTTP module -——requestandresponseAll belong toStream, one is a readable stream and the other is a writable stream.

Therefore, a thorough understanding of the HTTP module requires in-depth understandingStreamFlow related knowledge.

summary

This paper builds a simple HTTP server based on the most basic HTTP module, and implements a simpleReceive requestandSend request

However, real application scenarios generally don’t match like this. The community has mature and stableexpressThe framework is more suitable for writing node JS service; To send a request, you can use the one we are most familiar withaxios——- yes, Axios can also be on node JS.

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

Therefore, the foundation is very important. If the foundation is not firm, the earth will shake and the mountains will shake. Master the HTTP module, even if you see it in expressStreamThe usage of is not unknown, so.

That’s all for this one. Let’s continue to explore the next oneStreamFlow, remember to pay attention to me.

Previous highlights

bookspecial columnIt will output articles on front-end engineering and architecture for a long time, which have been published as follows:

Please support my article if you like it! Also welcome to my column.

Statement:This article is original. If you need to reprint it, please add wechatruidocContact authorization.