So far, the server we made has no practical use, so we will start to implement some practical and useful functions.
What we need to do is: the user selects a file, uploads the file, and then sees the uploaded file in the browser.
First we need a textarea for the user to enter the content, and then submit it to the server through a POST request.
We add code to the start event handler, and modify requestHandlers.js as follows:
The code copy is as follows:
function start(response) {
console.log("Request handler 'start' was called.");
var body = '<html>'+ '<head>'+
'<meta http-equiv="Content-Type" content="text/html; '+
'charset=UTF-8" />'+
'</head>'+
'<body>'+
'<form action="/upload" method="post">'+
'<textarea name="text" rows="20" cols="60"></textarea>'+
'<input type="submit" value="Submit text" />'+
'</form>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function upload(response) {
console.log("Request handler 'upload' was called.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello Upload");
response.end();
}
exports.start = start;
exports.upload = upload;
You can see the effect by visiting http://localhost:8888/start in your browser.
Next we want to implement the triggering of the /upload request handler to handle the POST request when the user submits the form.
To make the whole process non-blocking, Node.js will split the POST data into many small data blocks, and then pass these small data blocks to the callback function by triggering specific events. The specific events here include a data event (indicating that a new small data block has arrived) and an end event (indicating that all data has been received).
We do this by registering a listener on the request object. The request object here is passed to the onRequest callback function every time an HTTP request is received.
We put the code in the server and modify server.js as follows:
The code copy is as follows:
var http = require("http");
var url = require("url");
function start(route, handle) {
function onRequest(request, response) {
var postData = "";
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
request.setEncoding("utf8");
request.addListener("data", function(postDataChunk) {
postData += postDataChunk;
console.log("Received POST data chunk '"+ postDataChunk + "'.");
});
request.addListener("end", function() {
route(handle, pathname, response, postData);
});
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
The above code does three things: First, we set the encoding format of the received data to UTF-8, and then register the listener for the "data" event to collect new data blocks each time and assign them to the postData variable. Finally, we move the call requesting the route to the end event handler to ensure that it will only fire when all data is received and only fire once. We also pass POST data to request routes, because this data will be used by the request handler.
Next, on the /upload page, display the user input
Let's change router.js:
The code copy is as follows:
function route(handle, pathname, response, postData) {
console.log("About to route a request for " + pathname);
if (typeof handle[pathname] === 'function') {
handle[pathname](response, postData);
} else {
console.log("No request handler found for " + pathname);
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not found");
response.end();
}
}
exports.route = route;
Then, in requestHandlers.js, we include the data in the response to the upload request:
The code copy is as follows:
function start(response, postData) {
console.log("Request handler 'start' was called.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" content="text/html; '+
'charset=UTF-8" />'+
'</head>'+
'<body>'+
'<form action="/upload" method="post">'+
'<textarea name="text" rows="20" cols="60"></textarea>'+
'<input type="submit" value="Submit text" />'+
'</form>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function upload(response, postData) {
console.log("Request handler 'upload' was called.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("You've sent: " + postData);
response.end();
}
exports.start = start;
exports.upload = upload;
The last thing we have to do is: Currently we pass the entire message body of the request to the request routing and request handler. We should only pass the POST data, the part we are interested in, to the request routing and request handlers. In our example, what we are interested in is the text field.
We can use the querystring module introduced previously to implement it:
The code copy is as follows:
var querystring = require("querystring");
function start(response, postData) {
console.log("Request handler 'start' was called.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" content="text/html; '+
'charset=UTF-8" />'+
'</head>'+
'<body>'+
'<form action="/upload" method="post">'+
'<textarea name="text" rows="20" cols="60"></textarea>'+
'<input type="submit" value="Submit text" />'+
'</form>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function upload(response, postData) {
console.log("Request handler 'upload' was called.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("You've sent the text: "+ querystring.parse(postData).text);
response.end();
}
exports.start = start;
exports.upload = upload;
OK, the above is all about processing POST data.
In the next section, we will implement the function of uploading images.