Learning node. Building http Server from Zero (2)

  • 2021-07-22 08:44:15
  • OfStack

Preface

In the last article, we learned about the connection and difference between different module specifications. In this article, we officially started the study of node. First of all, we started by building an http server that can run simple programs.

1. hello world

The most classic hello world. First we create an server. js to hold our code:


console.log( 'hello world' );

Enter at the terminal node server.js Running:


node server.js

The terminal will output the words hello world. However, we have an node server program, which is always accessed on the browser. Here, we will use the http module that comes with node:


var http = require('http'); //  Introduce http Module 

//  Create http Server 
// request :  Request information brought from browser 
// response :  Information returned from the server to the browser 
http.createServer(function(request, response){
 response.writeHead(200, {'content-type': 'text/plain'}); //  Set header information and output text Text 
 response.write('hello world'); //  Information Output to the Page 
 response.end(); //  Return to End 
}).listen(3000);
console.log('server has started...');

We enter again at the terminal node server.js Run, there will be output in the terminal server has started… To indicate that the server is created and running, and then we visit 127.0. 0.1: 3000 on the browser, and we can see that hello world is output on the page.

2. form form

Just now, we just output a simple piece of text on the page. Now we want to present a form on the page, which allows the user to enter information and submit it:


// server.js
var http = require('http');

http.createServer(function(request, response){
var html = '<html>\
 <head>\
 <meta charset=UTF-8" />\
 </head>\
 <body>\
 <form action="/" method="post">\
 <p>username : <input type="text" name="username" /></p>\
 <p>password : <input type="password" name="password" /></p>\
 <p>age : <input type="text" name="age" /></p>\
 <p><input type="submit" value="submit" name="submit" /></p>\
 </form>\
 </body>\
 </html>';

 response.writeHead(200, {'content-type': 'text/html'}); //  Output html Header information 
 response.write(html); //  Will be spliced html String output to the page 
 response.end(); //  End 
}).listen(3000);
console.log('server has started...');

Modify the contents in server. js and rerun:


node server.js

After refreshing the page, we found that three text boxes and one submit button were output in the page. Because our program only renders the page and does nothing else, submitting data in the page simply refreshes the current page.

Note: Every time we modify any code in node, we have to restart.

2.1 Get the data submitted by form GET

We use POST in the above code, but we should first discuss the data submitted by GET. We don't consider the security of data first, but learn how to obtain the form form data submitted by get, change post to get, and run it again.

We know that submitting data by get will pass the data as URL parameters, so we get the data by parsing the parameters in URL, and here we use the method in url module:


// server.js
var http = require('http'),
url = require('url');

http.createServer(function(request, response){
 var html = '<html>\
 <head>\
 <meta charset=UTF-8" />\
 </head>\
 <body>\
 <form action="/" method="get">\
 <p>username : <input type="text" name="username" /></p>\
 <p>password : <input type="password" name="password" /></p>\
 <p>age : <input type="text" name="age" /></p>\
 <p><input type="submit" value="submit" name="submit" /></p>\
 </form>\
 </body>\
 </html>';
 
 var query = url.parse( request.url, true ).query;
 if( query.submit ){
 var data = '<p><a href="/" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >back</a></p>'+
 '<p>username:'+query.username+'</p>'+
 '<p>password:'+query.password+'</p>'+
 '<p>age:'+query.age+'</p>';
 
 response.writeHead(200, {'content-type': 'text/html'});
 response.write(data);
 }else{
 response.writeHead(200, {'content-type': 'text/html'});
 response.write(html);
 }
 response.end(); //  End 
}).listen(3000);
console.log('server has started...');

After we run the submission again, we can display the data in the page.

url.parse Is used to parse the URL string and returns the parsed URL object. If we only output 1 url.parse(request.url) :


url.parse(request.url);

result:
Url {
 protocol: null,
 slashes: null,
 auth: null,
 host: null,
 port: null,
 hostname: null,
 hash: null,
 search: '?username=111113&password=123&age=122&submit=submit',
 query: 'username=111113&password=123&age=122&submit=submit',
 pathname: '/',
 path: '/?username=111113&password=123&age=122&submit=submit',
 href: '/?username=111113&password=123&age=122&submit=submit'
}

If the second parameter is set to true, the query attribute in the returned result will be resolved to one object, and other attributes will remain unchanged; The default value is false, which means that the query property is a string:


url.parse(request.url, true);

result:
Url {
...
query: {
 username: '111113',
 password: '123',
 age: '122',
 submit: 'submit' },
...
}

Therefore, we can judge whether there is submitted data through the following statement, obtain the submitted data, and then output it to:


var query = url.parse( request.url, true ).query;
/*
{
 username: '111113',
 password: '123',
 age: '122',
 submit: 'submit'
}
*/

2.2 Get the data submitted by form POST

Now we use post to submit data. Because POST Request 1 is generally "heavy" (users may enter a large amount of content), if processed in a blocking way, it will inevitably lead to the blocking of user operations. Therefore, node splits post data into many small data blocks, and then passes these small data blocks through data events (indicating that new small data blocks have arrived) and end events (indicating that all data has been received). Therefore, our thinking should be to get data blocks in data events and manipulate data in end events.


// server.js
var http = require('http'),
querystring = require('querystring');

http.createServer(function(request, response){
 var html = '<html>\
 <head>\
 <meta charset=UTF-8" />\
 </head>\
 <body>\
 <form action="/" method="post">\
 <p>username : <input type="text" name="username" /></p>\
 <p>password : <input type="password" name="password" /></p>\
 <p>age : <input type="text" name="age" /></p>\
 <p><input type="submit" value="submit" name="submit" /></p>\
 </form>\
 </body>\
 </html>';
 
 if( request.method.toLowerCase()=='post' ){
 var postData = '';

 request.addListener('data', function(chunk){
 postData += chunk;
 });

 request.addListener('end', function(){
 var data = querystring.parse(postData);
 console.log( 'postData: '+postData );
 console.log(data);
 
 var s = '<p><a href="/" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >back</a></p>'+
 '<p>username:'+data.username+'</p>'+
 '<p>password:'+data.password+'</p>'+
 '<p>age:'+data.age+'</p>';

 response.writeHead(200, {'content-type': 'text/html'});
 response.write(s);
 response.end();
 })
 }else{
 response.writeHead(200, {'content-type': 'text/html'});
 response.write(html);
 response.end();
 }
}).listen(3000);
console.log('server has started...');

The main changes between this code and the previous code project are:

Instead of introducing url module, introduce querystring Module. Because we no longer operate on URL, there is no need to introduce it. Use request.method.toLowerCase()=='post' Judging whether there is data submission at present; Splicing data in data event and processing in end event; response.end() Is written inside the end event, because the end event is an asynchronous operation, so the data output must be completed before it can be executed response.end()

As we can see in the console, postData is a string like this:


node server.js
0

So we use query.parse Resolve postData to an object type to get the submitted data.

3. Routing

Now all our logic is done in the root directory, not according to url. Here we split the route according to function. Taking the above post request as an example, we can split it into page initialization and processing after form submission.

Page initialization:


// starter.js  Page initialization 

function start(request, response){
 var html = '<html>\
 <head>\
 <meta charset=UTF-8" />\
 </head>\
 <body>\
 <form action="/show" method="post">\
 <p>username : <input type="text" name="username" /></p>\
 <p>password : <input type="password" name="password" /></p>\
 <p>age : <input type="text" name="age" /></p>\
 <p><input type="submit" value="submit" name="submit" /></p>\
 </form>\
 </body>\
 </html>';
 
 response.writeHead(200, {"Content-Type":"text/html"});
 response.write( html );
 response.end();
}
exports.start = start;

Show the acquired data:


// uploader.js  Show the acquired data 
var querystring = require('querystring');

function upload(request, response){
 var postData = '';

 request.addListener('data', function(chunk){
 postData += chunk;
 });
 
 request.addListener('end', function(){
 var data = querystring.parse(postData);
 console.log( 'postData: '+postData );
 console.log(data);

 var s = '<p><a href="/" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >back</a></p>'+
 '<p>username:'+data.username+'</p>'+
 '<p>password:'+data.password+'</p>'+
 '<p>age:'+data.age+'</p>';

 response.writeHead(200, {'content-type': 'text/html'});
 response.write(s);
 response.end();
 })
}
exports.upload = upload;

Then route in server. js


node server.js
3

If we change the URL address at will, we will see the pathname of each address output (ignore/favicon. ico):


node server.js
4

Therefore, we route according to pathname and map the route by method:


node server.js
5

If the route/is matched, execute node server.js0 ; If Route/show is matched, execute uploader.upload(request, response) . If none match, 404 is displayed.

4. Upload and display pictures

We have been able to submit the data successfully above, and here we will explain how to upload and display pictures. It is very troublesome to use node's own module to deal with it. Here we use formidable module which has been developed by others to write it, which makes a good abstraction for analyzing uploaded file data.


node server.js
6

In starter. js, we added the file control:


// starter.js
function start(request, response){
 var html = '<html>\
 <head>\
 <meta charset=UTF-8" />\
 </head>\
 <body>\
 <form action="/upload" method="post" enctype="multipart/form-data">\
 <p>file : <input type="file" name="upload" multiple="multiple" /></p>\
 <p><input type="submit" value="submit" name="submit" /></p>\
 </form>\
 </body>\
 </html>';

 response.writeHead(200, {"Content-Type":"text/html"});
 response.write( html );
 response.end();
}
exports.start = start;

4.1 Picture Upload

The first thing we do is upload pictures. First, we must make sure that tmp and img directories exist in the current directory.

In uploader. js:


// uploader.js
var formidable = require('formidable'),
util = require('util'),
fs = require('fs');

function upload(request, response){
 if( request.method.toLowerCase()=='post' ){
 var form = new formidable.IncomingForm();

 form.uploadDir = './tmp/';
 form.parse(request, function(err, fields, files) {
 var oldname = files.upload.name,
 newname = Date.now() + oldname.substr(oldname.lastIndexOf('.'));
 fs.renameSync(files.upload.path, "./img/"+newname ); //  Upload to  img  Directory 

 response.writeHead(200, {'content-type': 'text/plain'});
 response.write('received upload:\n\n');
 response.end(util.inspect({fields: fields, files: files}));
 });
 return;
 }
}
exports.upload = upload;

After uploading the picture, we jump to the upload path and display the corresponding information:


node server.js
9

When we look at the img directory again, we will find the photos we just uploaded.

4.2 Picture Display

After uploading the picture to the server, how can I display the picture on the browser? Here we use the fs module to read the file and create an shower. js to show pictures:


// shower.js
var fs = require('fs'),
url = require('url');

function show(request, response){
 var query = url.parse(request.url, true).query,
 imgurl = query.src;

 //  Read the picture and output it 
 //  Here read the src Parameter that specifies which picture to read  /show?src=1484234660592.png
 fs.readFile('./img/'+imgurl, "binary", function(err, file){
 if(err) throw err;
 response.writeHead(200, {"Content-Type": "image/png"});
 response.write(file, "binary");
 response.end();
 })
}
exports.show = show;

Then add the route mapping of show to server. js:


var routeurl = {
 '/' : starter.start,
 '/upload' : uploader.upload,
 '/show' : shower.show //  Add 
};

Finally, the picture is quoted in upload. js:


form.parse(request, function(err, fields, files) {
 var oldname = files.upload.name,
 newname = Date.now() + oldname.substr(oldname.lastIndexOf('.'));
 fs.renameSync(files.upload.path, "./img/"+newname ); //  Upload pictures synchronously 

 response.writeHead(200, {'content-type': 'text/html'});
 var s = '<p><a href="/" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >back</a></p><p><img src="/show?src='+newname+'" /></p>'; //  Show the picture just now 
 response.write(s);
 response.end();
});

5. Synthesis

Just now, I learned to upload data and pictures. Here, we synthesize them and draw up a topic: "Set the user name and password, and upload the avatar". I hope I can achieve 1 by myself.

6. Implementation of the interface

Having studied the GET and POST requests in Part 2, writing a simple json or jsonp interface should not be difficult here.

Create 1 inter. js:


// inter.js
var url = require('url');

function init(request, response){
 if( request.method.toLowerCase()=='get' ){
 var query = url.parse(request.url, true).query;

 var data = {"code":0, "msg":"success", "data":[{"username":"wenzi", "age":26}, {"username":"bing", "age":25}]};
 if( query && query.callback ){
 // jsonp
 response.end( query.callback + '(' + JSON.stringify(data) + ')' );
 }else{
 // json
 response.end( JSON.stringify(data) );
 }
 }
}
exports.init = init;

Add references and routing mappings for inter to server:


var routeurl = {
 '/' : starter.start,
 '/upload' : uploader.upload,
 '/show' : shower.show,
 '/inter' : inter.init //  Add 
};

Then make an json request or an jsonp request to http://127.0.0.1: 3000/inter.

To provide you with a Chinese address for inquiring API: https://pinggod.gitbooks.io/nodejs-doc-in-chinese/content

Summarize

Ok, that's all the content of this article. This section still writes a lot of content. The core is to explain how to build a simple http server to submit and process data and pictures. At the end, I talked a little about the compilation of the next interface. If there is an opportunity later, I will explain the compilation of the next interface in detail. I will share the file operation of node with you below. Please continue to pay attention to this site.


Related articles: