一,
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
使用者主机IP:127.0.0.1
使用者使用端口号: 1060
response
[JSP]JSP中的隐藏对象 -- response- -
JSP的response隐藏对象在转换为Servlet之后,对应于HttpServletResponse型态对象,HttpServletResponse对象是有关于对客户端请求之响应,您可以利用它来设定一些要响应的讯息,例如标题信息、响应状态码等.
response的常用方法:
setHeader():是一个通用的标头设定方法,您可以用它来设定任何「名称/值」的标头.
setIntHeader():是专门用来设定整数值标头的版本.
setDateHeader():是setHeader()的Date设定版本,第二个参数是设定Date的Long数值,0表示GMT1970/1/1 00:00。
(Note:以上3个函数用来设置HTTP协议的表头,必须对HTTP协议有些了解才能正确使用,我现在也不清楚).
setStatus():是用来设定回应的状态码,例如404 Not Found,HttpServletResponse类中提供了一些助忆常数设定,例如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它是哪个类的实例呢?
request是HttpServletRequest的一个子类的实例,这么说很含糊,事实上这个具体类根据不同的服务器是不同的,但是这些具体类都implement了HttpServletRequest接口。因为无法确定具体是哪个类,所以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,则可以设置layout为false,例如:
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.x和3.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:登出
未登录前:主页左侧导航显示home、login、register,右侧显示已发表的文章,见下图
登陆后:主页左侧导航显示home、post、logout,右侧显示已发表的文章,见下图
用户登录、注册、发表成功以及退出后都返回到主页。效果图如下
用户登陆前主页:
用户登录后主页:
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.exports,routes(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){
});
};
你会发现reg、login和post都有get和post方法,我们可以这么理解:get方法是实现当用户试图访问这个网页时要显示些什么,post方法是当从这个网页上发出数据(这里时提交表单)时要干些什么,所以访问/和/logout就不需要post方法了。render函数的意思是,当你要访问比如主页时,服务器找到index.ejs文件并替换变量title的值为字符串’主页’(我们这里用的ejs,当然你也可以用jade,只是我还没学= =)。
接下来我们实现点击不同的链接显示不同的页面。我们把views/index.ejs修改成如下:
<%- include header %>
这是主页
<%- include footer %>
注意:这里用include,不再用partial和layout.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.js和crypto 模块,《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页面时显示注册表单,但用户提交表单时先检测两次密码一致后,试图往数据库中添加记录,若数据库中存在此用户名,返回“用户已存在”,若不存在,写入数据库,显示“注册成功”并返回到到主页,并且左侧导航栏条目变为home、post、logout。
接下来我们再写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加入checkNotLogin和checkLogin函数来实现。
最终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;
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。