@yellowhouse
2016-07-20T01:47:14.000000Z
字数 4390
阅读 1345
Node
Node.js,服务器端的JavaScript。相比于Web端操作DOM元素的JavaScript,node.js有自己的特点,如可以直接运行(在后端,无浏览器环境下运行JavaScript代码),这样就需要Google的V8虚拟机来 先解释代码,再正确的执行。
应用要求:
1、用户可以通过浏览器使用我们的应用。
2、当用户请求http://domain/start时,可以看到一个欢迎页面,页面上有一个文件上传的表单。
3、用户可以选择一个图片并提交表单,随后文件将被上传到http://domain/upload,该页面完成上传后会把图片显示在页面上。(并跳转为另一url)
思路:
1、需要一个HTTP服务器提供Web界面。
2、需要一个路由,把请求对应到请求处理程序(requestHandler),根据请求的URL,给与不同的响应。还应该有请求数据处理功能,能够处理POST数据,封装数据
3、需要一个最终请求处理程序,来对被服务器接收并通过路由的请求进行处理。
4、需要视图逻辑请求处理程序,以便将内容发送给用户的浏览器
主文件 index
var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");
var handle = {}
handle["/"] = requestHandlers.start;//将不同的URL都映射到相同的请求处理程序(requestHandlers.start)
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;
server.start(router.route, handle);
HTTP服务器 server貌似这里的start跟requestHandlers的start同名
创建一个叫server.js的文件来保存这部分的代码,首先调用http模块
var http = require("http");
var url = require("url");
function start(route,handle) {//在完成了其他对象的定义后,
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;//处理url,console.log后pathname= /
console.log("Request for " + pathname + " received.");
response.writeHead(200, {"Content-Type": "text/plain"});
var content = route(handle,pathname);//处理完的url交由路由处理,并传入handle对象
response.write(content);//写出请求处理程序的返回值
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;//把start作为module导出给index.js使用
http.creatserver()会返回一个对象(response对象,从服务器的回调函数onRequest()获取,从哪里获取?),有一个叫listen的方法,指定这个HTTP服务器监听的端口号。上面的代码启动了一个会侦听8888窗口的服务器。如果createServer()的参数为空,则这个服务器只会监听窗口,但什么也不会做,甚至不会请求应答。
response 和 request 是对象,可以用来处理HTTP的请求细节,当收到请求时,使用 response.writeHead() 函数发送一个HTTP状态200和HTTP头的内容类型(content-type),使用 response.write() 函数在HTTP相应主体中发送文本“Hello World"。最后,我们调用 response.end() 完成响应。
而为了实现非阻塞式操作,我们需要将response对象作为第三个参数传递给route()函数,并将onRequest()处理程序中所有有关response的函数调都移除,交由route()函数来完成
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);
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
路由 router
我们要为路由提供请求的URL和其他需要的GET及POST参数,随后路由需要根据这些数据来执行相应的代码。而提取出请求的URL以及GET/POST参数这一功能暂定为HTTP服务器的功能。这些数据都包含在onRequest回调函数的参数,request对象里。为了解析这些数据,需要url和querystring模块。现在server里把这些数据整理好后再交由router处理。
exports.route = route;
function route(handle, pathname, response) {
console.log("About to route a request for " + pathname);
if (typeof handle[pathname] === 'function') {
handle[pathname](response);//由于非阻塞式操作,这里就不把请求处理程序返回给它的信息返回给服务器了
} else {//检查给定的路径对应的请求处理程序是否存在(start和upload?——只有/ /start /upload
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;
请求处理程序 requestHandlers
var exec = require("child_process").exec;
function start(response) {
console.log("Request handler 'start' was called.");
exec("find /",
{ timeout: 10000, maxBuffer: 20000*1024 },
function (error, stdout, stderr) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(stdout);
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;
js中函数可以作为其它函数的参数,也就是说,函数和其它变量一样,都是可以被传递的。
function say(word) {
console.log(word);
}
function execute(someFunction, value) {
someFunction(value);
}
execute(say, "Hello");
//当然不一定要先定义后传递,也可以直接定义和传递,由于execute()函数的定义,后面的参数传递给前面的函数,而这个被传递的函数也称作匿名函数
execute(function(word){console.log(word},"hellow")
onrequest是一个回调函数(我们给某个方法传递了一个函数,这个方法在有相应事件发生时调用这个函数来进行 回调,基于事件驱动的回调)
当我们运行时,他会在命令行输出“Server has started.”.当我们向服务器发出请求,命令行中就会出现“Request received.”。这就是事件驱动的异步服务器端JavaScript和它的回调
阻塞与非阻塞
如果在requestHandlers里的start函数,用sleep(10000)延迟10s再返回(或者一些长时间的操作),则在打开两个窗口,同时加载upload start,则两者都要花10s,它阻塞了所有其他的处理工作,即单线程。平常的使用应该尽量使用非阻塞操作。
一般使用child_process模块里的exec()函数来实现非阻塞操作。它从Node.js来执行一个shell命令
function start() {
console.log("Request handler 'start' was called.");
var content = "empty";
exec("ls -lah", function (error, stdout, stderr) {
content = stdout;
});
return content;
}
//获得当前目录下的所有文件(“ls -lah”),并返回,但为了进行非阻塞工作,exec()使用了回调函数,exec()的操作是异步的,意味着在调用exec()之后,Node.js会立即执行 return content 。因此我们的web页面上的内容仍然是empty。一般用函数传递解决(函数回调?)
之前的顺序是请求处理程序 -> 请求路由 -> 服务器,改为将response对象->路由->请求处理程序。 随后,处理程序就可以采用该对象上的函数来对请求作出响应