学习Node.js的第一天

学习Node.js的第一天

一、初步认识nodejs

--------------------------------------------------------淘宝镜像源

npm config set registry https://registry.npm.taobao.org

------------------------------解决require没有自动补齐

npm install -D tslib @types/node

1.1nodejs简介

Node.js 在浏览器之外运行 V8 JavaScript 引擎(Google Chrome 的内核)。 这使得 Node.js 的性能非常好。
node.js是一个独立的运行环境,无法调用DOM和BOM浏览器内置API
在这里插入图片描述

检测nodejs是否安装成功cmd中node -v

二、fs模块

2.1读取指定文件中的内容

无论读取成功失败都会执行回调函数,第一个形参代表失败的结果,第二是成功的结果

//路径 编码(可选参数) 回调函数
fs.readFile(path,[options],callback)

读取文件

const fs = require('fs');
fs.readFile('./01fs读取文件中的内容.js','utf-8',function (err,data){
    console.log(err);//失败
    console.log(data);//成功
})

2.2在文件中写入内容

// 文件路径 写入的内容  编码(可选参数)  回调函数
fs.writeFile(file,data[options],callback)

指定路径写入文件

const fs = require('fs');
const data =' 123456'
fs.writeFile('./1.txt',data,function (err){
    if(!err){
        console.log('文件写入成功')
    }
})

2.3整理成绩小案例

const fs = require('fs');
fs.readFile('./03成绩.txt','utf-8',function (err,data){
   if(!err){
       console.log('文件读取成功'+data);
   }else {
       console.log('文件读取失败'+err);
   }
   //1.将文件里面的数据以,进行分割
   const strdata1 = data.split(',');     //这里会自动生成一个数组来装数据,
    console.log(strdata1)
    //2.弄一个新数组来装   咱们把数据里面的等号用冒号替换
    const strdata2 = [];
    strdata1.forEach(item => {
        strdata2.push(item.replace('=',':'));
    })
    console.log(strdata2);
    //3.将文件的里面的每一个数据弄成一行显示
    const newdata = strdata2.join('\r\n');
    console.log(newdata);
    fs.writeFile('./03成绩导出.txt',newdata,function (err){
        if(!err) {
            console.log('文件写入成功')
            console.log(data);
        }
    })
})

文件前后对比
在这里插入图片描述

2.4路径问题

我们在使用fs模块的时候如果有./或者…/这种相对的路径的时候
我们在使用node 运行js文件的时候会出现路径动态拼接错误
这里出现的错误就是我们使用node执行这个js文件时是以当前路径去查找
在这里插入图片描述
我们如果使用/是不会出现这种问题的
在这里插入图片描述
也开以提供一个完整的文件存放路径(当然这种操作会被开除)
我们要__dirname(表示当前文件所处的目录)
在这里插入图片描述
在写入文件时候一样会出现文件动态路径拼接问题
在这里插入图片描述
所以我们使用__dirname
在这里插入图片描述

三、path模块

3.1多个路径拼接在一起

path.join()方法可以拼接路径,以后我们也可以使用这个方法在文件读写上进行路径拼接。顺便提一下__filename
在这里插入图片描述

3.2获取路径中的最后一部分

path.basename()方法,获取路径的文件名部分

const path = require('path');
const str = '/a/b/c/index.js';
const str1 = path.basename(str);
console.log(str1);
const str2 = path.basename(str,'.js');  //干掉后缀js
console.log(str2);

在这里插入图片描述

3.3获取路径中的文件扩展名

path.extname获取扩展名

const path = require('path');
const str = '/a/b/c/index.js';
console.log(path.extname(str));

在这里插入图片描述

3.4分析需求,读取文件内容

将一个html网页分成css和html和js三个部分
在这里插入图片描述

//将我们的old1.html这个文件中的css和body和js三个模块中的内容提取出来
const fs = require('fs');
const path = require('path');
//     \s空白字符  \S非空白字符  *匹配任意次  <后面的\是转义字符防止/和最后的/冲突
const style=/<style>[\s\S]*<\/style>/;
const script = /<script>[\s\S]*<\/script>/;
//1.读取整个html文件
fs.readFile(path.join(__dirname,'file/old1.html'),'utf-8',function (err,data){
    if(err){
        console.log('读取文件失败');
    }else{
        resolveCss(data);
        resolveJs(data);
        resolveHtml(data);
    }
})
function resolveCss(css){
    // exec() 方法用于检索字符串中的正则表达式的匹配。
    // 如果字符串中有匹配的值返回该匹配值,保存在数组下标0里面,否则返回 null。
    const r1 = style.exec(css);
    //我们把开始和结束两个标签替换成空格
    const newr1 = r1[0].replace('<style>','').replace('</style>','');
    fs.writeFile(path.join(__dirname,'/file/1.css'),newr1,function (err){
        if(!err){
            console.log('css保存成功')
        }
    })
}
function resolveJs(js){
    // exec() 方法用于检索字符串中的正则表达式的匹配。
    // 如果字符串中有匹配的值返回该匹配值,保存在数组下标0里面,否则返回 null。
    const r1 = script.exec(js);
    //我们把开始和结束两个标签替换成空格
    const newr1 = r1[0].replace('<script>','').replace('</script>','');
    fs.writeFile(path.join(__dirname,'/file/1.js'),newr1,function (err){
        if(!err){
            console.log('js保存成功')
        }
    })
}
function resolveHtml(html){
    //对style和script两个标签里面的内容做一个替换
    const newhtml = html.replace(style,'<link rel="stylesheet" href="1.css">')
        .replace(script,'<script src="1.js"></script>');
    fs.writeFile(path.join(__dirname,'/file/1.html'),newhtml,err => {
        if(!err){
            console.log('1.html文件保存成功');
        }
    })
}

四、http模块

4.1什么是http模块

在网络节点中,负责消耗资源的叫客户端。负责对外提供资源的叫服务器。

4.2进一步理解http模块的作用

服务器和普通电脑的区别在于,服务器上安装了web服务器软件
例如IIS、Apache,通过这些服务器软件,就能把一台普通的电脑变成一台web服务器

4.3ip地址就是互联网上每台电脑唯一的地址,采用点分十进制。

127.0.0.1对应的域名是localhost,都代表我们自己的电脑
端口号的作用
在这里插入图片描述

4.4使用node创建最基本的web服务器

//引入http模块
const http =require('http');
//为服务器创建实例
const app = http.createServer();
//为服务器绑定request事件,监听客户端请求
app.on('request', (req,res) => {
    console.log('hello world');
})
//设置端口号,启动服务器
app.listen(3000,function (){
    console.log('服务器启动成功~');
})

启动服务器之后,访问这个127.0.0.1:3000这个域名就会打印hello world
在这里插入图片描述

4.4.1req请求对象

req请求对象包含了客户端的相关数据和属性
url是端口号后面的数据
这条代码写在app.on监听客户端请求里面

console.log(你的请求url地址${req.url},你的请求方式是${req.method});

在这里插入图片描述

4.4.2res响应对象

res.end向客户端发送指定内容,并结束这次请求的处理过程。

const str = `Your request url is ${req.url},and method is ${req.method}`;
    res.end(str);

在这里插入图片描述

4.4.3设置响应头解决中文乱码

app.on('request', (req,res) => {
    const str = `你的请求url地址${req.url},你的请求方式是${req.method}`;
    //响应头设置Content-Type的值为text/html;charset=utf-8  可以解决中文乱码
    res.setHeader('Content-Type','text/html;charset=utf-8');
    res.end(str);
})

在这里插入图片描述

4.5根据不同的url来响应不同的html页面

const http =require('http');
const app = http.createServer();
app.on('request', (req,res) => {
    let content = '<h1>404找不到网页</h1>';
    const url = req.url;
    if (url === '/'){
        content= '<h1>欢迎访问首页</h1>'
    }else if(url === '/about.html'){
        content= '<h1>欢迎访问更多页面</h1>'
    }
    res.setHeader('Content-Type','text/html;charset=utf-8');
    res.end(content);
})
app.listen(3000,function (){
    console.log('服务器启动成功~');
})

在这里插入图片描述

4.6实现网页响应的web服务器

在这里插入图片描述

const fs = require('fs');
const path =require('path');
const http =require('http');
const app = http.createServer();
app.on('request', (req,res) => {
    let content = '<h1>404找不到网页</h1>';
    const url =req.url;
    //把请求的url地址映射为具体的文件路径
    fs.readFile(path.join(__dirname,'/file',url),'utf-8',(err,data) => {
        if(err) return res.end(content);
        content=data;
        res.end(content);
    })
})
app.listen(3000,function (){
    console.log('服务器启动成功~');
})

在这里插入图片描述

五、模块化代码

5.1模块的分类require的使用

加载别的模块,会执行别的模块里面的代码
在这里插入图片描述

5.2模块作用域和module

5.2.1模块作用域

模块作用域和函数作用域差不多,在模块自定义的变量、方法等成员,只能在当前模块访问,别的模块访问不到的
在这里插入图片描述
好处就是防止全局变量污染,例如你导入的两个模块对同一个变量名定义了不同的值

5.2.2module对象

在每个自定义的js文件中都有module对象,他储存l当前模块的有关信息
在这里插入图片描述
moudle.exprots可以使用这个将模块的成员共享出去
require导入的自定义模块,就是这个moudle.exports对象
在这里插入图片描述
使用require导入模块的时候,导入的结果永远以module.exports指向的对象为准
可以这样理解前面两个是给对象添加属性,后面的那个是给对象重新赋值
在这里插入图片描述
module.exports和exprots指向同一个对象,因为这里两个都是空对象
在这里插入图片描述

5.2.3使用误区

使用require导入的时候,永远得到的是module.exports指向的对象
误区一
在这里插入图片描述

exports.name='张山';
module.exports={
    nikename:'小黑',
    age:18
}
console.log(exports);
console.log('----------')
console.log(module.exports)
console.log('----------')
console.log(module.exports === exports);

在这里插入图片描述

误区二、
在这里插入图片描述

误区三、这里与一不同的是这个module.exports并没有指向一个对象
在这里插入图片描述
误区四、

误区四张图
在这里插入图片描述

5.3CommonJs介绍

在这里插入图片描述

5.4包介绍

5.4.1安装所有包

npm install

这个命令会读取package.json的依赖包并且全部下载

5.4.2卸载指定包

npm uninstall

这个命令会卸载所有的包

第三方的模块又叫包。
包也是基于内置模块封装出来的,是为了提供我们的开发效率。
最大的包网站npmjs.com.
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.5包配置文件管理

在这里插入图片描述
dependencies节点
在这里插入图片描述
在这里插入图片描述
如何判断我们的包项目上线之后会不会用到,其实npmjs.com在安装的代码就会告诉我们
在这里插入图片描述

5.6解决下包慢的问题

原因分析
在这里插入图片描述
解决方案

// 配置npm代理来提高速度,设置淘宝镜像
npm config set registry https://registry.npm.taobao.org
// 查看配置是否成功
npm config get registry

在这里插入图片描述

5.6.1查看和切换下包镜像源

在这里插入图片描述

5.7npm与包(md文件的转换)

全局包安装的位置

C:\Users\A\AppData\Roaming\npm\node_modules

将md文件转换为html的小工具 -o是转换完成后在浏览器自动打开
在这里插入图片描述
规范包的使用
在这里插入图片描述

5.8模块加载机制

在这里插入图片描述
注意:内置模块加载优先级是最高的

六、express模块

6.1express的基本操作

安装express

npm i express

const express = require('express');
const app = express();
app.listen(30000,() => {
    console.log('服务器启动成功');
})

6.2监听GET和POST请求

GET请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
</body>
</html>
<script>
    function main(){
        const xhr = new XMLHttpRequest();
        xhr.open('GET','http://127.0.0.1:3000/get?a=200');
        xhr.send();
        //on when 当什么时候
        //readstate 是 xhr中的属性  表示状态 0 1 2 3 4
        //change 改变
        xhr.onreadystatechange = function (){
            //判断服务器响应了所有的结果
            if(xhr.readyState===4){
                if (xhr.status>=200&&xhr.status<300){
                    console.log(xhr.response);
                }
            }
        }
    }
    main();
</script>

在这里插入图片描述
POST请求(请求字符串和url中的动态参数)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
</body>
</html>
<script>
    function main(){
        const xhr = new XMLHttpRequest();
        xhr.open('POST','http://127.0.0.1:3000/post/1?a=200');
        xhr.send();
        //on when 当什么时候
        //readstate 是 xhr中的属性  表示状态 0 1 2 3 4
        //change 改变
        xhr.onreadystatechange = function (){
            //判断服务器响应了所有的结果
            if(xhr.readyState===4){
                if (xhr.status>=200&&xhr.status<300){
                    console.log(xhr.response);
                }
            }
        }
    }
    main();
</script>

在这里插入图片描述
多个请求字符串使用&连接
多个请求url中的动态参数
在这里插入图片描述

xhr.open('POST','http://127.0.0.1:3000/post/1/houwang');
app.post('/post/:id/:name',(request,response) => {

6.3托管静态资源

express.static()方法创建静态服务器资源
通过这个代码就可以把目录里面的文件对外开放访问

const express = require('express');
const app = express();
//调用express.static方法,快速提供静态资源
app.use(express.static('./file'));
app.listen(3000,() => {
    console.log('服务器启动成功')
})

在这里插入图片描述
访问静态资源文件的时候,按express.static()方法添加顺序去目录查找
挂载路径前缀

const express = require('express');
const path = require('path');
const app = express();
//调用express.static方法,快速提供静态资源
app.use('/05express',express.static(path.join(__dirname,'../05express模块')));
app.listen(3000,() => {
    console.log('服务器启动成功')
})

在这里插入图片描述

6.4自动重启服务器

nodemon安装参考学习AJAX的第一天

6.5express中的路由

路由客户端的请求和服务器处理函数之间的映射关系
路由三部分:请求类型,url地址,处理函数
在这里插入图片描述
路由的模块化

const express = require('express');
const router = express.Router();  //创建路由对象
router.get('/router-get',(request,response) => {
    response.send('hello world');
})
module.exports = router;  //暴露出去

在这里插入图片描述

添加路由前缀,一样的是上个js代码

const express = require('express');
const router = require('./05router模块化');
const app = express();
//app.use(); 都是用来注册全局中间件的
app.use('/router',router);
app.listen(3000,function (){
    console.log('服务器启动成功')
})

6.6express中间件介绍

中间件特指业务流程的中间处理环节
在这里插入图片描述
中间件的调用流程
在这里插入图片描述

中间件的流程
中间件函数的形参列表中必须包含next参数,路由只需要req和res
在这里插入图片描述
next函数的作用
在这里插入图片描述

6.7express中间件的初体验

6.7.1初体验

const express = require('express');
const app = express();
const nw = function (request,response,next){
    console.log('最简单的中间件');
    //流转关系,转交给下一个路由或者中间件
    next();
}
app.listen(3000,function (){
    console.log('服务器启动成功')
})

6.7.2全局中间件

客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫全局中间件。

const express = require('express');
const app = express();
const nw = function (request,response,next){
    console.log('最简单的中间件');
    //流转关系,转交给下一个路由或者中间件
    next();
}
//将nw注册为全局中间件
app.use(nw);
app.get('/',(requset,response) =>{
    response.send('hello world')
})
app.listen(3000,function (){
    console.log('服务器启动成功')
})

在这里插入图片描述

6.7.3全局中间件的简化形式

const express = require('express');
const app = express();
app.use((request,response,next) => {
    console.log('最简单的中间件');
    //流转关系,转交给下一个路由或者中间件
    next();
})
app.get('/',(requset,response) =>{
    response.send('hello world')
})
app.listen(3000,function (){
    console.log('服务器启动成功')
})

6.7.4中间件的作用

在这里插入图片描述
比如我们的每个路由都需要拿到一个时间

const express = require('express');
const app = express();
app.use((request,response,next) => {
    const startTime = new Date();
    request.time = startTime;
    //流转关系,转交给下一个路由或者中间件
    next();
})
app.get('/',(requset,response) =>{
    response.send('hello world /'+requset.time)
})
app.get('/user',(requset,response) =>{
    response.send('hello world user'+requset.time)
})
app.listen(3000,function (){
    console.log('服务器启动成功')
})

在这里插入图片描述
在这里插入图片描述

6.7.5局部中间件

在这里插入图片描述

const express = require('express');
const app = express();
const nw = (request,response,next) => {
    console.log('这是一个局部中间件函数');
    next();
}
//nw只在这个路由里面生效
app.get('/', nw,(requset,response) => {
    response.send('hello world /');
})
app.get('/user',(requset,response) =>{
    response.send('hello world user');
})
app.listen(3000,function (){
    console.log('服务器启动成功')
})

在这里插入图片描述

6.7.6多个局部中间件

在这里插入图片描述

const express = require('express');
const app = express();
const nw1 = (request,response,next) => {
    console.log('这是第一个局部中间件函数');
    next();
}
const nw2 = (request,response,next) => {
    console.log('这是第二个局部中间件函数');
    next();
}
//nw只在这个路由里面生效
app.get('/', [nw1,nw2],(requset,response) => {
    response.send('hello world /');
})
app.get('/user',(requset,response) =>{
    response.send('hello world user');
})
app.listen(3000,function (){
    console.log('服务器启动成功')
})

在这里插入图片描述

6.7.7中间件的五个注意事项

在这里插入图片描述

6.7.8中间件的分类

1.应用级别的中间件
在这里插入图片描述

2.路由级别的中间件
在这里插入图片描述
3.错误级别的中间件
在这里插入图片描述
4.express的内置中间件
使用request.body来接受客户端发送的请求数据
在这里插入图片描述

5.第三方中间件
在这里插入图片描述

6.8自定义中间件

在这里插入图片描述

6.8.1request监听data和end事件

在这里插入图片描述
在这里插入图片描述

const express = require('express');
const app = express();
app.use((request,response,next) => {
    //定义字符串用来存储
    let str = '';
    //使用.on绑定data事件   使用chunk来接受请求端的数据
    request.on('data',chunk => {
        str+=chunk;
    });
    //接受完客户端发送过来的数据触发
    request.on('end',() => {
        console.log(str);
    })
})
app.post('/',(requset,response) =>{
    //设置响应头   设置允许跨域
    response.setHeader('Access-Control-Allow-Origin','*');
    response.send('hello world /')
})
app.listen(3000,function (){
    console.log('服务器启动成功')
})

在这里插入图片描述

6.8.2使用querystring模块解析请求体数据

在这里插入图片描述

const qs =require('querystring');
const body = qs.parse(str);

在这里插入图片描述

6.8.3将解析出来的数据对象挂载到路由中

在这里插入图片描述

const express = require('express');
const qs =require('querystring');
const app = express();
app.use((request,response,next) => {
    //定义字符串用来存储
    let str = '';
    //使用.on绑定data事件   使用chunk来接受请求端的数据
    request.on('data',chunk => {
        str+=chunk;
    });
    //接受完客户端发送过来的数据触发
    request.on('end',() => {
        //完整的请求体数据
       // console.log(str);
        //使用querystring把字符串格式数据转化成对象形式
        const body = qs.parse(str);
        request.body=body;
       // 不调用这个next下面接受不到值
        next();
    })
})
app.post('/',(requset,response) =>{
    //设置响应头   设置允许跨域
    response.setHeader('Access-Control-Allow-Origin','*');
    response.send(requset.body);
})
app.listen(3000,function (){
    console.log('服务器启动成功')
})

在这里插入图片描述

6.8.4封装自定义中间件

在这里插入图片描述

6.9使用express写接口

6.9.0POST请求头的常见数据格式

1、application/json(JSON数据格式)

xhr.setRequestHeader("Content-type","application/json; charset=utf-8");

这种类型是我们现在最常用的,越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。
2、application/x-www-form-urlencoded

xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");

这应该是最常见的 POST 提交数据的方式了。浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据
3、multipart/form-data

xhr.setRequestHeader("Content-type", "multipart/form-data; charset=utf-8");

这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 form 的 enctyped 等于这个值
4、text/xml

xhr.setRequestHeader("Content-type", "text/xml; charset=utf-8");

它是一种使用 HTTP 作为传输协议,XML 作为编码方式的远程调用规范,这种方式现在不常用

6.9.1GET接口

注意请求的url地址
在这里插入图片描述
添加查询字符串
在这里插入图片描述

6.9.2POST请求

在这里插入图片描述
发送携带urlencoded的请求 服务端不配置这个POST请求获取不到request.body的数据

app.use(express.urlencoded({extended:false}));

在这里插入图片描述
前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button>点击发送请求</button>
</body>
</html>
<script>
    var btn = document.getElementsByTagName('button');
    btn[0].addEventListener('click',function (){
        var data = "name=houwang&age=18"
        const xhr = new XMLHttpRequest();
        xhr.open('POST','http://127.0.0.1:3000/api/post');
        //发送urlencoded数据带的请求头
        xhr.setRequestHeader("content-Type","application/x-www-form-urlencoded");
        xhr.send(`${data}`);
        xhr.onreadystatechange = function (){
            //判断服务器响应了所有的结果
            if(xhr.readyState===4){
                if (xhr.status>=200&&xhr.status<300){
                    document.write(xhr.response);
                }
            }
        }
    })
</script>

router代码:

const express = require('express');
const router = express.Router();
router.post('/post',(request,response) => {
    response.setHeader('Access-Control-Allow-Origin','*');
    //通过request获取请求体中包含url-encoded格式的数据
    const body = request.body;
    response.send({
        status:0,  //状态码0成功,1失败
        msg:'GET请求成功',   // 提示信息
        data:body      //需要响应给客户端的数据
    })
})
module.exports=router;

server代码:

const express = require('express');
const router =require('./06POST接口router');
const app = express();
//配置中间件来解析url-encoded格式的数据
app.use(express.urlencoded({extended:false}));
//app.use就是注册全局中间件   这里也可以把router认为是一个中间件
app.use('/api',router);
app.listen(3000,function (){
    console.log('服务器启动成功')
})

在这里插入图片描述

6.9.3跨域问题

之前我们解决跨域的问题是用这个

response.setHeader('Access-Control-Allow-Origin','*');

在这里插入图片描述
在这里插入图片描述
下载cors

npm i cors

导入后添加进去

app.use(cors());

前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<button id="GET">GET</button>
<button id="POST">POST</button>
</body>
</html>
<script>
    $(function (){
        $('#GET').on('click',function (){
            $.ajax({
                type:'GET',
                url:'http://127.0.0.1:3000/api/get',
                data:{name:'houwang',age:18},
                success:function (response){
                    console.log(response);
                }
            })
        })
        $('#POST').on('click',function (){
            $.ajax({
                type:'POST',
                url:'http://127.0.0.1:3000/api/post',
                data:{name:'houwang',age:18},
                success:function (response){
                    console.log(response);
                }
            })
        })
    })
</script>

router代码:

const express = require('express');
const router = express.Router();
router.post('/post',(request,response) => {
    /** response.setHeader('Access-Control-Allow-Origin','*');**/
    //通过request获取请求体中包含url-encoded格式的数据
    const body = request.body;
    response.send({
        status:0,  //状态码0成功,1失败
        msg:'POST请求成功',   // 提示信息
        data:body      //需要响应给客户端的数据
    })
})
router.get('/get',(request,response) => {
   /** response.setHeader('Access-Control-Allow-Origin','*');**/
    //通过request获取请求体中包含url-encoded格式的数据
    const body = request.query;
    response.send({
        status:0,  //状态码0成功,1失败
        msg:'GET请求成功',   // 提示信息
        data:body      //需要响应给客户端的数据
    })
})
module.exports=router;

server代码:

const express = require('express');
const cors =require('cors');
const router =require('./01Jquery跨域问题router');
const app = express();
//配置中间件来解析url-encoded格式的数据
app.use(express.urlencoded({extended:false}));
//app.use就是注册全局中间件   这里也可以把router认为是一个中间件
app.use(cors());
app.use('/api',router);
app.listen(3000,function (){
    console.log('服务器启动成功')
})

在这里插入图片描述

6.9.4CORS的介绍

在这里插入图片描述
在这里插入图片描述

6.9.5CORS的三个响应头

response.setHeader('Access-Control-Allow-Origin','*');

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.9.6简单请求和预检请求

在这里插入图片描述
在这里插入图片描述
基于6.9.3 前端添加代码:

  $('#DELETE').on('click',function (){
            $.ajax({
                type:'DELETE',
                url:'http://127.0.0.1:3000/api/delete',
                data:{name:'houwang',age:18},
                success:function (response){
                    console.log(response);
                }
            })
        })

router添加如下代码

router.delete('/DELETE',(request,response) => {
    // response.setHeader('Access-Control-Allow-Origin','*');
    //通过request获取请求体中包含url-encoded格式的数据
    const body = request.body;
    response.send({
        status:0,  //状态码0成功,1失败
        msg:'DELETE请求成功',   // 提示信息
        data:body      //需要响应给客户端的数据
    })
})

选中的这个就是预检请求
在这里插入图片描述

6.9.7JSONP接口

注:这个JSONP只支持GET请求
在这里插入图片描述
在这里插入图片描述
前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<button>jsonp</button>
<div></div>
</body>
</html>
<script>
    $(function (){
        $('button').on('click',function (){
            $.ajax({
                method:"GET",   //请求方式必须为GET
                url:'http://127.0.0.1:3000/jsonp',
                dataType:'jsonp',  //表示发起JSONP请求
                success:function (response){
                    document.write(response.name)
                    document.write(response.age);
                }
            })
        })
    })
</script>

后端代码:

const express = require('express');
const app = express();
//为了防止冲突必须在cors中间件前面声明JSONP接口
app.get('/jsonp',(request,response) => {
  //获取请求头中函数名称callback
    const funcName = request.query.callback;
    //自定义一个返回的data数据
    const data = {
        name:'houwang',
        age:18
    }
    //JSON.stringify()将对象转化为JSON格式字符串
    response.send(`${funcName}(${JSON.stringify(data)})`)
})
app.listen(3000,function (){
    console.log('服务器启动成功')
})

在这里插入图片描述

七、MySQL

7.1MySQL基本介绍

在这里插入图片描述
在这里插入图片描述

7.2增删查改

7.2.1 查询数据

– *号是通配符 查询users表所有列的数据

SELECT * FROM users

– 指定查询某一列

SELECT name FROM users

在这里插入图片描述

7.2.2插入数据

– 向users表插入三个列对应值为***

INSERT INTO users (id,name,pass) VALUES (1, '张三', '123')
INSERT INTO users (id,name,pass) VALUES (2, '李四', '456')

status是创建表设置好的默认值
在这里插入图片描述

7.2.3更新数据

UPDATE users SET pass=123456 -- 不加条件限制则更新所有数据
UPDATE users SET pass='admin123' WHERE id=1

在这里插入图片描述

7.2.4删除数据

注:删除数据一定要加where条件 不然就是删库跑路了

DELETE FROM users WHERE id=5 -- 删除id为5那行数据

7.3SQL子句

7.3.1WHERE子句

在这里插入图片描述
在这里插入图片描述
– 查询表中status大于1的数据

SELECT * FROM users WHERE `status`>1  

在这里插入图片描述
– 查询表中status不等于1的数据

SELECT * FROM users WHERE `status`<>1  

7.3.2and和or语句(并且或者)

在这里插入图片描述
– 查询表中pass等于admin123并且id小于4的数据

SELECT * FROM users WHERE pass='admin123' AND id<4

– 查询表中pass等于admin123或者id小于4的数据

SELECT * FROM users WHERE pass='admin123' or id<4

在这里插入图片描述

7.3.3ORDER BY子句(排序)

-- ASC升序(可不加)   --DESC降序
SELECT * FROM houwang ORDER BY 分数 ASC
SELECT * FROM houwang ORDER BY 分数 DESC

在这里插入图片描述
先按照分数升序排序后再按学号降序排序

SELECT * FROM houwang ORDER BY 分数 ASC,学号 DESC

7.3.4COUNT函数(统计)

– 查询表中分数为65的总数据条数

select COUNT(*) FROM houwang WHERE 分数=65

在这里插入图片描述

7.3.5AS取别名

– 查询表中分数为65的总数据条数并且取别名

select COUNT(*) AS 分数和 FROM houwang WHERE 分数=65

在这里插入图片描述
– 查询表数据分数等于87,姓名取别名为name,分数取别名为num

SELECT 姓名 AS name,分数 AS num FROM houwang WHERE 分数=87

在这里插入图片描述

八、在项目中操作MySQL

8.1安装mysql

npm i mysql

8.2基本操作

8.3查询表

注:这里查询到的结果是一个数组

const mysql = require('mysql');
//建立与本地数据库的连接
const db = mysql.createPool({
    host:'127.0.0.1',  //数据库的ip地址
    user:'root',    //mysql登录用户名
    password:'123456',  //登录密码
    database:'猴王'  //你要操作的数据库
});
//整一条sql语句检测一下
db.query('select * from users',(err,data) => {
    if(err) return console.log(err.message);
    console.log(data)
})

在这里插入图片描述

8.4插入数据

const mysql = require('mysql');
//建立与本地数据库的连接
const db = mysql.createPool({
    host:'127.0.0.1',  //数据库的ip地址
    user:'root',    //mysql登录用户名
    password:'123456',  //登录密码
    database:'猴王'  //你要操作的数据库
});
//自定义一个我们想插入的数据
const data = {name:'王二麻子',pass:'123456'};
//自定义一个sql语句    ?表示占位符
const sqlstr = 'insert into users (name,pass) values (?,?)';
//通过数组的形式依次指定我们要插入的数据
db.query(sqlstr,[data.name,data.pass],(err,result) => {
    if(err) return console.log(err.message);
    //检测插入成功的一种方式    affectedRows:受影响
    if(affectedRows=1) console.log('插入成功')
})
db.query('select * from users',(err,result) => {
    if(err) return console.log(err.message);
    console.log(result)
})

在这里插入图片描述
插入的快捷方式
在这里插入图片描述

const mysql = require('mysql');
//建立与本地数据库的连接
const db = mysql.createPool({
    host:'127.0.0.1',  //数据库的ip地址
    user:'root',    //mysql登录用户名
    password:'123456',  //登录密码
    database:'猴王'  //你要操作的数据库
});

/**快捷插入**/

//自定义一个我们想插入的数据
const data = {name:'王二麻子',pass:'123456'};
//?表示占位符   set ?就是一种简化的写法
const sqlstr = 'insert into users set ?';
//快捷插入不需要使用数组的形式
db.query(sqlstr,data,(err,result) => {
    if(err) return console.log(err.message);
    //检测插入成功的一种方式    affectedRows:受影响
    if(result.affectedRows=1) console.log('插入成功')
})
db.query('select * from users',(err,result) => {
    if(err) return console.log(err.message);
    console.log(result)
})

在这里插入图片描述

8.5更新数据

核心代码:

const data = {id:5};
//?表示占位符   set ?就是一种简化的写法
const sqlstr = 'update users set id = ? where name="王二麻子"';
db.query(sqlstr,[data.id],(err,result) => {
    if(err) return console.log(err.message);
    if(result.affectedRows=1) console.log('更新成功')
})

在这里插入图片描述
快捷操作
在这里插入图片描述
核心代码:

/**更新快捷操作**/
const data = {id:6,name:'王二麻子'};
const sqlstr = 'update users set ? where name= ? ';
//与插入不同的是这里写的是一个数组
db.query(sqlstr,[data,data.name],(err,result) => {
    if(err) return console.log(err.message);
    if(result.affectedRows=1) console.log('更新成功')
})

在这里插入图片描述

8.6删除数据

实际中推荐使用id来进行删除

const sqlstr = "delete from users where id = ? "
//当sql语句只有一个占位符的时候数组可以不写
db.query(sqlstr,6,(err,result) => {
    if(err) return console.log(err.message);
    if(result.affectedRows=1) console.log('删除成功')
})

在这里插入图片描述
标记删除,你写不好sql你删错了你就知道rm -rf /*有什么作用了
在这里插入图片描述

 // 标记删除
const sqlstr = "update users set status = ? where id =? "
//我们把status=2默认为删除了的数据
db.query(sqlstr,[2,4],(err,result) => {
    if(err) return console.log(err.message);
    if(result.affectedRows=1) console.log('标记删除成功')
})

在这里插入图片描述

九、web开发模式

9.1服务器端渲染和前后端分离渲染介绍

9.1.1服务器端渲染介绍

在这里插入图片描述
优缺点
在这里插入图片描述

9.1.2前后端分离渲染介绍

在这里插入图片描述
优缺点
在这里插入图片描述

9.1.3实际开发中如何选择

在这里插入图片描述

9.2身份认证

9.2.1session认证机制

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
network里请求头和Application里面都有cookies
在这里插入图片描述

9.2.2cookies的不安全性

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.3在express中使用session认证

9.3.1安装配置

安装

npm install express-session在这里插入图片描述


//导入express-session
const session = require('express-session');
//配置  使用app.use中间件来进行挂载
app.use(session({
    secret:'houwang',   //任意字符串
    resave:false,   //固定写法
    saveUninitialized:true    //固定写法
}))

9.4登录小案例

9.4.1咱们前端发送数据过去,后端接受并返回回来

我们是POST请求必须带如下两个参数,request.body里面才有值
前端:

        //发送urlencoded数据带的请求头   用来把字符串类型的参数序列化成Form Data
        xhr.setRequestHeader("content-Type","application/x-www-form-urlencoded");

后端:

//配置中间件来解析url-encoded格式的数据
 app.use(express.urlencoded({extended:false}));

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
账号:<input type="text" class="name"><br>
密码:<input type="text" class="password"><br>
<button>登录</button>
</body>
</html>
<script>
    var btn = document.getElementsByTagName('button')[0];
    btn.addEventListener('click',function (){
        main();
    })
    function main(){
        var name = document.getElementsByClassName('name')[0].value;
        var password = document.getElementsByClassName('password')[0].value;
        const data = `name=${name}&password=${password}`
        const xhr = new XMLHttpRequest();
        xhr.open('POST','http://127.0.0.1:3000/api/login');
        //发送urlencoded数据带的请求头   用来把字符串类型的参数序列化成Form Data
        xhr.setRequestHeader("content-Type","application/x-www-form-urlencoded");
        xhr.send(data);
        //设置响应体数据为JSON
        xhr.responseType='json';
        xhr.onreadystatechange = function (){
            if(xhr.readyState===4){
                if (xhr.status>=200&&xhr.status<300){
                    console.log(xhr.response.name);
                    console.log(xhr.response.password);
                }
            }
        }
    }

</script>

后端代码

const express =require('express');
const cors = require('cors');
const app = express();
//配置中间件来解析url-encoded格式的数据
 app.use(express.urlencoded({extended:false}));
//解决跨域
app.use(cors());
//登录接口"
app.post('/api/login',(request,response) => {
    const name = request.body.name;
    const password = request.body.password;
    const data = {
        'name':name,
        'password':password,
    }
    response.send(JSON.stringify(data));
})
app.listen(3000,() => {
    console.log('服务器启动成功');
})

在这里插入图片描述

9.4.2后端设置固定的账号密码,前端并提示用户登录成功与失败

失败跳转注册页面,成功跳转百度
登录前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
账号:<input type="text" class="name"><br>
密码:<input type="text" class="password"><br>
<button>登录</button>
</body>
</html>
<script>
    var btn = document.getElementsByTagName('button')[0];
    btn.addEventListener('click',function (){
        main();
    })
    function main(){
        var name = document.getElementsByClassName('name')[0].value;
        var password = document.getElementsByClassName('password')[0].value;
        const data = `name=${name}&password=${password}`
        const xhr = new XMLHttpRequest();
        xhr.open('POST','http://127.0.0.1:3000/api/login');
        //发送urlencoded数据带的请求头   用来把字符串类型的参数序列化成Form Data
        xhr.setRequestHeader("content-Type","application/x-www-form-urlencoded");
        xhr.send(data);
        //设置响应体数据为JSON
        xhr.responseType='json';
        xhr.onreadystatechange = function (){
            if(xhr.readyState===4){
                if (xhr.status>=200&&xhr.status<300){
                    const status = xhr.response;
                    console.log(status);
                    if(status.LoginStatus==1){
                        alert(status.msg+'去注册');
                        window.location.href='http://www.baidu.com';
                    }else if(status.LoginStatus==0){
                        const trueorfalse = confirm(status.msg + '回车确认跳转')
                        if (trueorfalse) window.location.href='01index.html';
                    }
                }
            }
        }
    }

</script>

后端

const express =require('express');
const cors = require('cors');
const app = express();
//配置中间件来解析url-encoded格式的数据
 app.use(express.urlencoded({extended:false}));
//解决跨域
app.use(cors());
//登录接口"
app.post('/api/login',(request,response) => {
    const name = request.body.name;
    const password = request.body.password;
    if(name!=='admin'&&password!=='123456'){
        return response.send({LoginStatus:1,msg:'登录失败'})
    }else{
        response.send({LoginStatus:0,msg:'登录成功'})
    }
})
app.listen(3000,() => {
    console.log('服务器启动成功');
})

在这里插入图片描述

9.4.3向seesion存入数据,并且首页检测是否登录

在这里插入图片描述
存储用户数据:

    //user和isLogin是我们自定义的属性
    request.session.user=request.body   //存储用户的账号和密码信息
    request.session.isLogin=true;       //用户的登录状态

登录页面代码不变,post请求里面request.session.isLogin值在get请求访问不到,(因为跨域问题)我这里借助that来访问
首页前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
</body>
</html>
<script>
    function main(){
        const xhr = new XMLHttpRequest();
        xhr.open('GET','http://127.0.0.1:3000/api');
        xhr.send();
        //设置响应体数据为JSON对象
        xhr.responseType='json';
        xhr.onreadystatechange = function (){
            if(xhr.readyState===4){
                if (xhr.status>=200&&xhr.status<300){
                    console.log(xhr.response)
                    document.write(xhr.response);
                    if(xhr.response.LoginStatus==1){
                        document.write('现在处于未登录状态'+xhr.response.msg)
                    }else{
                        document.write('你现在是登录成功状态'+xhr.response.msg)
                    }
                }
            }
        }
    }
main();
</script>

后端

const express =require('express');
const cors = require('cors');
//导入express-session
const session = require('express-session');
const app = express();
 app.use(express.urlencoded({extended:false}));
app.use(cors());
//配置  使用app.use中间件来进行挂载
app.use(session({
    secret:'houwang',   //任意字符串
    resave:false,   //固定写法
    saveUninitialized:true    //固定写法
}))
var that = false;
app.post('/api/login',(request,response) => {
    const name = request.body.name;
    const password = request.body.password;
    if(name!=='admin'&&password!=='123456'){
        return response.send({LoginStatus:1,msg:'登录失败'})
    }
    //user和isLogin是我们自定义的属性
    request.session.user=request.body   //存储用户的账号和密码信息
    request.session.isLogin=true;       //用户的登录状态
    that=request.session.isLogin;
    console.log(request.session.user);
    response.send({LoginStatus:0,msg:'登录成功'})
})
app.get('/api',(request,response) => {
    if(that){
        response.send({LoginStatus:0,msg:'success'})
    }else{
        return response.send({LoginStatus:1,msg:'fail'})
    }
})
app.listen(3000,() => {
    console.log('服务器启动成功');
})

在这里插入图片描述

9.4.4登出清除数据

在这里插入图片描述
上一个存入数据的逻辑,post请求里面request.session.isLogin值依旧访问不到,所以这个访问依旧没得用,这里我们借助info来实现,登录代码依旧不变
前端首页

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
账号:<input type="text" class="name"><br>
密码:<input type="text" class="password"><br>
<button>登录</button>
</body>
</html>
<script>
    var btn = document.getElementsByTagName('button')[0];
    btn.addEventListener('click',function (){
        main();
    })
    function main(){
        var name = document.getElementsByClassName('name')[0].value;
        var password = document.getElementsByClassName('password')[0].value;
        const data = `name=${name}&password=${password}`
        const xhr = new XMLHttpRequest();
        xhr.open('POST','http://127.0.0.1:3000/api/login');
        //发送urlencoded数据带的请求头   用来把字符串类型的参数序列化成Form Data
        xhr.setRequestHeader("content-Type","application/x-www-form-urlencoded");
        xhr.send(data);
        //设置响应体数据为JSON
        xhr.responseType='json';
        xhr.onreadystatechange = function (){
            if(xhr.readyState===4){
                if (xhr.status>=200&&xhr.status<300){
                    const status = xhr.response;
                    console.log(status);
                    if(status.LoginStatus==1){
                        alert(status.msg+'去注册');
                        window.location.href='http://www.baidu.com';
                    }else{
                        const trueorfalse = confirm(status.msg + '回车确认跳转')
                        if (trueorfalse) window.location.href='01index.html';
                    }
                }
            }
        }
    }

</script>

后端

const express =require('express');
const cors = require('cors');
//导入express-session
const session = require('express-session');
const app = express();
 app.use(express.urlencoded({extended:false}));
app.use(cors());
//配置  使用app.use中间件来进行挂载
app.use(session({
    secret:'houwang',   //任意字符串
    resave:false,   //固定写法
    saveUninitialized:true    //固定写法
}))
var that = false;  //判断是否处在登录成功失败的状态
var info = true;   //清空数据用的,清空了就是false
//登录接口记录值
app.post('/api/login',(request,response) => {
    const name = request.body.name;
    const password = request.body.password;
    if(name!=='admin'&&password!=='123456'){
        return response.send({LoginStatus:1,msg:'登录失败'})
    }
    //user和isLogin是我们自定义的属性
    request.session.user=request.body   //存储用户的账号和密码信息
    request.session.isLogin=true;       //用户的登录状态
    that=request.session.isLogin;
    console.log(request.session.user);
    response.send({LoginStatus:0,msg:'登录成功'})
    info=true;
})
//读取判断是否在登录状态
app.get('/api',(request,response) => {
    if(info==false) that=false;  //检测到数据被清空直接返回未登录状态
    if(that){
        response.send({LoginStatus:0,msg:'success'})
    }else{
        return response.send({LoginStatus:1,msg:'fail'})
    }
})
//清空登录状态
app.post('/api/logout',(request,response) =>{
//清空session的方法   摆设而已压根访问不到request.session的值
    request.session.destroy();
    response.send({LoginStatus:1,msg:'out'})
    info=false;
})
app.listen(3000,() => {
    console.log('服务器启动成功');
})

在这里插入图片描述

9.5在express中使用jwt认证机制

9.5.1什么jwt机制

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.5.2安装配置

在这里插入图片描述
定义密钥

const secretKey = 'houwang' //用于JWT字符串的加密和解密

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.5.3jwt基操

后端代码

const express =require('express');
const cors = require('cors');
const jwt = require('jsonwebtoken')              //生成jwt字符串
const expressJwt = require('express-jwt')       //把JWT字符串还原成JSON格式对象
const app = express();
app.use(express.urlencoded({extended:false}));
app.use(cors());
const secretKey = 'houwang' //用于JWT字符串的加密和解密
//expressJwt({secret:secretKey})  解析token的中间件  解析成JSON对象的中间件
//.unless({path:[/^\/api\//]})  正则匹配的那些接口访问不需要权限
//注意,配置成功这个express-jwt这个中间件,就可以把解析出来的用户信息,挂载到request.user属性上
app.use(expressJwt({secret:secretKey}).unless({path:[/^\/api\//]}));
//登录接口记录值
app.post('/api/login',(request,response) => {
    const name = request.body.name;
    const password = request.body.password;
    if(name!=='admin'||password!=='123456') {
        return response.send({LoginStatus: 1, msg: '登录失败'})
    }
        //参数一:用户信息对象,参数二:加密的密钥,参数三:配置对象配置当前token的有效期
        const tokenStr = jwt.sign({username: name}, secretKey, {expiresIn: '3h'});
         response.send({LoginStatus:0,msg:'登录成功',token:tokenStr});
})
//正则表达式未包含这个域名   所以这是一个需要权限的接口
app.get('/admin',(request,response) => {
    response.send({Status:200,data:request.user});
})
app.listen(3000,() => {
    console.log('服务器启动成功');
})

下载安装外部软件postman
请求第一个登录接口
在这里插入图片描述
拿到第一次请求获得的token进行请求第二个需要权限的接口
请求方式两者不一,注意请求的值前面要加Bearer和一个空格
在这里插入图片描述
日常作怪模拟一下token出错,报一堆错
在这里插入图片描述

核心代码注:这个中间件放在最后面

//jwt捕获错误
app.use((err,request,response,next) => {
if(err.name==='UnauthorizedError') return response.send({Status:401,msg:'无效的token'})
    response.send({Status:500,msg:'未知的错误'})
})

这不完美?
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值