第二天

一、复习:

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

我们刚才学习了,模块就是一些功能的封装,所以一些成熟的、经常使用的功能,都有人封装成为了模块。

www.npmjs.com

去社区搜索需求,然后点进去看api

..

  1. 我们的依赖包,可能在随时更新,我们永远想保持更新。
  2. 项目越来越大的时候,给别人看的时候,没有必要再次共享我们引用的第三方模块。

所以我们用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的更多相关文章

  1. Node_进阶_8

    Node进阶第八天 一.复习 Node.js特点:单线程.异步I/O(非阻塞I/O).事件驱动(事件环). 适合的程序:就是没有太多的计算,I/O比较多的业务. 举例:留言本.考试系统.说说.图片裁切 ...

  2. Node_进阶_7

    Node进阶第七天 一.复习 一.索引   数据库中,根据一个字段的值,来寻找一个文档,是很常见的操作.比如根据学号来找一个学生.这个学号是唯一的.只要有学号,就能唯一确认一个学生的文档.学号这个属性 ...

  3. Node_进阶_6

    Node进阶第六天 一.复习 cookie是在res中设置,req中读取的.第一次的访问没有cookie. cookie的存储大小有限,kv对儿.对用户可见,用户可以禁用.清除cookie.可以被篡改 ...

  4. Node_进阶_5

    Node进阶第五天 为什么mysql不用开mongod –dbpath xx… 答:因为mysql会在”服务”中运行,也就是开机时自动启动并且长久驻扎在内存中了. mongodb其实也能通过设置来设成 ...

  5. Node_进阶_4

    Node进阶第四天 一.传统数据库技术回顾 数据库就是存储数据的,那么存储数据用txt就行了啊,为什么要有数据库? 理由之一:数据库有行.列的概念,数据有关系,数据不是散的. 老牌数据库,比如Mysq ...

  6. React-Native进阶_2.加载指示动画 ActivityIndicator

    在安卓原始 App中使用的加载框 ProgressBar 在React -Native 中也是有相对应的视图,叫做ActivityIndicator,对应ios 中React-Native 提供的是  ...

  7. Node_进阶_1

    第一天 1.1简介 Node.js简介 V8引擎本身就是用于Chrome浏览器的JS解释部分,Ryan Dahl把这个V8搬到了服务器上,用于做服务器的软件. Node.js是一个让Javascrip ...

  8. Node_进阶_3

    Express框架: 一.   Express框架 Express框架是后台的Node框架,类似于JS中的jquery. #原生Node开发会有很多问题: 1呈递静态页面很不方便,需要处理每个HTTP ...

  9. 网易云课堂_C语言程序设计进阶_第二周:指针:取地址运算和指针、使用指针、指针与数组、指针与函数、指针与const、指针运算、动态内存分配_2信号报告

    2 信号报告(5分) 题目内容: 无线电台的RS制信号报告是由三两个部分组成的: R(Readability) 信号可辨度即清晰度. S(Strength)    信号强度即大小. 其中R位于报告第一 ...

随机推荐

  1. 如何在php中优雅的地调用python程序

    1.准备工作   安装有python和php环境的电脑一台. 2.书写程序. php程序如下 我们也可以将exec('python test.py') 换成 system('python test.p ...

  2. 解决AttributeError: 'module' object has no attribute 'main' 安装第三方包报错

    1.找到pycharm 目录下的 \helper\packaging_tool.py 文件 2.用新版pycharm 的packaging_tool.py 替换 旧版 同名文件 文件代码如下: imp ...

  3. 滚动效果--marquee的使用

    1. <marquee></marquee>标签,默认从最右侧往左滚动: 2. marquee 支持的属性 (1)behavior设置滚动方式: <marquee beh ...

  4. springboot 不使用前端模板直接跳转页面

    1.创建springboot项目 2.在resource 下创建pages文件夹,存放所有页面 3.编写后台代码 4.访问http://localhost:8080/index,即可跳转到页面

  5. 02018_StringBuffer练习

    1.已知int[] arr = {34,12,89,68}; 将其中的元素转成字符串,格式 [34,12,89,68]: 参考:02011_定义打印数组元素方法,按照给定的格式打印[11, 33, 4 ...

  6. OpenFace Docker 使用简介

    在Docker中使用openface最大的问题是数据与主机的交互,下面我介绍几种方法来实现主机与Docker容器的数据交互. 1.第一种也是最方便的一种方法是在进入容器时使用-v参数将主机的目录挂载到 ...

  7. [Erlang危机](4.2)Remsh

    原创文章,转载请注明出处:server非业余研究http://blog.csdn.net/erlib 作者Sunface 联系邮箱:cto@188.com Remsh There's a mechan ...

  8. 浅析PHP中cookie与session技术

    1.cookie是什么? cookie指某些站点为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据(通常经过加密). 通俗来理解就是,你去一个专卖店或者超市买东西,然后店里给你办一张 ...

  9. 27.Qt时钟

    myclock.h #ifndef MYCLOCK_H #define MYCLOCK_H #include <QObject> #include <QLCDNumber> # ...

  10. CentOS7开启网络配置

    虚拟机在安装时可以开启网络 如果没有开启的话 可以通过以下操作 ip  addr 查看是否开启网络 没有开启的话 cd /etc/sysconfig/network-scripts/ 然后 执行 ls ...