node.js从入门到菜鸟——资源无法载入?你需要学会地址解析

node.js是什么似乎已经不需要我多为赘述了,非阻塞的服务器语言、JS书写的后台代码,无数的文章已经很好的展示了node的魅力与展望。关于node.js的安装,大家不妨参考博客园聂微东的http://www.cnblogs.com/Darren_code/archive/2011/10/31/nodejs.html (node.js初体验),这篇文章很好的综述了node.js的一个基础(从安装到体验到模块的一个入门,个人感觉是一篇很好的文章),相信通过东哥的这篇文章大家可以对node有一个初步的了解。

node是一门很有意思的框架,它能够让一个长期执迷于前端开发的攻城湿(忘记了还有一种语言叫后端语言。。。)能够觉得很舒适(编码习惯都一样),但是也同样会让一个新手觉得无所适从(为什么么有从入门到精通哩?参考书在哪里???)。这是一个前端高手为之一亮(也许只亮了一眼o(╯□╰)o),新手眼前一晕(if you want to find more information,please read the source(╯□╰)o)的框架。为了让和我一样的新手能够多多少少摸到一点门路,我以身试法,来为新手找一条路~

本文旨在新手入门,所学尚浅,代码水准有限,这也仅仅只是一个基本入门的笔记,高手可以笑一笑然后点关闭了。。。

首先我假设你已经安装好了node(http://nodejs.org/#download,0.6.14已经很成熟了),那么首先我们来进行一个入门的编码分析。

在进行分析之前,我们先来想一下以前的服务器端语言框架的工作原理。首先,用户通过浏览器来访问我们的应用。然后服务器通过对端口的监听,来接收网络端的request请求,并进行相应的处理。最后再将处理的结果返回客户端。

好了,那么我们可以开始了。首先是服务器,要是没有办法启动服务器,那么一切都是闲的。我们也许用过很多服务器端的语言(PHP、JAVA、ASP等等),接收HTTP请求并提供Web页面的过程似乎不用我们来做,apache和IIS似乎都会帮我们来完成。但是在node里,这一步必须你自己做。我们来实现的不仅仅是一个应用,还需要实现HTTP处理的服务器。

好像很复杂的样子,但对于node这并不是什么复杂的东西。我们即将进行一个HTTP服务器的初步学习,但是在学习之前我们需要温习(预习?)一下node的模块机制。

node采取的是模块机制(和JS差不多),通过对模块的导入我们可以声明变量并将导入的模块的实例化对象赋给变量并加以使用。具体各个模块的使用方法以及用途请参考API,这里就不说了。。。

好了,我们回来看看HTTP服务器的构成。首先,我们先对HTTP模块进行一次请求:

var http = require("http");

在node中require方法用于对各个模块的引入,在这里我们需要对http模块加以使用时就可以导入。导入后将之赋予http变量,然后对http变量进行操作。让我们以hello world作为例子:

1 http.createServer(function(request, response) {2   response.writeHead(200, {"Content-Type": "text/plain"});3   response.write("Hello World");4   response.end();5 }).listen(12345,”127.0.0.1”);

每每看到hello world时内心都会有一丝变态的快意。。。

让我们来回忆一下刚才的问题:实现一个http的服务器。其实这个很简单,http模块自带的createServer方法就可以完成。该方法只有一个参数,类型为函数,在接口文档中的定义是“始终接收request事件”。而server.listen方法(server就是刚才通过createServer创建的server)的参数是(port, [hostname], [callback]),第一个是监听的端口号,第二个和第三个是可选项,第二个是主机名称,第三个回调函数。这个函数只在绑定端口后进行调用。

接下来是回调函数,回调函数的参数有两个,第一个是客户端发送的request,第二个是服务器端的response。这段代码进行了一个简单的响应操作。首先是书写了一个响应头,响应头参数包括状态码、原因描述以及头部内容。状态码即http状态码,例如200、404、500之类的。原因描述与头部内容可选,具体的就参见网络报头的书写了,这里就不多说了(其实我也不会。。。)。writehead方法必须写在end方法之前,这个是肯定的。。。

response的write方法就和JS的write所做的工作一样,就是向页面写入数据,虽然原理不尽相同,但目前没有准备去钻研这部分源码的我们可以忽略了。。。最后是end方法,它有两个可选参数,分别是data与encoding。该方法用于所有的响应头与响应正文输出之后,进行响应的终结,并将管道流中的所有响应数据输出。简单地说就是在响应最后加上去的东西,它执行后会将响应执行。如果该方法带有参数,那么就相当于先调用了response.write(data, encoding)方法,之后再调用无参数的end方法。

好了,最简单的一个http服务器已经工作起来了。当用户访问127.0.0.1的12345端口时服务器会监听到这一端口的request请求并书写报头与最简单的helloworld于页面上,用户得到响应之后会在浏览器中显示响应的内容,也就是helloworld。这个最简单的服务器已经搭好了,但我们不能只满足于这一点。

在继续下一步的学习之前,我想给所有没有使用过JS或者不怎么使用的同学大体的讲述一下一个也许你们会略微奇怪的参数传递方法——函数传递。

在JS中,函数与数字、字符串等都是以var定义的,在参数传递的过程中所接受的参数也是var这种弱类型的。而function类型也是作为弱类型传递,当我们将一个函数进行传递时,所得到的不是该函数的返回值,而是这个函数本身。也就是说,这个函数在运行时会变成传递到的函数的本地变量(自己都觉得好乱。。。)。

让我们回忆一下刚才的例子,在creatServer方法中我们使用了一个匿名函数作为参数,现在我们把这个匿名函数提出来:

 1 var http = require("http"); 2 var serverhandel = function(request, response) { 3   response.writeHead(200, {"Content-Type": "text/plain"}); 4   response.write("Hello World"); 5   response.end(); 6 } 7 function serverRequest (){ 8 http.createServer(serverhandel).listen(12345);  9 }10 exports. serverRequest = serverRequest;

exports即module.exports对象,在node中可以作为全局变量的赋予。也就是说它一般用来定义全局变量的,多用于模块间的变量传递。在此我需要简单说一下JS的模块机制,JS中的模块多用闭包进行包裹(我也不知道这么说对不对),而在闭包中定义的局部变量则无法在全局展开使用,也就是说别的地方调用这个模块时不能将其中的局部变量单独的进行使用。而exports则可以在载入模块后将该函数载入全局变量的作用链中。

说到这大家也应该明白了,我们要进行一次模块引用。将这段代码存入serverRequest.js中,然后建立一个index.js文件,然后引用serverRequest模块:

1 var server = require(“./serverRequest”);2 server. serverRequest();

这样我们就进行了一个最基本的小模块的搭建,也初步的了解了一下node的模块体系。那么下一步我们就要进行下连个个非常重要的模块的学习,也就是url模块与path模块。

url模块的作用是从请求中获取请求的url并进行处理,它有着几个常用的方法:

1 url.parse(string).pathname;2 url.parse(string).query;

第一个方法的作用是获取url请求部分的域名之后的路径名称,第二个方法获取的则是通过get向服务器传递的参数。

而path模块的作用是解决文件路径问题,我们这次先学习三个方法:

1 path.extname(p);2 path.join([path1], [path2], [...]);3 path.exists(p, [callback]);

第一个方法是获取扩展名的方法,参数是url路径。第二个方法是做路径拼接使用,用来标准化最终路径,参数是需要拼接的路径。第三个方法是检验路径存在与否,第一个参数是标准化的路径,第二个是可选的回调函数,无论路径存在与否都会被调用,函数有一个exist参数,标示路径是否存在。

好了,现在我们就可以通过这两个模块进行一个简单的路径服务器的搭建了。通过这个服务器的搭建,我们可以对本地的静态网站进行部署,对于页面以及网页所需要载入的各种资源进行寻址,最后对请求的资源进行反馈。

 1 //请求模块 2 var http = require(‘http‘);  3 var url=require(‘url‘);  4 var fs = require("fs"); //在这里先导入文件模块,仅仅做一个简单的操作,具体有关文件模块的学习在之后的文件服务器上会进行进一步的学习。 5 var path = require("path"); 6 //创建一个http服务器 7 var server=http.createServer(start).listen(12345); 8 //依据路径获取返回内容类型字符串,用于http返回头 9 var getContentType=function(filePath){10     var contentType="";11     //使用路径解析模块获取文件扩展名12     var extension=path.extname(filePath);13     switch(extension){14         case ".html":15             contentType= "text/html";16             break;17         case ".js":18             contentType="text/javascript";19             break;20         case ".css":21             contentType="text/css";22             break;23         case ".gif":24             contentType="image/gif";25             break;26         case ".jpg":27             contentType="image/jpeg";28             break;29         case ".png":30             contentType="image/png";31             break;32         case ".ico":33             contentType="image/icon";34             break;35         default:36         contentType="application/octet-stream";37     }38     return contentType; //返回内容类型字符串39 }40 //Web服务器主函数,解析请求,返回Web内容41 var funWebSvr = function (req, res){  42     //获取请求的url43     var url=req.url; 44     //使用url解析模块获取url中的路径名45     var pathName = url.parse(reqUrl).pathname; 46     if (path.extname(pathName)=="") {47         //如果路径没有扩展名48         if (pathName.length<2) {//如果是默认域名49             pathName+="/";50         }51         else{52             pathName+=".html";53         }54     }55     else{56         if (path.extname(pathName)!=".html"){57             pathName=".."+ pathName;58         }59     }60     if (pathName.charAt(pathName.length-1)=="/"){61         //如果访问目录62         pathName+="login.html"; //指定为默认网页63     }64     var filePath = pathName;65     //使用路径解析模块,组装实际文件路径66     if (pathName.charAt(pathName.length).search(/./) == -1) {67         filePath = libPath.join("./html",pathName);68     };69     //判断文件是否存在    70     libPath.exists(filePath,function(exists){71         if(exists){//文件存在72             //在返回头中写入内容类型73             res.writeHead(200, {"Content-Type": funGetContentType(filePath) });74             //创建只读流用于返回75             var stream = libFs.createReadStream(filePath, {flags : "r", encoding : null}); 76             //指定如果流读取错误,返回404错误77             stream.on("error", function() { 78                 res.writeHead(404); 79                 res.end("<h1>404 Read Error</h1>"); 80             }); 81             //连接文件流和http返回流的管道,用于返回实际Web内容82             stream.pipe(res);83         } 84         else {//文件不存在85             //返回404错误86             res.writeHead(404, {"Content-Type": "text/html"});87             res.end("<h1>404 Not Found</h1>");88         }89     });90 }

这是当时对着一篇大牛的博文敲的例子,后来发现只能载入单个网页,而其他资源不能很好的载入,就进行了一次较大的改正,主要添加了对不同pathname的寻址以及载入。本例的css、js以及image文件夹都与页面所在的html文件夹在同一目录下。

相信通过这个例子大家已经能简单的让一个静态网站在我们的服务器上支持起来了。我们下一次将会简单的部署一个文件系统,希望大家能继续关注。新手上道,文章代码写的都比较粗糙,希望大家指正。bye

标签: node.js

好文要顶 关注我 收藏该文

key yao
关注 - 27
粉丝 - 35

+加关注

1

0

(请您对文章做出评价)

« 上一篇:canvas元素简易教程(6)(大部分转自火狐,自己只写了简单的代码分析)
» 下一篇:模拟谷歌今天的包袱做的小玩意

posted @ 2012-03-30 17:32 key yao 阅读(6008) 评论(14) 编辑 收藏

时间: 2024-10-10 06:45:56

node.js从入门到菜鸟——资源无法载入?你需要学会地址解析的相关文章

Node.js开发入门—Stream用法详解

Stream是Node.js中非常重要的一个模块,应用广泛.一个流是一个具备了可读.可写或既可读又可写能力的接口,通过这些接口,我们可以和磁盘文件.套接字.HTTP请求来交互,实现数据从一个地方流动到另一个地方的功能. 所有的流都实现了EventEmitter的接口,具备事件能力,通过发射事件来反馈流的状态.比如有错误发生时会发射"error"事件,有数据可被读取时发射"data"事件.这样我们就可以注册监听器来处理某个事件,达到我们的目的. Node.js定义了R

Node.js开发入门—使用AngularJS

做一个Web应用,一般都有前台和后台,Node.js可以实现后台,利用jade模板引擎也可以生成一些简单的前台页面,但要想开发出具有实际意义的现代Web应用,还得搭配一个Web前端框架. AngularJS是一个JavaScript前端框架,对于Node.js来说是一个完美的客户端库.AngularJS强制使用MVC(模型-视图-控制器,Model-View-Controller)框架,而它又使用JavaScript对象作为它的模型,和Node.js特别般配,用AngularJS的某些服务(比如

Node.js开发入门—Express里的路由和中间件

我们已经基于Express写了HelloWorld示例,还使用express generator工具创建了一个HelloExpress项目,但有一些代码一直没有好好解释,这是因为它们牵涉到路由和中间件等概念,三言两语说不清楚,所以我专门用一篇文章来讲路由和中间件. 路由 通常HTTP URL的格式是这样的: http://host[:port][path] http表示协议. host表示主机. port为端口,可选字段,不提供时默认为80. path指定请求资源的URI(Uniform Res

Node.js开发入门—语音合成示例

出于项目需要,搞了一个语音合成(TTS)的小示例,使用的是OKVoice. 我想在PC上测试,OKVoice的快速接入API可以实现我的目的,文档在这里:http://dev.okvoice.com/file.php. 直接上代码吧,okVoiceTts.js,内容如下: var http = require('http'); var fs =require('fs'); var crypto = require('crypto'); var util = require('util'); va

Node.js开发入门—使用对话框ngDialog

做网站经常会遇到弹出对话框获取用户输入或弹出对话框让用户确认某个操作之类的情景,有一个基于AngularJS的扩展模块可以帮我们优雅地完成这类事情:ngDialog. ngDialog在github上提供了一个示例网页,演示了它的各种用法,在这里:https://github.com/likeastore/ngDialog/blob/master/example/index.html.ngDialog的github主页的readme也对常用的指令和服务做了较为详细的介绍,可以参考.我这篇就纯粹是

Node.js开发入门—Angular简单示例

在"使用AngularJS"中,我们提到了如何在Node.js项目中引入AngularJS,这次提供一个非常简单的示例,演示AngularJS里的指令.数据绑定.服务等内容. 我准备做Web后台管理系统,不同的管理员会有不同的权限,管理员登录后看到的菜单和他的权限有关,能看到什么,是动态生成的(类似RBAC).本文的示例从这个项目而来,当然,现在还是最简单的. 如果没有特别说明,后面我们用到的示例都使用express generator生成. Angular小demo 先搞起来吧. 第

Node.js开发入门—UDP编程

Node.js也提供了UDP编程的能力,相关类库在"dgram"模块里. 与TCP不同,UDP是无连接的,不保障数据的可靠性,不过它的编程更为简单,有时候我们也需要它.比如做APP的统计或者日志或者流媒体,很多流媒体协议都会用到UDP,网上一搜一大堆. 使用UDP,如果你要发送数据,只需要知道对方的主机名(地址)和端口号,扔一消息过去即可.至于对方收不收得到,听天由命了.这就是数据报服务,类似快递或邮件. 我们这次来介绍一下Node.js里的UDP编程,我会提供一个UDP版本的echo

Node.js开发入门—使用http访问外部世界

Node.js的http模块,不但可以构建服务器,也可以作为客户端类库来访问别的服务器.关键就在两个方法: http.request(options[,callback]) http.get(path[,callback]) 除了http,还会用到FileSystem模块和Stream中的stream.Readable和stream.Writable. 先来大概介绍一下相关API吧. API解释 http.request()方法接受一个options参数,这个参数可以是对象,用来指明你要访问的网

Node.js开发入门—套接字(socket)编程

Node.js的net模块提供了socket编程接口,方便我们利用较为底层的套接字接口来实现应用协议.这次我们看一个简单的回显服务器示例,包括服务端和客户端的代码. 使用JavaScript也可以进行套接字编程,哈哈,这酸爽! 代码 分服务器和客户端两部分来说吧. echoServer代码分析 echoServer.js: var net = require("net"); // server is an instance of net.Server // sock is an ins