node.js-5

node Web来了

先上code

//show.js
var http =require('http');
var querystring = require('querystring');


var server = http.createServer(function(req,res){
var post='';
req.on('data',function(chunk){
post+=chunk;
});
req.on('end',function(){
post=querystring.parse(post);
res.write(post.title);
res.write(post.text);
res.end();
});
}).listen(3000);


//html

<html>
<body>
<form method="post" action="http://localhost:3000/">
<input type="text" name="title"/>
<textarea name="text"></textarea>
<input type="submit"/>
</form>
</body>
</html>

一个简单的表单提交功能实现了。

在node中可以看出,闲通过data事件接受参数缓存到post中,在end中取出post用parse分割,写回浏览器。


这用我们的想法不一致,感觉复杂得多了。相比其他的实现而言(php)。这是因为node提供的是更底层的实现。也就麻烦一点,这样我们就可以接触到更多的内容


运用Express开发

安装:

npm install -g express

安装全局的Express

建立工程:

在终端输入:

express -t ejs microblog

安装完有提示需要输入

cd microblog && npm install

自动安装ejs和express,安装指定依赖是因为package.json中内容为:

{

  "name": "application-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.3.3",
    "jade": "*"
  }
}

现在运行里面的app.js

在浏览器中输入localhost:3000就可以得到一个简单的Web to Express


看看工程的结构

主文件

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.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');//定义模板引擎位置、__dirname的值为项目的绝对路径如(/home/zhoujixiang/node_code/microblog)
app.set('view engine', 'jade');//使用jade模板引擎
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());//解析客户端请求
app.use(express.methodOverride());//用于支持定制的HTTP方法
app.use(app.router);//项目的路由支持
app.use(express.static(path.join(__dirname, 'public')));//静态文件支持


// development only
if ('development' == app.get('env')) {
  app.use(express.errorHandler());//错误控制器
}


app.get('/', routes.index);//将‘/’路径映射到exports.index函数下

                                           //index.js的主要语句是res.render('index',{title:'Express'}),功能是调用模块解析引擎
app.get('/users', user.list);

//创建一个实例
http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});



routes/index.js是路由文件,相当于控制器,用于组织展示的内容

index.jade、layout.jade是模板文件,即routes/index.js中调用的模板

chrome请求localhost:3000返回的Network内容


由这可以看出是发送的get请求,后面若干请求头,app会解析请求的路径,调用相应的逻辑。app.js是请求routes.index函数处理。routes.index通过res.render('index',{title:'Express'})调用视图模板index传递title变量生成视图模板HTML页面,返回给浏览器。

chrome请求localhost:3000返回的Network内容

  1. Request URL:
    http://localhost:3000/
  2. Request Method:
    GET
  3. Status Code:
    200 OK
  4. Request Headersview source
    1. Accept:
      text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    2. Accept-Encoding:
      gzip,deflate,sdch
    3. Accept-Language:
      zh-CN,zh;q=0.8
    4. Cache-Control:
      max-age=0
    5. Connection:
      keep-alive
    6. Host:
      localhost:3000
    7. User-Agent:
      Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36
  5. Response Headersview source
    1. Connection:
      keep-alive
    2. Content-Length:
      170
    3. Content-Type:
      text/html; charset=utf-8
    4. Date:
      Fri, 05 Jul 2013 02:59:54 GMT
    5. X-Powered-By:
      Express

浏览器接收后发现要获取/stylesheets/style/css。再次发出请求。

app.js中并没用一个路由规则指派到/stylesheets/style/css,但app通过app.use(express.static(__dirname+'/public'))配置了静态文件服务器,会定位到/public/stylesheets/style.css

并想客户端返回

  1. Request URL:
    http://localhost:3000/stylesheets/style.css
  2. Request Method:
    GET
  3. Status Code:
    304 Not Modified
  4. Request Headersview source
    1. Accept:
      text/css,*/*;q=0.1
    2. Accept-Encoding:
      gzip,deflate,sdch
    3. Accept-Language:
      zh-CN,zh;q=0.8
    4. Cache-Control:
      max-age=0
    5. Connection:
      keep-alive
    6. Host:
      localhost:3000
    7. If-Modified-Since:
      Fri, 05 Jul 2013 02:18:37 GMT
    8. If-None-Match:
      "110-1372990717000"
    9. Referer:
      http://localhost:3000/
    10. User-Agent:
      Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36
  5. Response Headersview source
    1. Accept-Ranges:
      bytes
    2. Cache-Control:
      public, max-age=0
    3. Connection:
      keep-alive
    4. Date:
      Fri, 05 Jul 2013 02:59:54 GMT
    5. ETag:
      "110-1372990717000"
    6. Last-Modified:
      Fri, 05 Jul 2013 02:18:37 GMT
    7. X-Powered-By:
      Express

创建路由规则:

当我们在地址栏输入一个http://localhost:3000/zjx之类的网址时,肯定会返回404not find的结果,因为我们没有对应的路由规则

从app.js中我们可以发现

app.get定义中定义了两个路由规则'/' 以及‘users’。所以这两个是可以访问的。

现在可以手动加入一条路由规则如:

app.get('/time',routes.time)

然后在routes/index.js,增加time函数

exports.hello=function(req,res){

  res.send(‘Now  Time’+  new Date().toString());

};

重启服务器,就可以访问http;//localhost:3000/time就会得到一个时间结果。

如果不想一直重启,不方便调试的话,可以用之前说的supervisor


路径匹配:

Express还支持更高级的路径匹配模式。如当定义一下路由规则时:

app.get('/user/:username',function(req,res){
   res.send('user:',req.params.username);
});

访问http://localhost:3000/user/zjx

会得到

zjx的页面。

路径规则/user/:username会被自动编译为正则表达式,类似于\/user\/([^\/]+)\/?这样的实现。参数在响应函数中通过req.params的属性访问

路径规则支持js正则表达式。以便于定义更加复杂的路径规则,而不同指出是匹配的参数匿名。需要req.params[0]的形式访问。


REST风格的路由规则

REST表征状态转移,基于HTTP协议的网络应用的接口风格,充分利用HTTP的方法实现同一风格接口的服务。HTTP协议定义了一下8种标准的方法:

GET:请求获取指定资源

HEAD:请求指定资源的响应头

POST:向指定资源提交数据

PUT:请求服务器存储一个资源

DELETE:请求服务器删除指定资源
TRACE:回显服务器收到的请求,主要用于测试或诊断
CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
OPTIONS:返回服务器支持的HTTP请求方法

REST设计模式中:

GET:获取        安全   幂等

POST:新增       

PUT:更新              幂等

DELETE:删除      幂等

安全:指没有副作用,请求不会对资源产生变动,连续访问多次所获得的结果不受访问者的影响

幂等:重复请求多次与一次请求的效果是一样的

Express支持的HTTP请求的绑定函数

-------------------------------------------------------------------------------------------------------------------------------

请求方式                                                                   绑定函数

-----------------------------------------------------------------------------------------------------------------------------

GET                                                                       app.get(path,callback)

POST                                                                    app.get(path,callback)

PUT                                                                      app.get(path,callback)

DELETE                                                              app.get(path,callback)

PATCH                                                                app.get(path,callback)              部分更新某个资源

TRACE                                                                app.get(path,callback)

CONNECT                                                          app.get(path,callback)

OPTIONS                                                             app.get(path,callback)

所有方法                                                               app.all(path,callback)

-----------------------------------------------------------------------------------------------------------------------------------

app.all函数是将所有请求绑定到同一个响应 函数。


控制权转移

当同时定义多个路由规则时,访问被这些路由规则匹配的路径时,请求总是被迁移条路由规则捕获,后面的规则会被忽略。因为Express在处理路由规则时,会优先匹配定义的路由规则,因此后面相同的规则会被屏蔽掉。

Express提供了路由控制权转移的方法,即回调函数的第三个参数next,通过调用next(),会将路由控制权转移给后面的规则,例如:

app.all('/user/:username',function(req,res,next){
   console.log('all methods captured');
   next();
});
app.get('/user/:username',function(req,res){
   res.send('user:',req.params.username);
});

当访问被匹配到的路径时,如http://localhost:3000/user/zjx,会发现终端打印了all methods captured,而浏览器中显示了zjx。说明请求被第一条捕获了完成log后,用next()把转移控制权,又被第二条规则捕获。

从这里我们可以轻易地实现中间件,还能提高代码的复用程度。

例如代码中先使用

app.all拦截所有的请求,判断合法性后在转移控制权,如果不合法直接抛出异常,这样可以很请求的组织结构。方便定义中间件。把相似请求的相同部分提取出来,有利于代码维护其他next方法如果接受了参数,即代表发生了错误。使用这种方法把错误检查分段化,降低代码耦合度。


模板引擎

早期模板引擎存在的问题:

1.页面功能逻辑与页面布局样式耦合,网站规模变大以后逐渐难以维护

2.语法复杂,对于非技术的网页设计者来说,门槛较高,难以学习

3.功能过于全面,页面设计者可以在页面上编程,不利于功能划分,使模板解析效率降低。

现代的模板引擎是MVC的异步分,在功能划分上它严格属于视图部分,因此功能以生成HTML页面为核心,不会引入过度的编程语言的功能。

模板引擎的功能是将页面和要显示的数据结合起来生成HTML页面。模板引擎可以运行在服务器端,生成HTML后传输给客户端。也可以在客户端运行如XSLT,但是由于存在浏览器兼容性问题,不是很流行。目前主要是由服务器运行模板引擎。


    页面模板                数据      《-------------- |               

          |                             |                             |          

         \|/                           \|/                       控制器

                  模板引擎                                     |

                     |                                                |

                    \|/                                               |

               HTML页面------------------------ -》| 



使用模板引擎

在app.js中设置:

app.set('views',__dirname+'/views');//页面位置

app.set('view engine','jade');//设置模板引擎


调用模板引擎:

 res.render('index', { title: 'Express' });

第一个参数即views目录下的模板文件名,不包含文件扩展名;第二个是要传递给模板的数据,用于模板翻译

//index,jade

extends layout //引用layout


block content//将内容插入到定义的位置
  h1= title            //定义一个h1表情,标签体为title

  p Welcome to #{title}  //定义一个p表情,标签体为#{title}引用title参数值


结合layout.jade

//layout.jade

doctype 5
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    block content//定义插入内容的位置

结合两个jade模板可以看出jade,对于没有学过jade的也不是很难看懂。

对于index.jade

完整的内容就是

doctype 5
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body

h1= title           

  p Welcome to #{title}  

这样看,就可以对应页面的内容翻译成HTML了。

当然也可以关闭引用的layout.jade

如添加代码:

app.set('view options',{layout:false});//不引用layout模板

当然,大多数的网站,有前台展示和后台管理系统,两者的页面结构有很大的区别,一套页面布局不能满足需求。我们可以在模板翻译时指定页面布局,即设置layout属性例如

exports.index = function(req, res){
  res.render('index', { title: 'Express admin',layout:'admin' });//调用admin.jade作为页面布局
};












评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值