第二天

一、复习:

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. 如何添加删除子网卡eth0:1(linux案例)

    这种方法实现了单网卡多IP,我的系统是centos7的,如何添加删除子网卡IP详细请看下面操作例子 添加子网卡IP:ifconfig  ens3:1  192.168.0.100/24        ...

  2. Python数据结构1-----基本数据结构和collections系列

    1.基本数据结构 整型.浮点型.字符串.元祖.列表.字典.集合 2.高级数据结构 (collections模块) (1)计数器(counter):对字典的补充,用于追踪值的出现次数. [具备字典所有的 ...

  3. 数据库之JDBC入门

    数据表: 代码实现(注:jar包用的8.0版本) import java.sql.*; import java.util.Scanner; public class MyDatabase { publ ...

  4. C语言提高 (6) 第六天 文件(续) 链表的操作

    1昨日回顾 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include &l ...

  5. git入坑随笔

    一直以来,都喜欢用git做版本管理,主要涉及平台是coding, github以及公司自己搭建的gitlab. 因为一直以来都是自己一个人维护前端的项目,所以基本上很少有冲突的情况.(手动微笑 :) ...

  6. Windows常用软件

    目录 Uninstall Tool FACapture Unlocker Uninstall Tool Uninstall Tool 这是一款可以彻底删除应用的软件,能连通注册表内容一起删除. FAC ...

  7. Qt on Android:资源文件系统qrc与assets

    使用 Qt 为 Android 开发应用时,有时我们的应用会携带一些资源文件,如 png . jpg 等,也可能有一些配置文件,如 xml 等.这些文件放在哪里呢? 有两种方式: qrc assets ...

  8. [IOS]mac以太网连接

    今天玩了一下苹果一体机.感觉还是蛮不错的,只是.就是用以太网连接的时候遇到了一点问题.用这篇文章记录一下: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/ ...

  9. openfire 安装部署

    1. openfire安装和配置 本文介绍openfire 在linux上安装部署过程 linux上有两种安装方式,一个是RPM包方式.还有一个是tar.gz压缩包方式, 官方推荐採用RPM包方式,会 ...

  10. How to remove focus without setting focus to another control?

    How to remove focus without setting focus to another control? Ask Question up vote 67 down vote favo ...