1.1.笔试题:
1.1.1 什么是NodeJS, 以及优缺点和特点?
简单来说Node.js就是运行服务端的Javascript。Node.js是一个基于Chrome Javascript运行时建立的一个平台,是一个事件驱动I/O服务端Javascript环境。基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
NodeJs特点:
- 1.它是一个Javascript运行环境
- 2.依赖于Chrome V8引擎进行代码解释
- 3.事件驱动
- 4.非阻塞I/O
- 5.轻量、可伸缩,适于实时数据交互应用
- 6.单进程,单线程
NodeJS优缺点:
优点:
- 1.高并发(最重要的优点)。
- 2.适合I/O密集型应用。
缺点:
- 1.不适合CPU密集型应用。
CPU密集型应用给Node带来的挑战主要是:由于JavaScript单线程的原因,如果有长时间运行的计算(比如大循环),将会导致CPU时间片不能释放,使得后续I/O无法发起。
解决方案:分解大型运算任务为多个小任务,使得运算能够适时释放,不阻塞I/O调用的发起。 - 2.只支持单核CPU,不能充分利用CPU。
- 3.可靠性低,一旦代码某个环节崩溃,整个系统都崩溃。原因:单进程,单线程。
解决方案:(1)Nnigx反向代理,负载均衡,开多个进程,绑定多个端口;(2)开多个进程监听同一个端口,使用cluster模块。 - 4.开源组件库质量参差不齐,更新快,向下不兼容。
- 5.Debug不方便,错误没有stack trace
1.1.2 NPM是什么?它的好处?
npm是node.js的包管理工具,负责插件的更新、下载、卸载、发布和撤销等,允许用户从npm服务器上下载别人编写的第三方包到本地使用,或者将自己编写的包或命令行发布出去给别人使用。下载了node.js后,npm是其自带的,直接使用npm命令行使用插件即可。
具体思路步骤:
买个服务器作为代码仓库(registry),在里面放所有需要被共享的代码
发邮件通知 jQuery、Bootstrap、Underscore 作者使用 npm publish 把代码提交到 registry 上,分别取名 jquery、bootstrap 和 underscore(注意大小写)
社区里的其他人如果想使用这些代码,就把 jquery、bootstrap 和 underscore 写到 package.json 里,然后运行 npm install ,npm 就会帮他们下载代码
下载完的代码出现在 node_modules 目录里,可以随意使用了。
这些可以被使用的代码被叫做「包」(package),这就是 NPM 名字的由来:Node Package(包) Manager(管理器)。
优点:
允许用户从NPM服务器下载别人编写的第三方包到本地使用。
允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。
通过NPM,你可以安装和管理项目的依赖,并且能够指明依赖项的具体版本号。 对于Node应用开发而言,你可以通过package.json文件来管理项目信息,配置脚本, 以及指明项目依赖的具体版本。
1.1.3 ES5和ES6的区别,说一下你所知道的ES6
ES6, 全称 ECMAScript 6.0 ,是 JavaScript 的下一个版本标准,2015.06 发版。
ES6 主要是为了解决 ES5 的先天不足,比如 JavaScript 里并没有类的概念等等。
ES6增加了许多新的特性,如果大家想要深入的进行学习,可以进行一下的教程进行学习:)
ES6:https://es6.ruanyifeng.com/
下面我简单说一下我使用的比较频繁的ES6部分。
1.Template Literals(模板对象)
es6之前定义模版字符串要这样写(其中first和last 是变量)
var name = 'Your name is ' + first + ' ' + last + '.';
var url = 'http://localhost:3000/api/messages/' + id;
es6中使用新的语法${ },就简单多啦,注意es6中的模版字符串用得是反引号``(位置如图)
var name = `Your name is ${first} ${last}. `;
var url = `http://localhost:3000/api/messages/${id}`;
2.Destructuring Assignment (解构赋值)
在es5中是这样写的
var data = $(‘body‘).data(), // data has properties house and mouse
house = data.house,
mouse = data.mouse;
在nodejs中是这样的
var jsonMiddleware = require(‘body-parser‘).jsonMiddleware ;
var body = req.body, // body has username and password
username = body.username,
password = body.password;
在es6中就简化了很多
var { house, mouse} = $(‘body‘).data(); // we‘ll get house and mouse variables
var {jsonMiddleware} = require(‘body-parser‘);
var {username, password} = req.body;
同样适用于数组
var [col1, col2] = $('.column'),
[line1, line2, line3, , line5] = file.split(‘n‘);
3.Arrow Functions in(箭头函数)
在ES6中,有了丰富的箭头函数。这些丰富的箭头是令人惊讶的因为它们将使许多操作变成现实,比如,以前我们使用闭包,this总是预期之外地产生改变,而箭头函数的迷人之处在于,现在你的this可以按照你的预期使用了,身处箭头函数里面,this还是原来的this。有了箭头函数在ES6中, 我们就不必用that = this或 self = this 或 _this = this 或.bind(this)。
箭头函数提供了一种更加简洁的函数书写方式。基本语法是:
参数 => 函数体
箭头函数体中的 this 对象,是定义函数时的对象,而不是使用函数时的对象。
var func = () => {
// 箭头函数里面没有 this 对象,
// 此时的 this 是外层的 this 对象,即 Window
console.log(this)
}
func(55) // Window
var func = () => {
console.log(arguments)
}
func(55); // ReferenceError: arguments is not defined
function fn(){
setTimeout(()=>{
// 定义时,this 绑定的是 fn 中的 this 对象
console.log(this.a);
},0)
}
var a = 20;
// fn 的 this 对象为 {a: 19}
fn.call({a: 18}); // 18
不可以作为构造函数,也就是不能使用 new 命令,否则会报错。
适合使用的场景
ES6 之前,JavaScript 的 this 对象一直很令人头大,回调函数,经常看到 var self = this 这样的代码,为了将外部 this 传递到回调函数中,那么有了箭头函数,就不需要这样做了,直接使用 this 就行。
// 回调函数
var Person = {
'age': 18,
'sayHello': function () {
setTimeout(function () {
console.log(this.age);
});
}
};
var age = 20;
Person.sayHello(); // 20
var Person1 = {
'age': 18,
'sayHello': function () {
setTimeout(()=>{
console.log(this.age);
});
}
};
var age = 20;
Person1.sayHello(); // 18
所以,当我们需要维护一个 this 上下文的时候,就可以使用箭头函数。
我就先说这么多吧,ES6还有非常多的新特性值得我们去学习和使用,比如说Class累,比如说Promise对象等等等。我们需要深入的去学习。
1.1.4 var、let、const之间的区别
在了解它们三个之间的区别的时候我们需要先来了解一下什么是变量提升?
JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。
JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明。
一、var声明变量存在变量提升,let和const不存在变量提升
console.log(a); // undefined ===> a已声明还没赋值,默认得到undefined值
var a = 100;
console.log(b); // 报错:b is not defined ===> 找不到b这个变量
let b = 10;
console.log(c); // 报错:c is not defined ===> 找不到c这个变量
const c = 10;
再来看这段代码
function fn() {
//var a
if (true) {
console.log(a + ' now')
}
else {
var a = 1
console.log(2)
}
}
fn() // a -> undefined
我们发现不执行的代码也会影响会执行的代码,因为var a会提升到if语句的前面
undefined可以翻译为不明确,not defined可以翻译为未定义
在Java中变量的分为全局变量(成员变量)或者局部变量,在方法体中定义的变量都是局部变量,否则是全局变量(即在方法体外,在类中定义的变量)
在JavaScript中,在方法体外外用var定义的变量其它方法可以共享,在方法中用var定义的变量只有该方法内生效。
二、let、const都是块级局部变量
顾名思义,就是只在当前代码块起作用
{
let a = 1
}
console.log(a) // undefined
const 的特性和 let 完全一样,不同的只是
1)声明时候必须赋值
const a
编译器报错
控制台报错
SyntaxError: Missing initializer in const declaration
2)只能进行一次赋值,即声明后不能再修改
const a=1
a=2
编译器报错
控制台报错
TypeError: Assignment to constant variable.
3)如果声明的是复合类型数据,可以修改其属性
三、同一作用域下let和const不能声明同名变量,而var可以
const a =2
const a=1
SyntaxError: Identifier 'b' has already been declared
1.1.5 介绍下Set和Map的区别?
集合(Set):
ES6 新增的一种新的数据结构,类似于数组,但成员是唯一且无序的,没有重复的值。
Set 本身是一种构造函数,用来生成 Set 数据结构。
Set 对象允许你储存任何类型的唯一值,无论是原始值或者是对象引用。
const s = new Set()
[1, 2, 3, 4, 3, 2, 1].forEach(x => s.add(x))
for (let i of s) {
console.log(i) // 1 2 3 4
}
// 去重数组的重复对象
let arr = [1, 2, 3, 2, 1, 1]
[... new Set(arr)] // [1, 2, 3]
字典(Map):
是一组键值对的结构,具有极快的查找速度。
const m = new Map()
const o = {p: 'haha'}
m.set(o, 'content')
m.get(o) // content
m.has(o) // true
m.delete(o) // true
m.has(o) // false
区别:
Set:
- 成员唯一、无序且不重复。
- [value, value],键值与键名是一致的(或者说只有键值,没有键名)。
- 可以遍历,方法有:add、delete、has。
Map:
- 本质上是键值对的集合,类似集合。
- 可以遍历,方法很多可以跟各种数据格式转换。
1.1.6 下面的输出结果是多少?
const promise = new Promise((resolve, reject) => {
console.log(1);
resolve();
console.log(2);
})
promise.then(() => {
console.log(3);
})
console.log(4);
//结果:
1
2
4
3
1.1.7 分别介绍普通函数中this和箭头函数中this?
普通函数下的this:
- 在普通函数中的this总是代表它的直接调用者,在默认情况下,this指的是window
- 在严格模式下,没有直接调用者的函数中的this是undefined使用
- call,apply,bing绑定的,this指的是绑定的对象
箭头函数中的this:
- 箭头函数没有自己的this,它的this是继承而来的,默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象。简单来说就是箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。定义它的时候,可能环境是window,也有可能是其他的。
1.1.8 什么是Buffer? 并创建长度为6个字节的Buffer对象?
JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js中,定义了一个Buffer类,该类用来创建一个专门存放二进制数据的缓存区。
const buf=Buffer.alloc(6);
console.log(buf);//<Buffer 00 00 00 00 00 00>
1.1.9 如下代码输出多个个字节?
let buf=Buffer.from('世界你好','utf8');
console.log(buf);
//<Buffer e4 b8 96 e7 95 8c e4 bd a0 e5 a5 bd>
1.1.10 什么是闭包,闭包有哪些用处?
了解闭包,我们先来看看Javascript的变量作用域。
变量分为: 全局变量 和 局部变量。Javascript的特殊之处在于:每个函数都会创建一个新的作用域,函数内部可以读取函数外部的变量,相反 函数外部无法读取内部变量。
var a = 123;
function fun(){
console.log(a);
}
fun(); // 输出123,函数内部的a在自身找不到,会跳到外部全局中去找。
function foo(){
var b = 345;
}
console.log(b);
// error, 全局作用域中并无 b 这个变量,b只产生于 foo 这个函数作用域中。
闭包:
所谓“闭包”,指的是一个父函数嵌套着另一个子函数,那么这个子函数也是这个父函数表达式的一部分,可以理解为嵌套函数和函数作用域链。
正常来说,一个嵌套函数,内部的子函数不能被外部作用域引用,但如果,把这个子函数作为一个返回值传给父函数,那么全局作用域就能执行这个子函数内的结果了。
用一句话来说就是:如果一个函数用到了它作用域外面的变量,那么这个变量和这个函数之间的环境就叫闭包。
闭包的用处:
1.模仿块级作用域
所谓块级作用域就是指在循环中定义的变量,一旦循环结束,变量也随之销毁,它的作用范围只在这一小块。而在JavaScript中没有这样的块级作用域,由于JavaScript不会告诉你变量是否已经被声明,所以容易造成命名冲突,如果在全局环境定义的变量,就会污染全局环境,因此可以利用闭包的特性来模仿块级作用域。
在上面的代码中,闭包就是那个匿名函数,这个闭包可以当函数X内部的活动变量,又能保证自己内部的变量在自执行后直接销毁。这种写法经常用在全局环境中,可以避免添加太多全局变量和全局函数,特别是多人合作开发的时候,可以减少因此产生的命名冲突等,避免污染全局环境。
2.储存变量
闭包的另一个特点是可以保存外部函数的变量,内部函数保留了对外部函数的活动变量的引用,所以变量不会被释放。
这种写法可以用在把一些不经常变动计算起来又比较复杂的值保存起来,节省每次的访问时间。
3.封装私有变量
我们可以把函数当作一个范围,函数内部的变量就是私有变量,在外部无法引用,但是我们可以通过闭包的特点来访问私有变量。
1.1.11 你知道的fs有哪些常用的方法(至少5个)
fs.readFile()
- 读取文件内容
fs.writeFile()
- 文件写入方法
fs.mkdir(path[, options], callback)
- 异步地创建目录。
fs.stat(path[, options], callback)
- 读取文件状态
fs.open(path, flags[, mode], callback)
- 异步地打开文件
1.1.12 node中的异步和同步怎么理解?
什么是同步?
同步:上一步执行完后下一步才能得到执行。
什么是异步?
异步:将比较复杂的任务制作成任务线程,以任务线程实现,不用等上一句执行完,下一句也可以执行。
下面举两个例子展示同步与异步的不同之处。
建一个txt文件随便写几个字后保存。
展示同步操作,建立test.js文件,内容如下:
var fs = require("fs");
var data = fs.readFileSync('test.txt');
console.log(data.toString());
console.log("程序执行结束");
在终端中运行test.js文件,输出内容如下:
展示异步操作,建立test1.js文件,内容如下:
var fs = require("fs");
fs.readFile('test.txt',function(err,data){
if(err) return console.error(err);
console.log(data.toString());
});
console.log("非阻塞代码实例运行成功");
在终端中运行test1.js文件,输出内容如下:
node中同步异步的区别:同步就是程序自上而下运行,而异步不用等待上面的程序运行完就运行下面的操,异步编程依托于回调来实现。
1.1.13 express response有哪些常用方法?
Express:
1、send()方法: send 方法向浏览器发送一个响应信息,并可以智能处理不同类型的数据 send方法在输出响应时会自动进行一些设置,比如HEAD信息、HTTP缓存支持等等 类型可以是: String, Array, Object, Number. 当参数为一个String时,Content-Type默认设置为"text/html" 当参数为Array或Object时,Express会返回一个JSON 当参数为一个NumberExpress会帮你设置一个响应体,比如:200。
2、req.body:body不是nodejs默认提供的,你需要载入body-parser中间件才可以使用req.body,这个方法通常用来解析POST请求中的数据。
3、req.query:由nodejs默认提供,无需载入中间件,这个方法通常用来解析get请求中的数据。
4、req.params:传递参数给服务器,但是这不算是传统标准规范的做法,是属于 HTTP Routing 的延伸应用。
Response:
1、告诉浏览器数据类型 setContentType()
2、设置respon的编码格式 setCharacterEnconding()
3、返回服务器的预设错误网址并显示错误信息 sendError()
4、重定向页面 sendRedirect()
5、获取通向浏览器的字节流 getOutputStream()
6、获取通向浏览器的字符流 getWriter()
7、回传路径 encodeRedirectURL()
8、setHeader()设置消息头
9、setStatus()设置状态
10、addCookie()添加Cookie
11、res.end()
12、res.send()
1.1.14 node有哪些核心模块?
- path
- fs
- buffer
- http
- url
1.1.15 说一下get和post的区别以及何时使用post?
二者主要的区别如下:
1、Get 是用来从服务器上获得数据,而 Post 是用来向服务器上传递数据。
2、Get 将表单中数据的按照 variable=value 的形式,添加到 action 所指向的 URL 后面,并且两者使用“?”连接,而各个变量之间使用“&”连接;Post 是将表单中的数据放在 form 的数据体中,按照变量和值相对应的方式,传递到 action 所指向 URL。
3、Get 是不安全的,因为在传输过程,数据被放在请求的 URL 中,而如今现有的很多服务器、代理服务器或者用户代理都会将请求URL记录到日志文件中,然后放在某个地方,这样就可能会有一些隐私的信息被第三方看到。另外,用户也可以在浏览器上直接看到提交的数据,一些系统内部消息将会一同显示在用户面前。Post 的所有操作对用户来说都是不可见的。
4、Get 传输的数据量小,这主要是因为受 URL 长度限制;而 Post 可以传输大量的数据,所以在上传文件只能使用 Post(当然还有一个原因,将在后面的提到)。
5、Get 限制 Form 表单的数据集的值必须为 ASCII 字符;而 Post 支持整个 ISO10646 字符集。
6、Get 是 Form 的默认方法。
使用 Post 传输的数据,可以通过设置编码的方式正确转化中文;而 Get 传输的数据却没有变化。我们今后在程序中一定要注意这点。
7、Get方法会产生一个TCP数据包,浏览器会把Header和Data一并发送出去,服务器响应200(OK),并回传相应的数据。
Post方法会产生两个TCP数据包,浏览器会先将Header发送出去,服务器响应100(Continue)后,浏览器再发送Data,服务器响应200(OK),并回传相应的数据。
何时使用post?
- 无法使用缓存文件(更新服务器上的文件或数据库)
- 向服务器发送大量数据(POST 没有数据量限制)
- 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠
- 请求的结果有持续性的副作用,例如,数据库内添加新的数据行。
- 要传送的数据不是采用7位的ASCII编码。
1.2.编程题:
1.2.1 封装一个方法 去除数组中重复的元素
ES6提供了新的数据结构Set。类似于数组,只不过其成员值都是唯一的,没有重复的值。
利用Set方法进行数组去重写的代码很少,比较简洁。
let arr=[1,1,2,2,3,6,7]
function newArr(arr){
return Array.from(new Set(arr))
}
console.log(newArr(arr));//[1, 2, 3, 6, 7]
1.2.2 有Student 和Person 两个类, Person 类有name 属性和sayHello方法, Student 类继承自Person 类. 分别使用ES5 和ES6 的语法实现
ES5写法:
function Person(name, age) {
this.name = name;
this.age = age;
}
// 函数 sayHello 写在 原型中
Person.prototype.sayHello = function () {
console.log(`Hello,大家好, 我叫 ${this.name},我今年${this.age}`);
}
var person1 = new Person('zhangsna', 18);
// var person2 = new Person('王麻子',25);
console.log(person1);
person1.sayHello()
ES6写法:
ES6中添加 class的概念。注意JS中的class,本质上就是基于 原型做了进一步的封装。
class Person {
// 用来创建 ===> 实例化 一个对象
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`天生我材必有用, 一直不知怎么用 大家好, 我叫${this.name},今年${this.age}`);
}
}
var person1 = new Person('张无忌', 26);
// console.log(person1.name);
person1.sayHello()
// extends 实现继承 父类
class Student extends Person {
// 自定义构造器==> constructor()
constructor(name, age, stuId) {
super(name,age); // 指向的是 父类的 构造函数 constructor
this.stuId = stuId;
}
study() {
console.log(`${this.name},学号:${this.stuId}`);
}
}
const s1 = new Student('周芷若', 19, 110);
console.log(s1.name);
s1.study()
1.2.3 通过代码创建一个网站基本结构
要求如下:
css文件夹 img文件夹 js文件夹 index.html页面
//require()导入模块
//导入路径操作模块
const path = require('path');
//导入文件操作系统 模块
const fs = require('fs');
//文件操作
//初始化目录结构
//img css js
//创建项目 存储的目录地址
let root = 'C:\Users\EDZ\Desktop\Practise\pracise1017';
let initData = {
projectName:'mydemo',
data:[
{name:'img',type:'dir'},
{ name: 'css', type: 'dir' },
{ name: 'js', type: 'dir' },
{name:'index.html',type:'file'}
// dir指向的是当前执行的父级路径,file指向的是当前执行脚本路径,
]
}
// path.join() 方法会将所有给定的 path 片段连接到一起
// 创建项目的根路径
// fs.mkdir(path.join('C:\Users\EDZ\Desktop\Practise\pracise1017','mydemo'));
fs.mkdir(path.join(root,initData.projectName),(err)=>{
if(err){
return;
}
});
let fileContent=`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
`;
//创建子路径和文件
initData.data.forEach((item)=>{
if (item.type=='dir') {
//创建子目录
fs.mkdirSync(path.join(root,initData.projectName,item.name))
} else if(item.type=='file'){
//创建文件 并写入内容
fs.writeFileSync(path.join(root,initData.projectName,item.name),fileContent)
}
})
1.2.4 做一个成绩查询案例,根据学号查询学员成绩 并展示到搜索框的下面
(注: 使用JSON数据存储学员成绩,使用模板引擎art-template渲染数据)
index.js:
const template = require('art-template');
const http = require('http')
const path = require('path');
const queryString = require('querystring');
const scoreData = require('./data.json');
// createServer() 这个方法时 http模块提供的一个方法 可以用来创建服务端的请求和响应
http.createServer((req, res) => {
// 路由(请求路径+请求的方式)
if (req.url.startsWith('/query') && req.method == 'GET') {
let content = template(path.join(__dirname, 'view', 'index.art'), {})
res.end(content);
} else if (req.url.startsWith('/score') && req.method == 'POST') {
// 获取成绩的结果 /score
let pdata = '';
// 请求数据时 触发的事件data
// 将 post请求 传递过来的数据 使用变量 pdata接受
req.on('data', (chunk) => {
pdata += chunk;
});
// 请求数据结束时 触发的事件
req.on('end', () => {
// console.log('================='+pdata);
// 将字符串类型的数据 转换为 对象类型
let obj = queryString.parse(pdata);
// console.log(obj); {code:'no123'}
// 将 obj对象下code属性 获取到code对应的值
let result = scoreData[obj.code];
console.log(result);
// 将返回的结果 result 写在 页面中 result.art
let content = template(path.join(__dirname, 'view', 'result.art'), result)
res.end(content);
})
} else if (req.url.startsWith('/all') && req.method == 'GET') {
// 全部成绩
// console.log(req.url);
console.log(scoreData);
let content = template(path.join(__dirname, 'view', 'list.art'), {
list:[scoreData.no123,scoreData.no124,scoreData.no125,scoreData.no126]
})
// console.log(content);
res.end(content);
}
// res.end('服务器异常');
}).listen(3000, () => {
console.log('running.....');
})
index.art:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="http://localhost:3000/score" method="POST">
请输入考号:<input type="text" name="code"/>
<input type="submit" value="查询">
</form>
<div>
<a href="http://localhost:3000/all">全部成绩</a>
</div>
</body>
</html>
result.art:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>成绩结果</title>
</head>
<body>
<div>
<ul>
<li>语文: {{chinses}}</li>
<li>数学: {{math}}</li>
<li>外语: {{english}}</li>
<li>综合: {{summary}}</li>
</ul>
</div>
</body>
</html>
list.art:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
{{each list}}
<ul>
<li>语文:{{$value.chinses}}</li>
<li>数学:{{$value.math}}</li>
<li>外语:{{$value.english}}</li>
<li>综合:{{$value.summary}}</li>
</ul>
{{/each}}
</div>
</body>
</html>
data.json:
{
"no123":{
"chinses":"110",
"math":"140",
"english":"129",
"summary":"239"
},
"no124":{
"chinses":"100",
"math":"140",
"english":"129",
"summary":"239"
},
"no125":{
"chinses":"100",
"math":"140",
"english":"129",
"summary":"239"
},
"no126":{
"chinses":"100",
"math":"140",
"english":"129",
"summary":"239"
}
}
1.2.5 模拟用户登录实现账户和密码的验证
index.js:
//登录验证(前端+后端+数据库)
const express=require('express');
const app=express();
const db=require('./db.js')
//引用第三方的中间件
const bodyParser=require('body-parser');
//use() 挂载中间件
app.use(bodyParser.urlencoded({extended:false}));
//挂载内置的中间件 处理静态资源文件托管
app.use(express.static('public'))
//请求的接口地址 规划
app.post('/check',(req,res)=>{
console.log(req.body);
//获取post请求的参数
let param=req.body;
//登录 就是根据用户名和密码进行查询
let sql = 'select count(*) as total from user where username=? and password=?';
let data = [param.username, param.pwd];
db.base(sql, data, (result) => {
console.log(result);
if (result[0].total == 1) {
res.send('login success!');
} else {
res.send('login failure!');
}
})
})
app.listen(3000, () => {
console.log('running....');
})
db.js:
const mysql = require('mysql');
// exports 向外部 暴露成员(字段,函数,对象)
exports.base = (sql, data, callback) => {
//创建数据库连接
const connection = mysql.createConnection({
host: 'localhost', // 数据库所在的服务器的域名或者ip地址
user: 'root', // 登录数据库的账号
password: '1234567', // 登录数据库的密码
database: 'mybook' // 数据库名称
})
// 执行连接操作
connection.connect();
// 操作数据库(数据库的操作是异步的)
connection.query(sql, data, function (error, results, fields) {
if (error) throw error;
callback(results) // 以为数据的操作时异步的 所以在这里创建了回调函数
})
// 关闭数据库连接
connection.end();
}
login.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="http://localhost:3000/check" method="post">
<label for="">账户:</label>
<input type="text" name="username" id=""><br>
<label for="">密码:</label>
<input type="password" name="pwd" id=""><br>
<input type="submit" value="登录">
</form>
</body>
</html>
数据库建表:
1.2.6 使用Express搭建服务 并实现以下路由分发
/ get请求
/login get请求
/register post请求
/index get请求
/about get请求
var app =require('express')();
app.get('/',(req,res)=>{
res.send('Hello express')
})
app.get('/login',(req,res)=>{
res.send('Login')
})
app.post('/register',(req,res)=>{
res.send('Register')
})
app.get('/index',(req,res)=>{
res.send('Index')
})
app.get('/about',(req,res)=>{
res.send('About')
})
//不限制任何请求方法use
app.use('/all',(req,res)=>{
res.send('Use')
})
app.get('/news/:year/:month/:day',(req,res)=>{
res.send(req.params);
})
app.listen(3001,()=>{
console.log('running......');
})