1、Web 与 Node.js 相关技术介绍
1.1、Web应用的基本组件
web应用的三大部分
brower(GUI)<==>webserver(business logic、data access)<==>database(data storage)
GUI(浏览器、HTTP客户端)
Web服务器(Node.js service)
请求(浏览器访问网页时发送一个请求给服务器)
业务逻辑(服务器进行处理请求)
连接数据库(处理的过程中需要连接数据库,进行数据处理,最后将数据返回给GUI也就是浏览器,这是一个请求响应的过程)
数据库(SQLite,LevelDB,Redis)
GET /yorkie HTTP/1.1
Host:github.com
Connection:keep-alive
Accept:text/html,application/xhtml
User-Agent:My iPhone
Accept-Encoding:gzip,deflate,sdch
(请求的方法(method))get就是个请求请求的方法有很多种,主要有get和post两种,其他还有很多
/yorkie这部分就是请求的路径,也是一个资源的定位
1.1这一部分标识使用的HTTP的版本
Host:github.com这一部分表示我们要访问的域名,访问域名最后就可以转化成一个url了
1.2、expressjs框架
npm install express -g(全局安装成功,不带-g出现错误提示)
安装成功之后这时桌面(安装完会提示安装到哪了,具体看下图:)会出现node_moudules这么一个文件夹
[lin@vultr ~]$ sudo npm install express -g /usr/lib └─┬ express@4.16.4 ├─┬ accepts@1.3.5 │ ├─┬ mime-types@2.1.21 │ │ └── mime-db@1.37.0 │ └── negotiator@0.6.1 ├── array-flatten@1.1.1 ├─┬ body-parser@1.18.3 │ ├── bytes@3.0.0 │ ├─┬ http-errors@1.6.3 │ │ └── inherits@2.0.3 │ ├─┬ iconv-lite@0.4.23 │ │ └── safer-buffer@2.1.2 │ └── raw-body@2.3.3 ├── content-disposition@0.5.2 ├── content-type@1.0.4 ├── cookie@0.3.1 ├── cookie-signature@1.0.6 ├─┬ debug@2.6.9 │ └── ms@2.0.0 ├── depd@1.1.2 ├── encodeurl@1.0.2 ├── escape-html@1.0.3 ├── etag@1.8.1 ├─┬ finalhandler@1.1.1 │ └── unpipe@1.0.0 ├── fresh@0.5.2 ├── merge-descriptors@1.0.1 ├── methods@1.1.2 ├─┬ on-finished@2.3.0 │ └── ee-first@1.1.1 ├── parseurl@1.3.2 ├── path-to-regexp@0.1.7 ├─┬ proxy-addr@2.0.4 │ ├── forwarded@0.1.2 │ └── ipaddr.js@1.8.0 ├── qs@6.5.2 ├── range-parser@1.2.0 ├── safe-buffer@5.1.2 ├─┬ send@0.16.2 │ ├── destroy@1.0.4 │ └── mime@1.4.1 ├── serve-static@1.13.2 ├── setprototypeof@1.1.0 ├── statuses@1.4.0 ├─┬ type-is@1.6.16 │ └── media-typer@0.3.0 ├── utils-merge@1.0.1 └── vary@1.1.2
本地安装: |
下面一段代码简单实现在浏览器页面显示一部分内容:
var express = require('express'); var app = express(); app.get('/jikexueyuan',function(req,res){ res.send('hello jikexueyuan'); }); app.listen(3000);
以下是在浏览器中显示的内容。
注意查看expressJS官方API文档的侧边栏的基本组件
2、expressjs 的配置与路由
2.1、expressjs基础
请求和响应的数据全部放在头部是不现实的。
get一般是从服务器拿数据,是没有{body}这种东西的
//or cristring style name=hahaha name=hahaha&foo=bar&x[y]=10 { name:'hahaha', foo:'bar', x: { y: 10} } //expressjs request_object = { method:'POST', path: '/hahahaha', headers:{ 'Content-Type':'application/json', ... ... } body:{} } request.body = JSON.parse(rawBody); bodyparser.urlEncoded(); //response HTTP/1.1 200 OK ... .. ... //express status var response = {} response.status = function (){}; response.status(200); response.status(500); response.headers['Content-Type'] = 'application/json'; response.set('Content-Type', 'application/json'); response.send([20]); response.json()
比较重要的点:
req.path
req.hostname(主机名)
req.body
bodyParser(模组:用处:用来解析BODY的,因为body有很多编码方式(像json、cristring等等)express自己是不会自己进行解析的,bodyParser提供了两种方式
request.body = JSON.parse(rawBody);
bodyparser.urlEncoded();
)
2.2、expressjs的初始化配置
request
|
middleware 1
|
middleware 2
|
middleware 2
|
URL
|
response
middleware: (中间件----由很多回调函数组成的东西)
app.use
app.get
app.post
request:
req.params
req.query
req.body
response:
res.send()
next()
2.3、expressjs的路由
2.4、expressjs的返回响应
app = express()
app.use
body-parser:https://github.com/expressjs/body-parser
res.send()
plain text
JSON
代码示例:
var express = require('express'); var app = express(); app.get('/plain-text', function(req, res){ res.status(200).send('<h1>'+"hello"+`world<h1>`); }); app.get('/category', function(req, res){ res.status(200); res.json({ python: 20, nodejs: 1, others: 10 }); }); var questions = [ { id:1, title: 't1', asker: 'you', course: 'nodejs', 'last-reply': Date.now(), reply:1, state: 'resolved' }, { id:2, title: 't2', asker: 'you', course: 'nodejs', 'last-reply': Date.now(), reply: 1, state: 'unresolved' }, { id:3, title: 't3', asker: 'you', course: 'nodejs', 'last-reply': Date.now(), reply: 1, state: 'unresolved' }, { id:4, title: 't4', asker: 'you', course: 'nodejs', 'last-reply': Date.now(), reply: 1, state: 'unresolved' } ]; app.get('/questions', function(req, res){ res.status(200); res.json(questions); }); //liebiao guolv (jia ru yi ge state) app.get('/questions/all', function(req, res){ res.status(200); res.json(questions); }); app.get('/questions/unresolved', function(req, res){ res.status(200); res.json(questions.filter(function(q){ //console.log("q : "+ q); //console.log("q.state : " + q.state ); //console.log("q && q.state: " + (q && q.state)); var ppp = q && q.state; //console.log(ppp);//resolved unresolved unresolved unresolved //if(q.state === 'unresolved')return q; //This is the same function!!! if(q.state ==='unresolved')return true;//This is the real function !!! //return q && q.state === 'unresolved'; })); }); app.get('/questions/resolved', function(req, res){ res.status(200); res.json(questions.filter(function(q){ return q && q.state === 'resolved'; })); }); app.listen(3000);
3、expressjs 与HTML
3.1、使用expressjs返回HTML内容
HTML
Content-Type:text/html(服务器要返回给客户端什么类型的数据)
fs.createReadStream('xxx.html').pipe(res)
res.render()
3.2、模板渲染
模板:
用途:复用HTML组件,简化开发流程
比喻:模具
渲染/生成:
用途:“生成”最终的HTML内容
比喻:烤饼干
3.3、使用app.set来设置express实例所使用的模板引擎
ejs:http://ejs.co(模板引擎)
使用模板引擎,需要加一个语句(想用其他的模板引擎的话,直接修改ejs这一部分)
app.set('view engine', 'ejs')
res.render('home.ejs', {title: 'ejs template'})
这里出现了cannot find module 'ejs' 的问题,解决办法是在用户目录下执行以下两行命令
npm install ejs -g (全局安装ejs)(发现全局安装ejs之后并不起作用(这里是我忘了这是普通用户的原因了。)之后再执行下面一行命令)
(全局安装就是必须用root权限安装,不是root用户就用sudo ,是root就直接使用以上命令安装) npm install ejs (在代码目录下再安装一次)
安装完成功之后的情况下可以移动当前所在目录的项目了,具体原因未知。不过对我来说,可以用就行了!
render_myprogram2.js
var express = require('express'); var app = express(); app.set('view engine', 'ejs'); app.set('views', __dirname + '/views'); /*定义views的路径*/ /*__dirname好像是个全局变量,注意这里是两个下划线*/ app.get('/', function(req, res){ res.render('home.ejs', {name: 'nameishahaha'}); }); app.listen(3000);
home.ejs(views目录下的home.ejs)
<html> <head> <title>new template</title> </head> <body> <p> hello hahahahahaha </p> <p> Hi <%= name %> </p> </body> </html>
如何与request对象进行结合:
render_myprogram.js
var express = require('express'); var app = express(); app.set('view engine', 'ejs'); app.set('views', __dirname + '/views'); /*定义views的路径*/ /*__dirname好像是个全局变量,注意这里是两个下划线*/ app.get('/', function(req, res){ res.render('home.ejs', {name: 'nameishahaha'}); }); app.get('/request/:id', function(req, res){ var locals = {name: 'gagagagaga', 'id': req.params['id']}; res.render('home.ejs', locals); }); app.listen(3000);
home.ejs(views目录下的home.ejs)
<html> <head> <title>new template</title> </head> <body> <p> hello hahahahahaha </p> <p> Hi <%= name %> </p> <p> id <%= id %> </p> </body> </html>
3.4、前后端共用模板
在前端渲染(render)模板
<script srv="ejs.js"></script> ejs.render(tmpl,data)
复制文件ejs.min.js到根目录下的headers文件夹下
这里老师讲的main文件没有引入,不知道原因是什么他运行着没有问题,但是我还是自己引入了main1.js
下面是代码
render_my_program2.js
var express = require('/usr/lib/node_modules/express'); //这里是真的屌,原来这里的参数是express框架的目录,恕我愚钝 //所以这里可以通过在项目目录执行npm install express来解决呢 var app = express(); app.set('view engine', 'ejs'); app.set('views', __dirname + '/views'); /*定义views的路径*/ /*__dirname好像是个全局变量,注意这里是两个下划线*/ app.use(express.static(__dirname)); //console.log(__dirname);// /home/lin/lin_nodejs_nodes/my_project1 app.get('/', function(req, res){ res.render('home.ejs', {name: 'nameishahaha'}); }); app.get('/request/:id', function(req, res){ var locals = {name: 'gagagagaga', 'id': req.params['id']}; res.render('home.ejs', locals); }); app.listen(3000);
/views/home.ejs
<html> <head> <title>new template</title> </head> <body> <p> hello hahahahahaha </p> <p> Hi <%= name %> </p> <p> id <%= id %> </p> <input id="new-temp-val" type="text"> <div id="new-temp"></div> </body> <script type="text/javascript" src="/ejs.min.js"></script> <!--这里的/ejs.min.js是__dirname/ejs.min.js--> <script type="text/javascript"> //alert("test_alert"); var tmpl = '<p>A new template</p>'; var newTempDiv = document.getElementById('new-temp'); /* setTimeout(function(){ newTempDiv.innerHTML = ejs.render(tmpl); },2000); */ //因为后面有了main.js所以这里的js代码不管用了,就注释掉可以了 </script> <script type="text/javascript" src="/main_js_dir/main1.js"></script> <!--/指的是当前项目的工作路径的根目录,我没写/的时候报错了。--> </html>
/main_js_dir/main1.js
//alert("test_alert");//alert好像在只有声明了是text/javasceipt类型才会管用,在这里不管用 console.log("????"); var newTemp = document.getElementById('new-temp'); setInterval(function(){ var tmpl = '<p>the value is <%= val1 %></p>'; val1 = document.getElementById('new-temp-val').value || null; newTemp.innerHTML = ejs.render(tmpl); },2000);
4、模组化
1、如何设计API
不要让用户使用关键字new
保持简洁
不要轻易地输出接口
2、发布到NPM
npm publish
生成一个package.json文件,在生成的时候他会自动地把你的一些内容给输入进去,包括你之前有node modules他会自动识别node modules里面的模组,然后将他们包含在你的package里面,这样你在别人从npm装上你的包的时候就能自动安装这些dependencys(依赖),这样比较方便的,所以npm init是比较方便的东西,等你准备发布之后,你可使用npm publish将你的包上传到npm的服务器上,然后在另外一台机器上你就可以用npm install +你的名字然后就可以将你相应的包下载到对应的node modules目录下
3、课程总结
express或Node.js在开发Web应用程序的基本流程
如何在Node.js中复用代码并使用npm来分发