服务端JavaScript
JavaScript最早是运行在浏览器上的,浏览器只是提供了一个上下文,它定义了JavaScript可以做什么,并没有指明JavaScript语言本身可以做什么,实际上,JavaScript是一门完整的语言,可以使用在不同的上下文中,要实现在后台运行JavaScript代码,代码需要先被解释然后执行,Node.js的原理就是如此,他使用Google的V8虚拟机来解释和执行JavaScript代码,因此,NodeJs事实上既是一个运行时环境,同时又是一个库。
Node.js的Web应用
一个基础的HTTP服务器
新建一个server.js文件并写入如下代码:
var http = require("http");
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
使用Node.js执行脚本
node server.js
在浏览器访问http://localhost:8888/,可以看到网页。
用这样的代码也可以实现:
var http = require("http");
function onRequest(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
基于事件驱动的回调
var http = require("http");
function onRequest(request, response) {
console.log("Request received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
运行后,会马上在命令行输出“Server has started”,在浏览器输入地址访问后(发出请求),“Request has received.”就会在命令行中出现。
模块化
var http = require("http");
function start() {
function onRequest(request, response) {
console.log("Request received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
我们现在就可以创建我们的主文件 index.js 并在其中启动我们的HTTP了,虽然服务器的代码还在 server.js 中。
创建 index.js 文件并写入以下内容:
var server = require("./server");
server.start();
请求的路由
请求的数据都回包含在request对象,该对象作为onRequest()回调函数的第一个参数传递,为了解析这些数据,我们需要url模块和queryString模块。
url.parse(string).query
|
url.parse(string).pathname |
| |
| |
------ -------------------
http://localhost:8888/start?foo=bar&hello=world
--- -----
| |
| |
querystring(string)["foo"] |
|
querystring(string)["hello"]
改server.js为如下:
var http = require("http");
var url = require("url");
function start() {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
现在我们编写路由,建一个route.js文件如下:
function route(pathname) {
console.log("About to route a request for " + pathname);
}
exports.route = route;
扩展server.js以整合路由:
var http = require("http");
var url = require("url");
function start(route) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
route(pathname);
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
同时,我们会相应扩展index.js,使得路由函数可以被注入到服务器中:
var server = require("./server");
var router = require("./router");
server.start(router.route);
路由给真正的请求处理程序
创建一个requestHandlers模块,并对于每一个请求处理程序,添加一个占位用函数,并导出
function start() {
console.log("Request handler 'start' was called.");
}
function upload() {
console.log("Request handler 'upload' was called.");
}
exports.start = start;
exports.upload = upload;
扩展index.js
var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");
var handle = {}
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;
server.start(router.route, handle);
修改server.js
var http = require("http");
var url = require("url");
function start(route, handle) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
route(handle, pathname);
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
修改route.js
function route(handle, pathname) {
console.log("About to route a request for " + pathname);
if (typeof handle[pathname] === 'function') {
handle[pathname]();
} else {
console.log("No request handler found for " + pathname);
}
}
exports.route = route;
不好的实现方式
让请求处理程序通过onRequest函数直接返回(return())他们要展示给用户的信息。
我们先就这样去实现,然后再来看为什么这不是一种很好的实现方式。
将requestHandler.js修改为如下形式:
function start() {
console.log("Request handler 'start' was called.");
return "Hello Start";
}
function upload() {
console.log("Request handler 'upload' was called.");
return "Hello Upload";
}
exports.start = start;
exports.upload = upload;
同样的,请求路由需要将请求处理程序返回给它的信息返回给服务器。因此,我们需要将router.js修改为如下形式:
function route(handle, pathname) {
console.log("About to route a request for " + pathname);
if (typeof handle[pathname] === 'function') {
return handle[pathname]();
} else {
console.log("No request handler found for " + pathname);
return "404 Not found";
}
}
exports.route = route;
最后,我们需要对我们的server.js进行重构以使得它能够将请求处理程序通过请求路由返回的内容响应给浏览器,如下所示:
var http = require("http");
var url = require("url");
function start(route, handle) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
response.writeHead(200, {"Content-Type": "text/plain"});
var content = route(handle, pathname)
response.write(content);
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
如果我们运行重构后的应用,一切都会工作的很好:请求http://localhost:8888/start,浏览器会输出“Hello Start”,请求http://localhost:8888/upload会输出“Hello Upload”,而请求http://localhost:8888/foo 会输出“404 Not found”。