Node.js笔记

一,

forEach不支持break发现break后面的还是会执行,就老老实实用for遍历了。

 

二,

sys.puts:简单地打印在日志中给定的字符串。

console.log:如果你想打印更复杂的对象(数组,JSON的JSObject),你必须使用console.log

 

三,

通常在网上看到安装是使用的这种方式 npm install connect,即 npm install <name>。那为什么只是给了name它就能安装,安装地址在哪啊?

install文档中提到了 a<name>@<version> that is published on the registry with (c)

那就看以下registry 的说明,文档下方SEE ALSO中有链接

可以看出名称是由它来解析的,那地址在哪了,下面还有一句

我们再看一下config(1) 链接,查看config文档,它就是一个全局设置,文档中有下面这段话:

registry

Default: https://registry.npmjs.org/

Type: url

The base URL of the npm package registry.

 

看到这个默认地址了吧,就是从这来的。这个就是官方地址:

The official public npm registry is athttp://registry.npmjs.org/, It is powered by a CouchDB database at http://isaacs.iriscouch.com/registry.

四,

模版引擎 ejs  : Embedded (嵌入的)JavaScript

 

五,

当通过http://localhost:8100访问时, 会转到index.js,而index.js而index.ejs传递了title和users对象作为参数。

 

六,

package.json文件

  此文件是项目的配置文件(可定义应用程序名,版本,依赖项等等)

  node_modules文件夹下的依赖项是从哪里知道的呢?原因就是项目根目录下的这个package.json文件,执行npm install时会去此文件中的dependencies,并安装指定的依赖项。

 

 

 

 

 

 

七,

views文件夹,用于存放模版文件

 

八.

下载:supervisor

npm install -g supervisor

         随后直接利用supervisor方式运行程序:

supervisor app.js

         以后项目之中,每一次文件的改变,那么都可以及时的监听到,同时也可以及时加载新的代码文件,对于开发是非常方便,但是有一点不方便:每一次修改的时候如果代码有错,后台会一直报错。

 

九,

npm install <name>安装nodejs的依赖包

例如npm install express 就会默认安装express的最新版本,也可以通过在后面加版本号的方式安装指定版本,如npm install express@3.0.6

npm install <name> -g 将包安装到全局环境中

但是代码中,直接通过require()的方式是没有办法调用全局安装的包的。全局的安装是供命令行使用的,就好像全局安装了vmarket后,就可以在命令行中直接运行vm命令

npm install <name> --save 安装的同时,将信息写入package.json

项目路径中如果有package.json文件时,直接使用npm install方法就可以根据dependencies配置安装所有的依赖包

这样代码提交到github时,就不用提交node_modules这个文件夹了。

npm init  会引导你创建一个package.json文件,包括名称、版本、作者这些信息等

npm remove <name>移除

npm update <name>更新

npm ls 列出当前安装的了所有包

npm root 查看当前包的安装路径

npm root -g 查看全局的包的安装路径

npm help  帮助,如果要单独查看install命令的帮助,可以使用的npm help install

*******************************************************************************

 

Request

个我总结:只要记住 只要是有关于客户端请求的信息,都可以藉由它来取得,例如请求标头、请求方法、请求参数、使用者IP等等信息。

3.什么情况下为响应?什么情况下为请求?

简单一句话,请求就是好像你向某个为借东西,响应就是他把这个东西借给你!!!

[JSP] JSP中的隐藏对象 -- request- -

request告,就可以在JSP网页中使用,在转译为Servlet之后,它会转换为javax.servlet.http.HttpServletRequest型态的对象,HttpServletRequest对象是有关于客户端所发出的请求之对象,只要是有关于客户端请求的信息,都可以藉由它来取得,例如请求标头、请求方法、请求参数、使用者IP等等信息。

request的主要方法:

getParameterNames():取得客户端所发出的请求参数名称.

getParameter():可以让您指定请求参数名称,以取得对应的设定值.

getServerName():请求的服务器.

getProtocol():使用协议.

getMethod():请求方法.

getServerPort():请求端口号.

getContextPath():Context路径. context理解为上下文比较好(也就是一个项目)

getServletPath():Servlet路径.

getRequestURI():URI路径.

getQueryString():查询字符串.

getRemoteAddr():使用者主机IP.

getRemotePort():使用者使用端口号.

  例子:

http://localhost:8080/myjsp/requestdemo.jsp?name=john&nick=johncn

  对应的信息为:

  请求的服务器: localhost 

  使用协议:HTTP/1.1 

  请求方法:GET 

  请求的端口号: 8080 

Context路径:/myjsp 

Servlet路径:/requestdemo.jsp 

URI路径:/myjsp/requestdemo.jsp 

  查询字符串: name=john&nick=johncn 

  使用者主机IP127.0.0.1 

  使用者使用端口号: 1060 

response

[JSP]JSP中的隐藏对象 -- response- -
JSPresponse隐藏对象在转换为Servlet之后,对应于HttpServletResponse型态对象,HttpServletResponse对象是有关于对客户端请求之响应,您可以利用它来设定一些要响应的讯息,例如标题信息、响应状态码等.
response的常用方法:
setHeader():是一个通用的标头设定方法,您可以用它来设定任何「名称/值」的标头.
setIntHeader():是专门用来设定整数值标头的版本.
setDateHeader():setHeader()Date设定版本,第二个参数是设定DateLong数值,0表示GMT1970/1/1 00:00
(Note:以上3个函数用来设置HTTP协议的表头,必须对HTTP协议有些了解才能正确使用,我现在也不清楚).
setStatus():是用来设定回应的状态码,例如404 Not FoundHttpServletResponse类中提供了一些助忆常数设定,例如SC_NOT_FOUND就是表示404状态码(可以在ServletAPI文件中查询相关的助忆常数).
sendError():会根据服务器的预设错误网页回报方式显示错误讯息.
sendRedirect():设置重定向页面.
getWriter():取得PrintWriter对象,由它来写出响应至服务器的本体信息.


1.输出文本和HTML代码
利用的是response提供的Write()方法
Response.Write("peterbbs");
Response.Write("< br />");
输出换行符号
string table ="<table border=1>........";
Response.Write(table);//Output html



2.
输出图像
Response
输出图像是通过输出该图像的二进制数据实现的实现方法BinaryWrite();
具体方法:
(1)
将图像的虚拟地址转换为物理地址
(2)
定义文件流读取二进制数据并保存
(3)
调用方法BinaryWrite()
(4)
设置当前的Web窗体页的输出格式为“image/pjpeg”,此格式只能输出文件后缀名".jpg"的图像
(5)
调用Response对象的End()方法,中止页面的其他输出。

        string path =Request.MapPath("~/image.gif");
        FileStream fs = newFileStream(path,FileMode.Open,FileAccess.Read);
        byte[] imageData = newbyte[(int)fs.Length];
        fs.Read(imageData, 0,(int)fs.Length);
        Response.BinaryWrite(imageData);
        Response.End();//
使用这个东西的时候,你会发现你再response的任何write方法都失效了


3.
页面间的跳转
这里我就不写了,在我的BAIDU空间里有关于新窗口的response.redirect的方法


4.
页面间的参数传递
直接就response.redirect("######.aspx? id =10"); 就可以了,需要记住这个格式,很固定的。
获取传递过来参数就直接调用Request.Param就可以获取这个值了


 

其它问题:

1.JSP中,request是不是HttpServletRequest的一个实例?  
          response是不是HttpServletResponse的一个实例?  
        若是,我就不理解了,HttpServletRequest不是接口吗?接口怎么会有实例呢?   
        若不是,request/response它是哪个类的实例呢?

requestHttpServletRequest的一个子类的实例,这么说很含糊,事实上这个具体类根据不同的服务器是不同的,但是这些具体类都implementHttpServletRequest接口。因为无法确定具体是哪个类,所以request只能说与javax.servlet.http.HttpServletRequest对应。你可以在不同的服务器下使用相同的Jsp页面,在其中嵌入<%=request.getClass()%>看看

request对象与javax.servlet.http.HttpServletRequest类对应,  
  response对象与javax.servlet.http.HttpServletResponse对应

2.Request对象获取客户提交的汉字字符时,会出现乱码问题,必须进行特殊处理。解决方法是在需要接收request对象内容的页面加一句
request.setCharacterEncoding("GB18030");
这里的GB18030是根据你自己的页面编码来决定的。

3.什么情况下为响应?什么情况下为请求?

简单一句话,请求就是好像你向某个为借东西,响应就是他把这个东西借给你!!!

 

*******************************************************************************Nodejs学习笔记(四):ejs模板布局 layout

1.如果不愿意使用默认的layout.ejs,可自行指定。例如:

res.render("index",{"title":"test","layout":"main"});
// 
res.render("index",{"title":"test","layout":"main.ejs"});

2. 如果不愿意使用layout,则可以设置layoutfalse,例如

res.render("index",{"layout":false});

3. 如果不想每个请求都单独设置一次。可以使用全局设置: 

app.set("view options",{                                                                                          
    "layout":false
});

4. ejs 里,默认的闭合标记是 <%  .. %>,我们也可以定义自己的标签。例如:
 

app.set("view options",{                                                                                  
   "open":"{{",                                                                                  
   "close":"}}"
});

5. 局部布局

web应用中,经常会需要重复显示某个内容,例如:用户评论功能,需要重复显示出每一条用户的评论,这个时候,我们可以通过循环来实现。但是也可以使用【局部模版】(
partial
)来实现。例如:

首先我们建一个局部的模版 ./views/comment.ejs

<div class="comment_item">                                                          
    <div class="comment_user"><%=comment.user%></div> 
    <div class="comment_content"><%=comment.content%></div> 
</div>

注意:这里是
comment.xxxx

然后在./views/index.ejs中,通过partial调用comment

this is <%=title%>!                                                          
<br/>                                                          
<%- partial("comment", comments)%>

注意:这里是
partial(“comment.ejs”,comments);

最后是在router中,调用index.ejs


app.get("/",function(req,res){                                                  
    res.render("index",{"title":"test","layout":false,"comments":[                                                  
        {"user":"gainover","content":"test1"},                                                  
        {"user":"zongzi","content":"test2"},                                                  
        {"user":"maomao","content":"test3"}                                                  
    ]});                                                  
});

注意:代码里的
comments
index.ejs comments变量名称一致,而partial所调用的comment.ejs中,则采用 comment 的单数形式



在列表显示时,我们通常会遇到的场景是,对第一个元素或者最后一个元素加以特殊显示。在partial中,我们可以通过express内置的变量来判断当前对象是否是第一个元素或者最后一个元素,例如:


<div class="comment_item<%if(firstInCollection){%> firtitem <%}%>"> 
    <div class="comment_user"><%=comment.user%></div> :                             
    <div class="comment_content"><%=comment.content%></div>                         
</div>

这样第一条评论的 class 里就会多一个firstitem

类似的内置变量还有:
firstInCollection
 如果是数组的第一个元素,则为true
indexInCollection
 当前元素在数组里的索引 
lastInCollection
 如果是数组的最后一个元素,则为true
collectionLength
 数组的长度

最后是partial调用模版时的路径查找问题:

partial(“edit”) 会查找同目录下的edit.ejs文件。
partial(“../message”)
 会查找上一级目录的message.ejs文件。
partial(“users”)
会查找users.ejs文件,如果不存在users.ejs, 则会查找 /users/index.ejs文件。

<%= users %> 会对内容进行转义,想不转义,可以用 <%- users %>

 

1.EJS简要介绍.

EJS(Embedded JavaScript templates),是一个JS的模板引擎.

EJS快贴入门教程

npm ejs

 

2.如何使用EJS.

使用默认的<%= 变量 %>就能输出变量了.

 

3.如何在node.js中向EJS模板发送数据?

方法1:

 res.render('viewName',{"key":"value","key":"value"},callback);

方法2:

 res.local.key = "value";

 res.local.key = "value";

 res.render('viewName');

 

4.在给EJS模板传值时,必须要将模板里的所有变量都传值,否则会报错,如何解决?

可以用try catch 来监视是否有变量.

例如EJS模板如下.

<% try{ %>

   <%= key1%>

<%}catch(e){}%>

<% try{ %>

   <%= key2%>

<%}catch(e){}%>

复制代码

传入:

res.render('viewName',{"key1":"w3cfuns"});

复制代码

是不会报错的. 如果有更加好的,希望在下面留言哈.

 

5.EJS 中的<%= key %> 与 <%- key%>的区别?

<%= key %> 会把key转义(escape),

例如 key 如果是 <h1>title</h1>

就会输出 <h1>title</h1>

 

这样的话,对于那些比如想插入动态生成html元素的话很不友好.可以用<%- key %>来实现.

<%- key %> 不会转义  就会在html文档中插件h1元素.

 

6.如果实现模板的分离布局(layout)?

使用 <% include viewName %>

<% include head %>

<h1>Title</h1>

<p>My page</p>

<% include foot %>

复制代码

 

7.客户端如何使用ejs?

请参见node_module/EJS下的客户端文件.

 

8.EJS 只能渲染数据吗?

no,EJS其实提供了一种动态改变html文件的方法,不只是动态改变html里面的数据,还可以是样式,行为.例如:

<header class=<%= className %>>

  iam header

</header>

复制代码

在渲染的时候,就能传入想要的类名,实现样式的改变.当然还有很多巧用的方法,多多实践即可.

 

9.EJS如何动态生成列表?

<ul>

<% for(var i  = 0; i < list.length; i++){%>

 <li><%= list[i]%></li>

<%}%>

</ul>

复制代码

 

10.EJS,jade...对比.

我个人觉得EJS还行吧,一是能直接用别人的代码,复制过来就能用了,网上都是html格式的,不用费力去改写为jade这种简洁形式的.二是,能实现基本的数据渲染对我来说就够了吧.也不是太复杂.

***********************************************************************

 

学习 Node.js 的 6 个步骤

 发布于 4-2015:25  3835 次浏览

从刚接触Node.js到现在,自己也是一路摸滚打爬过来的,虽不说是什么高手,但对于如何学习Node.js,还是有一些个人见解,拿出来与大家共勉~

 

学习Node.js大致有 6 个步骤或者说 6 个层次:

 

第一步

 

对于刚接触Node.js的新手来说,第一步无非是打好基础,你需要弄明白以下事情:

 

JavaScript 的特性和语法。假如你对JavaScript 还不熟悉的话,推荐书籍及链接:

JavaScript 推荐书籍列表

深入理解JavaScript系列

Node.js 是什么?Node.js与JavaScript的区别是什么?

Node.js的优点?Node.js的缺点?

Node.js适用场景?Node.js不适用的场景?

Node.js的基本语法。Node.js的特性:

单线程

异步 IO

事件驱动

npm 是什么?npm的基本使用

REPL

等等

其实上面的内容,大部分Node.js的书籍都有介绍。基本了解了Node.js后,我们可以写一些 hello world 的程序:

 

搭建一个 HTTP 服务器,返回 hello, world 。(使用 HTTP 模块)

读取一个 txt 文件,将内容显示到命令行中。(使用 fs 模块)

等等

第二步

 

你也许想,Node.js 只有那些少得可怜的核心模块能做什么呢?别担心,npm 上目前有近 7W 的第三方模块,月下载量高达 2.1亿(2014—4—20 数据)... 这才是 Node.js 的活力所在。当你对Node.js已经了解的差不多了,并且按耐不住跃跃欲试了。这个时候,我们不妨用 Node.js 的第三方模块做些好玩的事情:

 

搭建一个微博网站

搭建一个博客网站

搭建一个在线聊天室

写一个简单的爬虫

调用一些网站的API做一些好玩的东西

等等

但是,并不是说 Node.js 只能做以上事情,几乎其他语言能做的事情 Node.js 都能做,而且有些情况下能做的更好。

 

第三步

 

当然,就像学 js 也不能只会用框架一样,学习 Node.js 也不能只会用外部模块。这个时候,我们需要回头深入了解下 Node.js 核心模块的用法。说白了,就是好好看 Node.js 官方 API 文档。看文档是码农必备技能,英语不好的童鞋浏览器装个划词翻译的插件。

 

第四步

 

多实践。不管是用核心模块还是外部模块,尝试用 Node.js 解决某个问题或者替换掉以前用其他语言写过的代码。

读源码。这里说的读源码并不是说上来就去读 Node 或者其他较大的框架的源码。这个时候,挑一些简单的只实现某个特定功能的工具模块的源码读,这种模块的代码通常在几百行,阅读起来并不是很困难,但是却能涨不少的姿势。比如:

underscore (学习 JavaScript 的语法和技巧)

等等

第五步

 

坚持第四步。在使用 Node.js 时发现没有合适的模块选择或者选择的模块功能不尽人意,这个时候你可以尝试去创建一个模块或者修改现有的模块,并且使用 npm 发布自己的模块或者去该模块的 GitHub  上提 PR 。

 

第六步

 

多实践。这个就不用解释了

读 Node 源码及较大的框架的源码。提高必备

多关注下 GitHub 上的牛人

重复第1-6步

PS:贯穿始终的是买几本 Node.js 的书读,推荐《深入浅出Node.js》。

 

分享到微博

17 回复

yingjie0904yingjie0904 1楼•4-21 10:36

《深入浅出Node.js》确实不错,推荐,,

 

qiangzhiqiangzhi 2楼•4-21 12:09

确实应该理论+实践的学习

 

think2011think2011 3楼•4-21 13:37

《深入浅出Node.js》支持!~

 

panawangpanawang 4楼•4-21 18:59

超级赞,楼主总结的太棒了。这里Node的源码应该指的是JS部分吧, C++那部分对于JS同学可是超级吃力也没有太大意义的哟,除非你有计划或需要开发一些addon

 

borisyuborisyu 5楼•4-22 13:44

领教

 

usherwongusherwong 6楼•4-22 14:27

大赞,话说是看着楼主教程入门的。

 

jiyinyiyongjiyinyiyong 7楼•4-22 18:17

取消制定了, 文章在 Wiki 里放了个链接 :)

-> nodeclub Wiki/论坛精华帖

 

JeffwanJeffwan 8楼•4-26 17:14

最近一直在看LZ的github学习nodeJS开发,非常棒!会继续按照楼主的说的六步练习,其实任何语言也无外乎这几步,关键是坚持下去

 

yorkieyorkie 9楼•4-26 19:40

+1

 

CarlosRenCarlosRen 10楼•4-27 16:28

推荐《nodejs入门经典》 + 《深入浅出nodejs》楼主好建议 我现在处于阶段2  请问简单的博客跟爬虫哪能找到好点的例子呢?

 

yaochunyaochun 11楼•4-27 20:33

归根到底还是多实践,多写bug

 

SansuSansu 12楼•6-12 14:12

推荐《nodejs开发指南》,不过里面的实例用的nodejs版本太低了

 

Finebyme1Finebyme1 13楼•6-12 15:02

《深入浅出node.js》是不错,比较详细,讲了很多实质性的内容。目前还没看过其它书,接下来准备找个《node.js实战》来看看,不知道怎么样。有没有看过的朋友,发表下意见?

 

yiwei1223 yiwei1223 6-12 21:59

由于本人是新手,买了一本《Node实战》目前正在看!!书中以实例项目驱动为主!比较符合楼主所说的第二部学习步骤!比较适合已经基本掌握了Node一些基本的API而想要进一步进阶的小伙伴!!

 

http://jiafeifei.weebly.com/blog/nodejs-1

 

………………………………………………………………………………………………….

【一起学node.js (一)】用node+express搭建多人博客[转]  

2013-11-25 14:56:40|  分类: nodejs|举报|字号 订阅

【转】http://cnodejs.org/topic/515b009a6d38277306192e4e

学习node有一段时间了,作为新手,我也深知大部分初学者被node资料的匮乏和express2.x3.x的差异搞的死去活来,于是我决定把建站的经验拿出来与大家分享,有不正确的地方望您指正(第一次发教程,大家轻喷啊)。
学习前提:windows下安装node0.10.0+express3.1.0+,有一定node+express+ejs的基础者,推荐看完《node.js开发指南》再来看本教程。

好了,我们进入正题。
首先我们要在D盘根目录下建个blog文件夹作为我们的工作目录,打开cmd切到D盘,输入express-e ejs blog(注意express3.x中安装ejs不再是-t而是-e,可以输入express-h查看),然后输入cdblog&npm install安装所需模块,安装完成后输入node app,在浏览器里输入localhost:3000,如下所示:

注意:接下来你也可以选择安装supervisor,这里不再多述。
第一个博客建成了,但它有点简单,我们来建一个稍微复杂的博客。实现以下功能:

/:首页
/login:登录
/reg:注册(允许多人注册,如何建个人博客另作介绍)
/post:发表文章
/logout:登出

未登录前:主页左侧导航显示homeloginregister,右侧显示已发表的文章,见下图
登陆后:主页左侧导航显示homepostlogout,右侧显示已发表的文章,见下图
用户登录、注册、发表成功以及退出后都返回到主页。效果图如下
用户登陆前主页:

Login页面:

Register页面:

用户登录后主页:

Post页面:

打开D:\blog,里面如图所示:

这里也不再多述每个文件的作用了,我们新建一个文件夹取名为models用来存放模型。

然后我们打开app.js看看里面有什么:

/**
 * Module dependencies.
 */
 
var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path');
 
var app = express();
 
app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'ejs');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(path.join(__dirname, 'public')));
});
 
app.configure('development', function(){
  app.use(express.errorHandler());
});
 
app.get('/', routes.index);
app.get('/users', user.list);
 
http.createServer(app).listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});

我们发现在其中有这两行代码:

app.get('/', routes.index);
app.get('/users', user.list);

它起了路由功能,我们不妨把实现路由功能的代码放到另一个文件里,比如routes/index.js里,这样会变得更容易维护(我们当然可以把这些代码放到app.js里,但app.js里代码会变得越来越多,不便维护)。好了,我们删除这两行代码,在app.js最后添加一行代码:

routes(app);

注意:后面你会看到routes/index.js中重写了module.exportsroutes(app);其实就实现了路由的功能。
routes/index.js修改成如下:

module.exports = function(app){    
    app.get('/',function(req,res){
        res.render('index', { title: '主页' });
    });
    app.get('/reg',function(req,res){
        res.render('reg', { title: '注册' });
    });
    app.post('/reg',function(req,res){
    });
    app.get('/login',function(req,res){
        res.render('login', { title: '登录' });
    });
    app.post('/login',function(req,res){
    });
    app.get('/logout',function(req,res){
    });
    app.get('/post',function(req,res){
        res.render('post', { title: '发表' });
    });
    app.post('/post',function(req,res){
    }); 
};

你会发现regloginpost都有getpost方法,我们可以这么理解:get方法是实现当用户试图访问这个网页时要显示些什么,post方法是当从这个网页上发出数据(这里时提交表单)时要干些什么,所以访问//logout就不需要post方法了。render函数的意思是,当你要访问比如主页时,服务器找到index.ejs文件并替换变量title的值为字符串主页(我们这里用的ejs,当然你也可以用jade,只是我还没学= =)。
接下来我们实现点击不同的链接显示不同的页面。我们把views/index.ejs修改成如下:

<%- include header %>
这是主页
<%- include footer %>

注意:这里用include,不再用partiallayout.ejs
views下新建header.ejs,内容如下:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Blog</title>
<link rel="stylesheet" href="stylesheets/style.css">
</head>
<body>
 
<header>
<h1><%= title %></h1>
</header>
 
<nav>
<span><a title="主页" href="/">home</a></span>
<span><a title="登录" href="/login">login</a></span>
<span><a title="注册" href="/reg">register</a></span>
</nav>
<article>

新建footer.ejs,内容如下:

</article>
</body>
</html>

修改public/stylesheets/style.css如下:

/* inspired by http://yihui.name/cn/ */
*{padding:0;margin:0;}
body{width:600px;margin:2em auto;padding:0 2em;font-size:14px;font-family:"Microsoft YaHei";}
p{line-height:24px;margin:1em 0;}
header{padding:.5em 0;border-bottom:1px solid #cccccc;}
nav{float:left;font-family:"Microsoft YaHei";font-size:1.1em;text-transform:uppercase;margin-left:-12em;width:9em;text-align:right;}
nav a{display:block;text-decoration:none;padding:.7em 1em;color:#000000;}
nav a:hover{background-color:#ff0000;color:#f9f9f9;-webkit-transition:color .2s linear;}
article{font-size:16px;padding-top:.5em;}
article a{text-decoration:none;color:#dd0000;}
article a:hover{color:#333333;text-decoration:underline;}
article h2{display: inline;}
article time{font-size:14px;float:right;}

cmd中启动你的app,打开http://localhost:3000后将如下图所示:

一个简单的主页做好了,然后我们做登录页和注册页,在views下新建login.ejs,内容如下:

<%- include header %>
<form method="post">
用户名:<input type="text" name="username" /><br />
密码:    <input type="password" name="password" /><br />
        <input type="submit" value="登录" />
</form>
<%- include footer %>

views下新建reg.ejs,内容如下:

<%- include header %>
<form method="post">
用户名:<input type="text" name="username" /><br />
密码:    <input type="password" name="password" /><br />
确认密码:<input type="password" name="password-repeat" /><br />
        <input type="submit" value="注册" />
</form>
<%- include footer %>

现在注册、登陆的界面也做好了,你可以打开浏览器查看一下。
登录页:

注册页:

至此,我们在routes/index.js中实现了简单的路由功能,我们还需要个数据库,用来实现注册、登录和保存发表的文章。我们下载mongodb,解压到D:\mongodb,在mongodb文件夹下新建文件夹取名blog用来存放我们的数据。然后新打开一个cmd窗口,cd到我们的d:\mongodb\bin目录下,输入mongod-dbpath "d:\mongodb\blog"设置数据库路径并启动数据库,最小化窗口不要关闭。

接下来我们在node中连接mongodb,打开package.json,在dependencies 属性中添加一行代码:"mongodb":"*",然后npminstall安装mongodb模块,接下来在blog文件夹下创建settings.js 文件,用于保存数据库的连接信息:

module.exports = { 
  cookieSecret: 'myblog', 
  db: 'blog', 
  host: 'localhost'
}; 

models目录下创建 db.js,输入以下内容:

var settings = require('../settings'),
    Db = require('mongodb').Db,
    Connection = require('mongodb').Connection,
    Server = require('mongodb').Server;
module.exports = new Db(settings.db, new Server(settings.host, Connection.DEFAULT_PORT, {}));

这些代码实现了与数据库的连接。

接下来我们安装connect-mongo模块用来存储会话信息到数据库(详见《node.js开发指南》5.6.2),在package.json dependencies中添加一行代码:"connect-mongo":"*"npm install安装connect-mongo模块。
打开 app.js,在“, path= require('path')”后添加以下内容:

, MongoStore = require('connect-mongo')(express)//注意:后面有(express)
, settings = require('./settings');

注意:别忘了删除“, path= require('path')”后的分号。
“app.use(express.methodOverride());”后添加:

app.use(express.cookieParser());
app.use(express.session({ 
      secret: settings.cookieSecret, 
      store: new MongoStore({ 
      db: settings.db 
   }) 
}));

node.js开发指南》这样描述:
其中express.cookieParser() Cookie 解析的中间件。express.session() 则提供会话支持,设置它的 store 参数为MongoStore 实例,把会话信息存储到数据库中,以避免丢失。
在后面的小节中,我们可以通过req.session 获取当前用户的会话对象,以维护用户相关的信息。
至此,数据库的配置工作完成了,后面我们就可以用数据库了。

有了数据库,接下来我们注册页面响应,实现注册功能。
我们先引入flash模块用来实现页面的通知和错误信息显示功能。
cmd中输入npminstall connect-flash安装flash模块,然后在app.js“, settings = require('./settings');”后添加如下代码:

, flash = require('connect-flash');

“app.set('viewengine', 'ejs');”后添加:

app.use(flash());

node.js开发指南》这样描述:
“req.flash
Express提供的一个奇妙的工具,通过它保存的变量只会在用户当前
和下一次的请求中被访问,之后会被清除,通过它我们可以很方便地实现页面的通知
和错误信息显示功能。
现在就可以用flash的通知功能了。

要实现注册功能,首先我们在routes/index.js最前面添加如下代码:

var  crypto = require('crypto'),
User = require('../models/user.js');

载入所需的模型文件user.jscrypto 模块,《node.js开发指南》中这样描述:
“crypto
Node.js的一个核心模块,功能是加密并生成各种散列,使用它之前首先
要声明 varcrypto = require('crypto')。我们代码中使用它计算了密码的散列值。

user.js则实现如何从数据库中存和取用户名和密码。
我们在models下新建user.js,添加如下代码:

var mongodb = require('./db');
 
function User(user){
    this.name = user.name;
    this.password = user.password;
};
module.exports = User;
 
User.prototype.save = function save(callback) {
    var user = {
        name: this.name,
        password: this.password,
    };
 
mongodb.open(function(err, db){
    if(err){
        return callback(err);
    } 
 
    db.collection('users', function(err, collection){
        if(err){
            mongodb.close();
            return callback(err);
        }
 
        collection.ensureIndex('name',{
            unique:true
        });
 
        collection.insert(user,{safe: true}, function(err, user){
            mongodb.close();
            callback(err, user);
        });
    });
});
};
 
User.get = function get(username, callback){
mongodb.open(function(err, db){
    if(err){
        return callback(err);
    }
 
    db.collection('users', function(err, collection){
        if(err){
            mongodb.close();
            return callback(err);
        }
 
        collection.findOne({
            name: username
        },function(err, doc){
            mongodb.close();
            if(doc){
                var user = new User(doc);
                callback(err, user);
            } else {
                callback(err, null);
            }
        });
    });
});
};

接下来我们引入视图助手,《node.js开发指南》中这样描述:
为了实现不同登录状态下页面呈现不同内容的功能,我们需要创建动态视图助手,通过它我们才能在视图中访问会话中的用户数据。同时为了显示错误和成功的信息,也要在动态视图助手中增加响应的函数。
打开 app.js,在http.createServer()前添加以下代码:

app.use(function(req,res,next){
var err = req.flash('error'),
    success = req.flash('success');
res.locals.user = req.session.user;
res.locals.error = err.length ? err : null;
res.locals.success = success.length ? success : null;
next();
});

然后修改/reg的相关响应函数:

app.get('/reg', function(req,res){
    res.render('reg',{
        title:'注册',
        user:req.session.user,
        success:req.flash('success').toString(),
        error:req.flash('error').toString()
    }); 
});
app.post('/reg', function(req,res){
    if(req.body['password-repeat'] != req.body['password']){
        req.flash('error','两次输入的口令不一致'); 
        return res.redirect('/reg');
    }
    var md5 = crypto.createHash('md5');
    var password = md5.update(req.body.password).digest('base64');
    var newUser = new User({
        name: req.body.username,
        password: password,
    });
    User.get(newUser.name, function(err, user){
        if(user){
            err = '用户已存在';
        }
        if(err){
            req.flash('error', err);
            return res.redirect('/reg');
        }
        newUser.save(function(err){
            if(err){
                req.flash('error',err);
                return res.redirect('/reg');
            }
            req.session.user = newUser;
            req.flash('success','注册成功');
            res.redirect('/');
        });
    });
});

注意:这里用到了req.session来读取用户相关的信息。

修改header.ejs中的导航栏部分:

<nav>
<span><a title="主页" href="/">home</a></span>
<% if(locals.user){ %>
<span><a title="发表" href="/post">post</a></span>
<span><a title="登出" href="/logout">logout</a></span>
<% } else { %>
<span><a title="登录" href="/login">login</a></span>
<span><a title="注册" href="/reg">register</a></span>
<% } %>
</nav>

实现已登入用户和未登入用户显示不同的信息。

header.ejs最后也就是<article>后面添加如下代码:

<% if (locals.success) { %> 
  <div > 
    <%= locals.success %> 
  </div> 
<% } %> 
<% if (locals.error) { %> 
  <div> 
    <%= locals.error %> 
  </div> 
<% } %> 

它实现了页面通知的功能。

至此,注册页面写完了,当用户访问reg页面时显示注册表单,但用户提交表单时先检测两次密码一致后,试图往数据库中添加记录,若数据库中存在此用户名,返回用户已存在,若不存在,写入数据库,显示注册成功并返回到到主页,并且左侧导航栏条目变为homepostlogout

接下来我们再写login的响应函数。修改如下:

app.get('/login', function(req, res){
    res.render('login',{
        title:'登录',
        user:req.session.user,
        success:req.flash('success').toString(),
        error:req.flash('error').toString()
    }); 
 });
app.post('/login', function(req, res){
    var md5 = crypto.createHash('md5'),
        password = md5.update(req.body.password).digest('base64');
    User.get(req.body.username, function(err, user){
        if(!user){
            req.flash('error', '用户不存在'); 
            return res.redirect('/login'); 
        }
        if(user.password != password){
            req.flash('error', '密码错误'); 
            return res.redirect('/login');
        }
        req.session.user = user;
        req.flash('success','登陆成功');
        res.redirect('/');
    });
});

我们继续写logout的响应,修改如下:

app.get('/logout', function(req, res){
    req.session.user = null;
    req.flash('success','登出成功');
    res.redirect('/');
});

至此,注册、登陆和登出都实现了,接下来我们加入路由中间件。《node.js开发指南》中这样描述:
在前面我们已经实现了用户登入,并且在页面中通过不同的内容反映出了用户已登入和未登入的状态。现在我们还有一个工作要做,就是为页面设置访问权限。例如,登出功能应该只对已登入的用户开放,注册和登入页面则应该阻止已登入的用户访问。
index.js加入checkNotLogincheckLogin函数来实现。
最终index.js代码如下:

var  crypto = require('crypto'),
    User = require('../models/user.js');
    module.exports = function(app){    
    app.get('/',function(req,res){
        res.render('index', { title: '主页' });
    });
 
app.get('/reg', checkNotLogin);
app.get('/reg', function(req,res){
    res.render('reg',{
        title:'注册',
        user:req.session.user,
        success:req.flash('success').toString(),
        error:req.flash('error').toString()
    }); 
});
 
app.post('/reg', checkNotLogin);
app.post('/reg', function(req,res){
    if(req.body['password-repeat'] != req.body['password']){
        req.flash('error','两次输入的口令不一致'); 
        return res.redirect('/reg');
    }
    var md5 = crypto.createHash('md5');
    var password = md5.update(req.body.password).digest('base64');
    var newUser = new User({
        name: req.body.username,
        password: password,
    });
    User.get(newUser.name, function(err, user){
        if(user){
            err = '用户已存在';
        }
        if(err){
            req.flash('error', err);
            return res.redirect('/reg');
        }
        newUser.save(function(err){
            if(err){
                req.flash('error',err);
                return res.redirect('/reg');
            }
            req.session.user = newUser;
            req.flash('success','注册成功');
            res.redirect('/');
        });
    });
});
 
app.get('/login', checkNotLogin);
app.get('/login', function(req, res){
    res.render('login',{
        title:'登录',
        user:req.session.user,
        success:req.flash('success').toString(),
        error:req.flash('error').toString()
    }); 
});
 
app.post('/login', checkNotLogin);
app.post('/login', function(req, res){
    var md5 = crypto.createHash('md5'),
        password = md5.update(req.body.password).digest('base64');
    User.get(req.body.username, function(err, user){
        if(!user){
            req.flash('error', '用户不存在'); 
            return res.redirect('/login'); 
        }
        if(user.password != password){
            req.flash('error', '密码错误'); 
            return res.redirect('/login');
        }
        req.session.user = user;
        req.flash('success','登陆成功');
        res.redirect('/');
    });
});
 
app.get('/logout', checkLogin);
app.get('/logout', function(req, res){
    req.session.user = null;
    req.flash('success','登出成功');
    res.redirect('/');
});
 
app.get('/post', checkLogin);
app.get('/post', function(req, res){
});
app.post('/post', checkLogin);
app.post('/post', function(req, res){
});
};
 
function checkLogin(req, res, next){
    if(!req.session.user){
        req.flash('error','未登录'); 
        return res.redirect('/login');
    }
    next();
}
 
 
function checkNotLogin(req,res,next){
    if(req.session.user){
        req.flash('error','已登录'); 
        return res.redirect('/');
    }
    next();
}

  至此,我们还有以下功能还没有实现:
1.app.get('/post'),即post页面的布局
2.app.post('/post'),即保存发表的文章到数据库的功能
3.app.get('/'),即完成主页的布局并在主页上显示已发表的文章
我们依次完成以上步骤。

1.修改app.get('/post')如下:

app.get('/post', checkLogin);
app.get('/post', function(req, res){
    res.render('post',{
        title:'发表',
        user:req.session.user,
        success:req.flash('success').toString(),
        error:req.flash('error').toString()
    }); 
});

views下新建post.ejs,输入:

<%- include header %>
<form method="post">
标题:<br />
<input type="text" name="title" /><br />
正文:<br />
<textarea name="post" rows="20" cols="120"></textarea><br />
<input type="submit" value="发表" />
</form>
<%- include footer %>

2.models文件夹下新建post.js,定义了如何保存发表的文章以及如何获取发表的文章,代码如下:

var mongodb = require('./db');
 
function Post(username, title, post, time) {
this.user = username;
this.title= title;
this.post = post;
if (time) {
    this.time = time;
} else {
    this.time = new Date();
    }
}
 
module.exports = Post;
 
Post.prototype.save = function save(callback) {
var post = {
    user: this.user,
    title:this.title,
    post: this.post,
    time: this.time,
};
 
mongodb.open(function (err, db) {
    if (err) {
        return callback(err);
    }
 
    db.collection('posts', function (err, collection) {
        if (err) {
            mongodb.close();
            return callback(err);
        }
 
        collection.ensureIndex('user');
        collection.insert(post, {
            safe: true
        }, function (err,post) {
            mongodb.close();
            callback(err,post);
        });
    });
});
};
 
Post.get = function get(username, callback) {
mongodb.open(function (err, db) {
    if (err) {
        return callback(err);
    }
 
    db.collection('posts', function(err, collection) {
        if (err) {
            mongodb.close();
            return callback(err);
        }
 
        var query = {};
        if (username) {
            query.user = username;
        }
        collection.find(query).sort({
            time: -1
        }).toArray(function (err, docs) {
            mongodb.close();
            if (err) {
                callback(err, null);
            }
 
            var posts = [];
 
            docs.forEach(function (doc, index) {
                var post = new Post(doc.user, doc.title, doc.post, doc.time);
                var now = post.time;
                post.time = now.getFullYear() + "-" + (now.getUTCMonth()+1) + "-" + now.getUTCDate();
                posts.push(post);
            });
            callback(null, posts);
        });
    });
});
};

routes/index.js “User =require('../models/user.js')”后添加如下代码:

Post = require('../models/post.js');

修改app.post('/post')如下:

app.post('/post', checkLogin);
app.post('/post', function(req, res){
    var currentUser = req.session.user,
        post = new Post(currentUser.name, req.body.title, req.body.post);
    post.save(function(err){
        if(err){
            req.flash('error', err); 
            return res.redirect('/');
        }
        req.flash('success', '发布成功!');
        res.redirect('/');
    });
});

3.最后一步,app.get('/'),用来从数据库获取并显示已发表过的文章:

app.get('/', function(req,res){
    Post.get(null, function(err, posts){
        if(err){
            posts = [];
        } 
        res.render('index',{
            title:'主页',
            user: req.session.user,
            posts:posts,
            success:req.flash('success').toString()
        });
    });
});

修改views/index.ejs如下:

<%- include header %>
<% locals.posts.forEach(function(post, index){ %>
    <p><h2><a href="#"><%= post.title %></a></h2><time><%= post.time %> by:<a href="#"><%= post.user %></a></time></p>
    <p><%- post.post %></p>
<% }) %>
<%- include footer %>

我们的blog建成了,赶紧打开浏览器看看把= =
(附上最终代码下载链接:http://www.kuaipan.cn/file/id_80904329019546225.htm不要忘了npminstall一下。)

………………………………………………………………..

express的app.js的详细配置说明

express.js继承自connect模块,所以如果你的node_modules文件夹下没有connect模块也是不行的。

设置views路径和模板

我们再来看下面两行:

app.set('views', __dirname + '/views');
app.set('view engine', 'jade');


上面两行是设置views文件夹,即模板文件夹,__dirname是node.js里面的全局变量,即取得执行的js所在的路径,另外__filename是目前执行的js文件名。所以,app.set(‘views’,__dirname + ‘/views’);是设置views的文件夹。

而app.set('viewengine', 'jade');是设置express.js所使用的render engine。除了Jade之外,express.js还支持EJS(embedded javascript)、Haml、CoffeScript和jQuery template等js模板。

app.use配置

app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));

express.bodyParser()是Connect內建的middleware,设置此处可以将client提交过来的post请求放入request.body中。
express.methodOverride()也是Connect內建的,可以协助处理POST请求伪装PUT、DELETE和其他HTTPmethods。
app.router()是routerequests,但express.js的官方文件是这句可有可无,并且经过测试还真的是这样,不过还是写上吧。
express.static()也是一个Connect內建的middleware来处理静态的requests,例如css、js、img文件等。所以static()里面指定的文件夹中的文件会直接作为静态资源吐出来。

app.configure设置

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
  app.use(express.errorHandler());
});

express.errorHandler()是Connect內建的middleware来協助處理例外。這裡也揭露了app.configure()的令一个用法,第一个參數是node.js的環境設定,如此我們就可以設定在不同的執行環境使用不同程度的dump。PS:node.js是透過NODE_ENV這个環境變數来取得環境設定,e.g.:在命令列,NODE_ENV=production node app.js就可以進入production環境。

路由和request的处理

ok,下面是nodejs处理request的内容:

app.get('/', function(req, res){
  res.render('index', {
    title: 'Express'
  });
});

上面的代码意思是,get请求根目录则调用views文件夹中的index模板,并且传入参数title为“Express”,这个title就可以在模板文件中直接使用。

在express中要处理post请求,需要使用app.post()。如下面的代码:

app.post('/add', function(req,res){
  res.render('add', {
    sum: req.body.a + req.body.b
  });
});

前面我们提到了req.body是express.bodyParser()把POST参数处理后的结果。

另外除了get和post方法,还有app.all()意思就是所有的请求处理。

添加listen,启动nodejs服务器

app.listen(3000);
console.log(
    "Express server listening on port %d in %s mode",
    app.address().port, 
    app.settings.env);

到目前为止,我们就基本全明白了express配置了,也就不会像以前那样跟别人都写个hello world却不知道各行代码的含义了。

 

 

 

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

post与get区别            

客户端 ---post-----服务器

     ---get-----

post(更常用)  

get

服务器

向服务器(目地)传送数据。

从服务器(源地)上获取数据。

提交机制

通过HTTP post机制,,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。安全性较高。

参数数据队列加到提交表单的ACTION属性所指的URL中,在URL中可以看到,安全性非常低,但是执行效率高。

获取数据方法

服务器端用Request.Form获取提交的数据

服务器端用Request.QueryString获取变量的值

大小

数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。

传送的数据量较小,不能大于2KB。

数据操作

增,删,改,

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

nodejs中express的“Error:Cannot find module 'jade'”错误

安装express之后访问http://localhost:3000

会出现500Error: Cannot find module 'jade'错误

解决方案:

一?确定package.json里有添加相应的jade依赖配置

二?使用npminstall -d 可以自动配置package.json,并安装所有需要依赖的包

切换到工程目录下 命令行下执行: npm install –d

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

   <!--  <form method="post"action="/search">    <!--表单 传递方式  post   向INDEX.PHP提交-->

        <input id="text"type="text" name="q" value=""class="search-query span8"/> <!--text文本框  名字叫做q-->

        <input id="button"type="submit" value="搜索"/>  <!--submit 提交-->

   </form>-->注释不了,只能删除。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

  ENOENT   

Error: NO ENTry 进入  的缩写),它表示文件或目录不存在。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

文件上传可能要更改目录:app.js中的target_path='../grauPro/public/upLoadFiles/'+req.files[i].name;

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值