Node_进阶_2
第二天
一、复习:
Node.js开发服务器、数据、路由。本地关心效果,交互。
Node.js实际上是极客开发出的一个小玩具,不是银弹。有着别人不具备的怪异特点:
单线程、非阻塞I/O、事件驱动。 实际上是一个特点。
首先,Node不为每个用户开辟一个线程,所以非常极端的选择了单线程。
单线程,要照顾所有的用户,必须有非阻塞I/O否则一个人的I/O就把别人、自己都阻塞了。
一旦有非阻塞I/O,一个人如果I/O去了,就会放弃CPU的使用权,换成另一个人使用CPU(或者执行此人后面的语句)。所以CPU的利用率是100%。第一个人I/O结束了,就要用事件来通知线程,执行回调函数。此时必须有事件环,就有一个排队调度机制,Node中有超过半数的C++代码,在搭建事件环。
Node.js和别的老牌3P不一样:
1) 没有自己的语法,使用V8引擎,所以就是JS。V8引擎解析JS的,效率非常高,并且V8中很多东西都是异步的。Node就是将V8中的一些功能自己没有重写(别人做了,自己就站在巨人肩膀上),移植到了服务器上。
2) 没有web容器,就是安装配置完成之后,没有一个根目录。
汇编语言 暴露几个API => C语言 暴露几百个API => 高级语言 暴露更多API
系统中,80端口,就是默认的http端口,所以当没有端口号的时候就默认80端口。
(https是443)
之前写了一个静态服务器,但是其实不是很完善,虽然对mime类型有判断了,但是返回的都是200状态码。304状态码表示已经存在这个文件,实现的机制是用cookies来给文件打标记,302表示重定向。这些都没有实现.(顺带一提)
二、模块
模块的概念
·在Node.js中,以模块为单位划分所有功能,并且提供了一个完整的模块加载机制,这时的我们可以将应用程序划分为各个不同的部分。
不可能用一个js文件去写全部的业务,肯定要有MVC。
·狭义的说,每一个JavaScript文件都是一个模块,而多个JavaScript文件之间可以相互require,他们共同实现了一个功能,他们整体对外,又称为一个广义上的模块。
·Node.js中,一个JavaScript文件中定义的变量、函数,都只在这个文件有效。当需要从模块外部引用这些变量、函数时,必须使用exports对象进行暴露。使用者要用require()命令引用这个JS文件。
var msg = ‘你好’
var info = ‘呵呵’
exports.msg = msg
msg这个变量是一个js文件内部才有作用域的变量。
使用者:
var foo = require(‘./test/foo.js’)
console.log(foo.msg);
暴露与引用。js文件中可以用exports暴露很多东西,比如函数、变量。
相当于增加了顶层变量。所有的函数、变量都要从这个顶层变量走。
Node中,js文件和js文件,就是被一个个exports和require构建称为网状依赖的。
不是像HTML文件中从上往下依赖的。
在js中可以将一个类暴露出去,然后进行引用。
a.js
function People(name,sex,age)
{
this.name = name;
this.sex = sex;
this.age = age;
}
People.prototype = {
SayHello:function(){
console.log(this.name+this.sex+this.age);
}
}
//直接暴露出来
module.exports = People;
b.js:
var People = require(‘./a.js’);
var xiaoming = new People(‘xiaoming’,12,’男’);
xiaoming.sayHello();
文件夹模块和package文件
如果require(‘a.js’)这样不写出路径
会自动默认的加载node_modules文件夹中的内容。
如果当前层没有,他就逐级遍历哪一层有Node_modules文件夹。
甚至可以放到NODE_PATH环境变量的文件夹中。
计算机-高级系统设置-环境变量-新建系统遍历 名字叫NODE_PATH。
·也可以使用文件夹来管理模块,比如:
var bar = require(‘bar’)
那么Node.js将会去寻找node_modules目录下的bar文件夹中的Index.js去执行。
可以自定义这个文件,需要建立package.json然后为main项设定。
这样require(‘bar’)文件夹的时候,就会去读取这个app.js
NPM
我们刚才学习了,模块就是一些功能的封装,所以一些成熟的、经常使用的功能,都有人封装成为了模块。
去社区搜索需求,然后点进去看api
..
- 我们的依赖包,可能在随时更新,我们永远想保持更新。
- 项目越来越大的时候,给别人看的时候,没有必要再次共享我们引用的第三方模块。
所以我们用package.json来管理我们的依赖。
package.json的
‘dependency‘中的^符号确保更新时这一位版本不变,其他的位数在install时候会自动更新。因为社区开发者每个人对自己的版本更新都有不同的定义。有时虽然大版本没变,但是小版本号的更新也可能带来了巨大的变化。会导致程序挂掉。所以出现了packagelock.json来锁定到特定的版本。
路径
文件的操作一定要用绝对路径,因为如果在a.js中require了一个b.js,这个js中有用fs读取了一个相对路径,那么读取出来的路径会有错误,因为node a.js的时候是以a为相对目录的。
require()别的文件的时候,会执行这个js文件。
实际上他会做一次绑定,把对象中的export对象绑定给承接的变量。
注意:require()中的路径是从当前js文件出发找到别人。所以,桌面上有一个a.js,test文件夹中有一个b.js和c.js
a要引用b:
var a = require(‘./test/b.js‘);
b要引用c:
var b = require(‘./c.js’)
但是,fs等其他的模块用到路径的时候都是相对于入口文件的。
所以,如果test文件夹中,有一个1.txt,那么在b.txt中想读取这个文件,请使用绝对路径。
(使用__dirname)
狭义的讲,一个js文件就是一个模块。
广义的讲,一个文件夹(或者是带package.json的文件夹)也是一个模块,因为会去读取文件夹内的index.js(或者package.json中的main:’入口文件.js’)
三、post请求
post请求
示例:
(req.addListener == req.on)
a.js:
const http = require('http');
const querystring = require('querystring');
var server = http.createServer((req, res) => {
//如果你的访问地址是这个,并且请求类型是post
if (req.url == '/dopost' && req.method == 'POST') {
var alldata = "";
//不断的往事件环里去加载这个事件
//接受了一小段,可能就给别人去服务了。防止一个过大的表单阻塞了整个线程
req.on('data', (chunk) => {
alldata += chunk;
});
req.on('end', (chunk) => {
var datastring = alldata.toString();
res.end('success');
//将datastring转为一个对象
var dataObj = querystring.parse(datastring, null, null,
);
console.log(dataObj);
console.log(dataObj.name);
console.log(dataObj.sex);
})
}
});
server.listen(3000);
aa.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="http://127.0.0.1:3000/dopost" method="POST">
<p>
姓名:
<input type="text" name='name'>
</p>
<p>
性别:
<input type="radio" name='sex' value='女' id='female'>
<label for="female">女</label>
<input type="radio" name='sex' value='男' id='male'>
<label for="male">男</label>
</p>
<p>
爱好:
<input type="checkbox" name='hobby' value='睡觉'>睡觉
<input type="checkbox" name="hobby" value="吃饭">吃饭
<input type="checkbox" name="hobby" value="足球">足球
</p>
<input type="submit" value="提交">
</form>
</body>
</html>
如果这里有一个图片上传的input 最后alldata.toString()以后会是undefined ,所以,对于图片要做一个二进制的文件的处理。
formidable
formidable是一个node.js的表单模块
看以下npm.js网址上对这个模块的介绍:
Purpose
A Node.js module for parsing form data, especially file uploads.
This module was developed for Transloadit, a service focused on uploading and encoding images and videos. It has been battle-tested against hundreds of GB of file uploads from a large variety of clients and is considered production-ready.
(图为API的使用)
可以看到,把所有请求的表单域用fields(字段)表示,把所有的文件用files(文件)来表示。
aa.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="http://127.0.0.1:3000/dopost" enctype="multipart/form-data" method="POST">
<p>
姓名:
<input type="text" name='name'>
</p>
<p>
性别:
<input type="radio" name='sex' value='女' id='female'>
<label for="female">女</label>
<input type="radio" name='sex' value='男' id='male'>
<label for="male">男</label>
</p>
<p>
爱好:
<input type="checkbox" name='hobby' value='睡觉'>睡觉
<input type="checkbox" name="hobby" value="吃饭">吃饭
<input type="checkbox" name="hobby" value="足球">足球
</p>
<p>
图片:
<input type="file" name='tupian'>
</p>
<input type="submit" value="提交">
</form>
</body>
</html>
12.js:
//formidable
1.js:
const http = require('http');
const querystring = require('querystring');
const formidable = require('formidable');
const util = require('util');
var server = http.createServer((req, res) => {
if (req.url == '/dopost' && req.method == 'POST') {
//create a new incoming form
var form = new formidable.IncomingForm();
//设置文件上传存放的地址
form.uploadDir = "./uploads";
//执行里面回调函数的时候,表单已经全部接收完毕了。
form.parse(req, function (err, fields, files) {
if (err) {
throw err;
}
//所有的文本域、单选框,都在fileds里面存放;
//所有的文件与,都在files内存放。
//util.inspect 相当于console.log这个对象
console.log(util.inspect({ fields: fields, files: files }));
res.writeHead(200, { 'content-type': 'text/html;charset=UTF-8' });
res.write('received upload:\n\n');
res.end('Success');
});
return;
}
}).listen(3000);
在这节课学到的一个比较重要的东西是如果上传图片的时候,在form标签里一定要加enctype="multipart/form-data"
上传改名
原生的POST比较复杂,要写两个监听。
所以用第三方的formidable比较方便。
下面继续上面的案例来做,上传的文件名改名为2018050812323(时间+随机数)这样。
这里顺带介绍了一下silly-datetime插件 可以格式化的生成时间
https://www.npmjs.com/package/silly-datetime
(非常好用)
formidable里面生成的fields与files的数据结构是这样的:
13.js:
//上传图片 文件名是当前时间
//formidable
const http = require('http');
const querystring = require('querystring');
const formidable = require('formidable');
const util = require('util');
const fs = require('fs');
const sd = require('silly-datetime');
const path = require('path');
var server = http.createServer((req, res) => {
if (req.url == '/dopost' && req.method == 'POST') {
//create a new incoming form
var form = new formidable.IncomingForm();
//设置文件上传存放的地址
form.uploadDir = "./uploads";
//执行里面回调函数的时候,表单已经全部接收完毕了。
form.parse(req, function (err, fields, files) {
if (err) {
throw err;
}
//所有的文本域、单选框,都在fileds里面存放;
//所有的文件与,都在files内存放。
//util.inspect 相当于console.log这个对象
console.log(util.inspect({ fields: fields, files: files }));
//时间,使用的第三方模块,silly-datetime
var ttt = sd.format(new Date(), 'YYYYMMDDHHmm');
var ran = parseInt(Math.random() * 89999 + 10000);
var extname = path.extname(files.tupian.name);
//执行该名
var oldpath = __dirname + '/' + files.tupian.path;
//新的路径由三个部分组成: 时间戳、随机数、扩展名
var newpath = __dirname + '/uploads/' + ttt + ran + extname;
//改名
fs.rename(oldpath, newpath, (err) => {
if (err) throw Error('改名失败');
res.writeHead(200, { 'content-type': 'text/html;charset=UTF-8' });
res.end('成功');
});
});
} else if (req.url == '/') {
//呈递form.html页面
fs.readFile('./aa.html', (err, data) => {
res.writeHead(200, { 'Content-type': 'text/html;charset=UTF-8' });
res.end(data);
});
} else {
res.writeHead(404, { 'Content-type': 'text/html;charset=UTF-8' });
res.end('404');
}
}).listen(3000);
aa.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="http://127.0.0.1:3000/dopost" enctype="multipart/form-data" method="POST">
<p>
姓名:
<input type="text" name='name'>
</p>
<p>
性别:
<input type="radio" name='sex' value='女' id='female'>
<label for="female">女</label>
<input type="radio" name='sex' value='男' id='male'>
<label for="male">男</label>
</p>
<p>
爱好:
<input type="checkbox" name='hobby' value='睡觉'>睡觉
<input type="checkbox" name="hobby" value="吃饭">吃饭
<input type="checkbox" name="hobby" value="足球">足球
</p>
<p>
图片:
<input type="file" name='tupian'>
</p>
<input type="submit" value="提交">
</form>
</body>
</html>
这个项目可以运行在服务器上,运行在局域网中,然后让别人给你的电脑上传文件,很棒。
四、模板引擎
ejs模板引擎
<a href="<%=url%>"><img src="<%=imageURL%>" alt=""></a>
数据绑定,就成为一个完整的html字符串了。
前台的模板,我们现在要学习的是后台的模板。
后台模板,著名的有两个,第一个叫做ejs,第二个叫做jade
是npm第三方的包
先说ejs
Embedded JavaScript templates
(嵌入式javascript模板引擎)
index.ejs:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>好高兴啊,今天我买了一个iphone
<%= a %>s</h1>
<ul>
<%for(var i = 0;i<news.length;i++){%>
<li><%= news[i]%></li>
<% }%>
</ul>
</body>
</html>
1.js:
const fs = require('fs');
const ejs = require('ejs');
const http = require('http');
var server = http.createServer((req, res) => {
fs.readFile('./views/index.ejs', (err, data) => {
//绑定模板
var template = data.toString();
var dictionary = {
a: 6,
news: [21, 4, '哈哈']
};
var html = ejs.render(template, dictionary);
res.writeHead(200, { 'Content-type': 'text/html;charset=UTF8' });
res.end(html);
});
}).listen(2888);
(模板引擎这种在服务器上把语句组织起来的形式将逐渐被淘汰了,因为代码组织起来太杂糅了。这种时代一去不复返了。)
(未来后台只负责出数据)
jade模板引擎
ejs效率不高,因为是对字符串的处理 <% %>这种东西 下面介绍一下jade模板引擎
http://jade-lang.com/ (jade:玉)
www.npmjs.com/package/jade
(这个语法有点像Python)
这里不做介绍啦.
Node_进阶_2的更多相关文章
- Node_进阶_8
Node进阶第八天 一.复习 Node.js特点:单线程.异步I/O(非阻塞I/O).事件驱动(事件环). 适合的程序:就是没有太多的计算,I/O比较多的业务. 举例:留言本.考试系统.说说.图片裁切 ...
- Node_进阶_7
Node进阶第七天 一.复习 一.索引 数据库中,根据一个字段的值,来寻找一个文档,是很常见的操作.比如根据学号来找一个学生.这个学号是唯一的.只要有学号,就能唯一确认一个学生的文档.学号这个属性 ...
- Node_进阶_6
Node进阶第六天 一.复习 cookie是在res中设置,req中读取的.第一次的访问没有cookie. cookie的存储大小有限,kv对儿.对用户可见,用户可以禁用.清除cookie.可以被篡改 ...
- Node_进阶_5
Node进阶第五天 为什么mysql不用开mongod –dbpath xx… 答:因为mysql会在”服务”中运行,也就是开机时自动启动并且长久驻扎在内存中了. mongodb其实也能通过设置来设成 ...
- Node_进阶_4
Node进阶第四天 一.传统数据库技术回顾 数据库就是存储数据的,那么存储数据用txt就行了啊,为什么要有数据库? 理由之一:数据库有行.列的概念,数据有关系,数据不是散的. 老牌数据库,比如Mysq ...
- React-Native进阶_2.加载指示动画 ActivityIndicator
在安卓原始 App中使用的加载框 ProgressBar 在React -Native 中也是有相对应的视图,叫做ActivityIndicator,对应ios 中React-Native 提供的是 ...
- Node_进阶_1
第一天 1.1简介 Node.js简介 V8引擎本身就是用于Chrome浏览器的JS解释部分,Ryan Dahl把这个V8搬到了服务器上,用于做服务器的软件. Node.js是一个让Javascrip ...
- Node_进阶_3
Express框架: 一. Express框架 Express框架是后台的Node框架,类似于JS中的jquery. #原生Node开发会有很多问题: 1呈递静态页面很不方便,需要处理每个HTTP ...
- 网易云课堂_C语言程序设计进阶_第二周:指针:取地址运算和指针、使用指针、指针与数组、指针与函数、指针与const、指针运算、动态内存分配_2信号报告
2 信号报告(5分) 题目内容: 无线电台的RS制信号报告是由三两个部分组成的: R(Readability) 信号可辨度即清晰度. S(Strength) 信号强度即大小. 其中R位于报告第一 ...
随机推荐
- 如何在php中优雅的地调用python程序
1.准备工作 安装有python和php环境的电脑一台. 2.书写程序. php程序如下 我们也可以将exec('python test.py') 换成 system('python test.p ...
- 解决AttributeError: 'module' object has no attribute 'main' 安装第三方包报错
1.找到pycharm 目录下的 \helper\packaging_tool.py 文件 2.用新版pycharm 的packaging_tool.py 替换 旧版 同名文件 文件代码如下: imp ...
- 滚动效果--marquee的使用
1. <marquee></marquee>标签,默认从最右侧往左滚动: 2. marquee 支持的属性 (1)behavior设置滚动方式: <marquee beh ...
- springboot 不使用前端模板直接跳转页面
1.创建springboot项目 2.在resource 下创建pages文件夹,存放所有页面 3.编写后台代码 4.访问http://localhost:8080/index,即可跳转到页面
- 02018_StringBuffer练习
1.已知int[] arr = {34,12,89,68}; 将其中的元素转成字符串,格式 [34,12,89,68]: 参考:02011_定义打印数组元素方法,按照给定的格式打印[11, 33, 4 ...
- OpenFace Docker 使用简介
在Docker中使用openface最大的问题是数据与主机的交互,下面我介绍几种方法来实现主机与Docker容器的数据交互. 1.第一种也是最方便的一种方法是在进入容器时使用-v参数将主机的目录挂载到 ...
- [Erlang危机](4.2)Remsh
原创文章,转载请注明出处:server非业余研究http://blog.csdn.net/erlib 作者Sunface 联系邮箱:cto@188.com Remsh There's a mechan ...
- 浅析PHP中cookie与session技术
1.cookie是什么? cookie指某些站点为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据(通常经过加密). 通俗来理解就是,你去一个专卖店或者超市买东西,然后店里给你办一张 ...
- 27.Qt时钟
myclock.h #ifndef MYCLOCK_H #define MYCLOCK_H #include <QObject> #include <QLCDNumber> # ...
- CentOS7开启网络配置
虚拟机在安装时可以开启网络 如果没有开启的话 可以通过以下操作 ip addr 查看是否开启网络 没有开启的话 cd /etc/sysconfig/network-scripts/ 然后 执行 ls ...