web前端笔记4后端相关部分

十三.Ajax

1.Ajax概述

1.1Ajax初识

1.作用
获取服务器数据
2.效果
在不刷新整个页面的情况下,通过一个url地址获取服务器数据,然后进行页面局部刷新
3.应用场景
①评论刷新
②用户名验证
4.总结
局部,异步刷新

1.2XML

是一种可扩张标记语言
被设计用来传输和存储数据
与html不同的是,html都是预定义标签,xml中没有预定义标签,全部都是自定义标签
用来存储一些数据,不过现在已经被JSON取代,此处仅了解

1.3ajax优缺点

1.优点
①可以无需刷新页面就可以与服务端进行通信
②允许根据事件来更新部分页面内容
2.缺点
①没有浏览历史,不可回退
②存在跨域问题(同源)
③对SEO优化不友好

2.基础知识铺垫

2.1服务器与客户端

1.区别
服务器时提供某种服务的的电脑,客户端是使用服务器所提供服务的电脑

2.服务器能提供的服务
网页服务,邮箱服务,文件上传下载服务,聊天服务等

3.服务器软件
http网页服务:apache,tomcat,iis等
文件上传下载服务:vsftp等
邮箱服务:sendmail等
数据存储服务:mysql,oracle等

2.2网络相关概念

1.IP地址
通过IP地址可以快速找到特定的服务器

2.域名
IP地址是一串数字,很难记忆,因而诞生了域名,方便记忆
查看本机ip:ipconfig
查看域名ip:ping

3.dns域名解析服务器
dns叫做域名解析服务器,提供域名与ip地址的映射关系
访问服务器的流程:本机hosts文件→dns服务器→服务器

4.端口
当通过域名找到一台服务器,但是一台服务器可以提供多种服务,这时我们通过端口号进行区分
即端口是用来区分一台服务器上提供的不同服务的

2.3通信协议

通信协议就是事先规定好的规则
常见协议
超文本传输协议:http,https
文件传输协议:ftp
简单邮件传输协议:smtp

1.http协议
超文本传输协议,详细规定了浏览器和万维网服务器之间相互通信的规则
在f12network处可以查看报文
请求报文(在headers下的后两个就是请求行头·和请求体)
在这里插入图片描述
响应报文(headers下的response和response分别为请求行头和请求体)
在这里插入图片描述

3.数据收发

3.1插件nodemon

1.作用
无需重复启动服务,刷新即可更改
2.安装
只需要在vscode的集成终端运行npm install -g nodemon
安装中如果遇到系统禁止运行脚本
则管理员权限打开vscode,然后集成终端运行、、、打开权限
在这里插入图片描述

3.2数据收发

1.问题

IE浏览器会有缓存问题,即server更改后不随之改变,
应对方法
在这里插入图片描述
在目标url后加?t=
在引号外加Date.now();

3.3实操

1.server.js

//引入express
const express = require('express');
//创建应用对象
const app = express();
//创建路由规则
app.get('/server', (request, response) => {
    //设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    //设置响应体
    response.send('hello world');
});

app.all('/server', (request, response) => {
   
    //设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
     //设置允许接受所有类别的请求头
    response.setHeader('Access-Control-Allow-Headers', '*')
    //设置响应体
    response.send('hello ajax post');
});

app.all('/json-server', (request, response) => {
   
    //设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
     //设置允许接受所有类别的请求头
    response.setHeader('Access-Control-Allow-Headers', '*')
    //设置响应体
    const data = {
        name: 'ajax'
    }
    let str = JSON.stringify(data);
    response.send(str);
});
app.get('/delay', (request, response) => {
    //设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    //设置响应体
    setTimeout(() => {
        response.send('延时响应');
    },3000)
   
});

//监听端口启动服务
app.listen(8000, () => {
    console.log("服务已启动,8000端口监听中");
})

2.get

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #result {
            width: 200px;
            height: 200px;
            border: 1px solid #90b;
        }
    </style>
</head>

<body>
    <button>点击发送请求</button>
    <div id="result"> </div>
    <script>
        //获取元素
        const btn = document.getElementsByTagName('button')[0];
        const result = document.getElementById("result");
        //绑定事件
        btn.onclick = function () {
            //创建对象
            const xhr = new XMLHttpRequest();
            //初始化,设置请求方法和url
            xhr.open('GET', 'http://127.0.0.1:8000/server');
            //发送
            xhr.send();
            //事件绑定 处理服务端返回的结果
            //on when 当...时候
            //readystate 是xhr对象中的属性,表示状态0 1 2 3 4
            //change 改变
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    //判断响应码200 404 403 401 500
                    if (xhr.status >= 200 && xhr.status < 300) {
                        console.log(xhr.status); //状态码
                        console.log(xhr.statusText); //状态字符串
                        console.log(xhr.getAllResponseHeaders()); //所有响应头
                        console.log(xhr.response); //响应体

                        result.innerHTML = xhr.response;

                    }
                }

            }

        }
    </script>
</body>

</html>

3.post

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #result {
            width: 200px;
            height: 200px;
            border: 1px solid #90b;
        }
    </style>
</head>

<body>
    <div id="result"> </div>
    <script>
        //获取元素
        const result = document.getElementById("result");
        //绑定事件
        result.addEventListener("mouseover", function () {
            //创建对象
            const xhr = new XMLHttpRequest();
            //初始化,设置请求方法和url
            xhr.open('POST', 'http://127.0.0.1:8000/server');
            //设置请求头
            //有预定义请求头和自定义,默认无法接受自定义的,可以在server里设置接受所有
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            //发送 括号内为请求体
            xhr.send('a=100');
            //事件绑定 处理服务端返回的结果
            //on when 当...时候
            //readystate 是xhr对象中的属性,表示状态0 1 2 3 4
            //change 改变
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    //判断响应码200 404 403 401 500
                    if (xhr.status >= 200 && xhr.status < 300) {
                        console.log(xhr.status); //状态码
                        console.log(xhr.statusText); //状态字符串
                        console.log(xhr.getAllResponseHeaders()); //所有响应头
                        console.log(xhr.response); //响应体

                        result.innerHTML = xhr.response;

                    }
                }

            }
        })
    </script>
</body>

</html>

4.超时与网络异常

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #result {
            width: 200px;
            height: 200px;
            border: 1px solid #90b;
        }
    </style>
</head>

<body>
    <button>点击发送请求</button>
    <div id="result"> </div>
    <script>
        //获取元素
        const btn = document.getElementsByTagName('button')[0];
        const result = document.getElementById("result");
        //绑定事件
        btn.onclick = function () {
            //创建对象
            const xhr = new XMLHttpRequest();
            //超时应对
            xhr.timeout = 2000;
            xhr.ontimeout = function () {
                alert("网络异常"); //超时会弹出
            }
            xhr.onerror = function () {
                alert("你的网络似乎出现了一些问题")
            }
            //初始化,设置请求方法和url
            xhr.open('GET', 'http://127.0.0.1:8000/delay');
            //发送
            xhr.send();
            //事件绑定 处理服务端返回的结果
            //on when 当...时候
            //readystate 是xhr对象中的属性,表示状态0 1 2 3 4
            //change 改变
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    //判断响应码200 404 403 401 500
                    if (xhr.status >= 200 && xhr.status < 300) {
                        console.log(xhr.status); //状态码
                        console.log(xhr.statusText); //状态字符串
                        console.log(xhr.getAllResponseHeaders()); //所有响应头
                        console.log(xhr.response); //响应体

                        result.innerHTML = xhr.response;

                    }
                }

            }

        }
    </script>
</body>

</html>

5.取消请求

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button>点击发送</button>
    <button>点击取消</button>
    <script>
        const btns = document.querySelectorAll('button');
        let x = null;

        btns[0].onclick = function () {
            x = new XMLHttpRequest();
            x.open("GET", 'http://127.0.0.1:8000/delay');
            x.send();

        }
        btns[1].onclick = function () {
            x.abort(); //手动取消,在发送还在“路上”的时候
        }
    </script>
</body>

</html>

6.重复请求问题

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button>点击发送</button>
    <button>点击取消</button>
    <script>
        const btns = document.querySelectorAll('button');
        let x = null;
        let isSending = false;

        btns[0].onclick = function () {
            if (isSending) x.abort();
            x = new XMLHttpRequest();
            isSending = true
            x.open("GET", 'http://127.0.0.1:8000/delay');
            x.send();
            x.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    isSending = false;
                }

            }
        }
        btns[1].onclick = function () {
            x.abort(); //手动取消,在发送还在“路上”的时候
        }
    </script>
</body>

</html>

4.jQuery中的ajax

ajax方法功能更丰富
get,post更简洁简便
①server.js

//引入express
const express = require('express');
//创建应用对象
const app = express();
//创建路由规则
app.get('/server', (request, response) => {
    //设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    //设置响应体
    response.send('hello world');
});

app.all('/server', (request, response) => {
   
    //设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
     //设置允许接受所有类别的请求头
    response.setHeader('Access-Control-Allow-Headers', '*')
    //设置响应体
    response.send('hello ajax post');
});

app.all('/json-server', (request, response) => {
   
    //设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
     //设置允许接受所有类别的请求头
    response.setHeader('Access-Control-Allow-Headers', '*')
    //设置响应体
    const data = {
        name: 'ajax'
    }
    let str = JSON.stringify(data);
    response.send(str);
});
app.get('/delay', (request, response) => {
    //设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    //设置响应体
    setTimeout(() => {
        response.send('延时响应');
    },3000)
   
});
app.all('/jquery-server', (request, response) => {
    //设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
   //设置允许接受所有类别的请求头
   response.setHeader('Access-Control-Allow-Headers', '*')
    //设置响应体
    const data = {
        name: 'jquery-ajax'
    }
    let str = JSON.stringify(data);
    response.send(str);

   
});


//监听端口启动服务
app.listen(8000, () => {
    console.log("服务已启动,8000端口监听中");

②html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
        integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>

<body>

    <h2>jquery发送ajax请求</h2>
    <button type="button" class="btn btn-primary">GET</button>
    <button type="button" class="btn btn-success">POST</button>
    <button type="button" class="btn btn-info">通用型方法ajax</button>
    <script>
        $('button').eq(0).click(function () {
            $.get('http://127.0.0.1:8000/jquery-server', {
                a: 100
            }, function (data) {
                console.log(data);
            });
        })
        $('button').eq(1).click(function () {
            $.post('http://127.0.0.1:8000/jquery-server', {
                a: 100
            }, function (data) {
                console.log(data.name);
            }, 'json'); //json作用是转化类型为对象格式,
        })
        $('button').eq(2).click(function () {
            $.ajax({
                url: 'http://127.0.0.1:8000/jquery-server',
                data: {
                    a: 100,
                    b: 200
                },
                type: 'GET',
                dataType: 'json',
                success: function (data) {
                    console.log(data);
                },
                timeout: 2000,
                error: function () {
                    console.log('出错了');

                },
                Headers: {
                    c: 300,
                    d: 400
                }
            });
        })
    </script>
</body>

</html>

还可以发送ajax请求的有axios和fetch

5.同源策略

是一种安全策略,
同源:协议,域名,端口号要完全相同
ajax默认同源
跨域:违背同源策略

解决跨域的方法:
1.JSONP
2.CORS官方方法,即access-control方法

十四.git

1.git概述

1.1git应用场景

1.文件备份
2.代码还原
3.协同开发
4.追溯问题代码编写人员和编写时间

1.2版本控制器的方式

1.集中式版本控制工具
版本库是集中存放在中央服务器的,team里每个人work时,从中央服务器下载代码,是必须联网才能工作,局域网或者互联网,个人修改后提交到中央版本库。
例如:SVN和CVS

2.分布式版本控制工具
没有中央服务器,每个人的电脑上都是一个完整的版本库,这样工作的时候,就无需联网了,因为版本库就在自己电脑上。
例如:Git

3.SVN(已经不用了)
在这里插入图片描述
4.git
在这里插入图片描述
5.git工作流程
在这里插入图片描述

2.git安装与常用命令

2.1git环境配置

在这里插入图片描述
1.下载
2.配置用户信息
在这里插入图片描述
3.在用户目录创建.bashrc文件
如果不行就touch命令创建
在这里插入图片描述
4.在bashrc中输入
在这里插入图片描述
5.解决乱码问题在这里插入图片描述

2.2获取本地仓库

1.创建目录
在这里插入图片描述
2.基本操作指令
在这里插入图片描述
①查看修改的状态
git status
②添加到暂存区
git add
git add .全部添加
③提交暂存区到本地仓库
git commit -m ‘注释内容’
④查看提交日志
git log [option]
在这里插入图片描述
git-log就可以包含所有options(前面设置的别名)
⑤版本回退
git reset --hard commitID
(comminID可以git-log或者git log查看)
查看删除记录
git reflog

⑥添加到忽略文件夹

练习案例

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ touch file01.txt

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ git add .

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ git commit -m 'commit 001'
[master (root-commit) 26ba2cd] commit 001
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 file01.txt

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ git log
commit 26ba2cd6480ce786390f580cc0d24c95b46f97df (HEAD -> master)
Author: guixiaoliuqi <guixiaoliuqi@163.com>
Date:   Thu Oct 21 19:39:51 2021 +0800

    commit 001

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ git-log
* 26ba2cd (HEAD -> master) commit 001

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ git add .

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ git commit -m 'update file01'
[master 4286969] update file01
 1 file changed, 1 insertion(+)

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ git log
commit 4286969beafeecf37f2fe29cb5938d931d3c00a6 (HEAD -> master)
Author: guixiaoliuqi <guixiaoliuqi@163.com>
Date:   Thu Oct 21 19:44:21 2021 +0800

    update file01

commit 26ba2cd6480ce786390f580cc0d24c95b46f97df
Author: guixiaoliuqi <guixiaoliuqi@163.com>
Date:   Thu Oct 21 19:39:51 2021 +0800

    commit 001

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ git-log
* 4286969 (HEAD -> master) update file01
* 26ba2cd commit 001

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ it reset --hard 26ba2cd
bash: it: command not found

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ git-log
* 4286969 (HEAD -> master) update file01
* 26ba2cd commit 001

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ git reset --hard 26ba2cd
HEAD is now at 26ba2cd commit 001

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ got-log
bash: got-log: command not found

guixiaoliuqi@DESKTOP-TGJVK6S MINGW64 /d/desk/git-test (master)
$ git-log
* 26ba2cd (HEAD -> master) commit 001

3.分支操作
git branch查看分支
git branch 分支名 创建分支
git checkout 分支名 切换分支(HEAD指向谁现在就是哪个分支)
git checkout -b 分支名 创建并切换
git merge 分支名 分支合并(important)把指定分支合并到当前分支
git branch -d b1 删除分支时,要做各种检查
git branch -D b1 不做检查,强制删除

解决冲突:如果两个人都改了同一部分内容,需要手动解决
在这里插入图片描述
开发中分支使用规则
在这里插入图片描述
在这里插入图片描述

3.git远程仓库

3.1常用托管服务(远程仓库)

在这里插入图片描述

3.2创建仓库

①创建仓库
②配置公钥
在这里插入图片描述

3.3操作远程仓库

在这里插入图片描述
-f表示强制覆盖
如果对接远程仓库错误,可以适应git remot rm 库名
第一次push记得加上–set-upstream用来绑定关系
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

十五node.js

1.概述

1.1为什么要学习node.js

企业要求服务端开发经验
只有了解服务端才能更好的配合服务端开发人员进行协同开发
可以学到
①B/S编程模型
②模块化编程
③node常用api
④异步编程
⑤express框架
⑥es6
⑦有助于学习框架

1.2node.js是什么

1.node.js不是一门语言,也不是库,不是框架,是js的运行环境,可以解析和执行js代码(浏览器也可以解析和执行js代码)

1.5.构建在Chromev8引擎之上,代码只是特定的字符串,引擎可以认识他并解析和执行,v8引擎是工人解析js最快的

2.node.js中没有dom和bom,在node中为js提供了一服务器级别的操作API
(和浏览器中的js不同,浏览器中js是es,dom,bom)
如:
①文件读写
②网络服务的构建
③网络通信
④http服务器

3.npm是世界上最大的开源生态系统,绝大所属js相关的包都是存放在npm上

1.3node.js能做什么

1.web服务器后台
2.开发命令行工具
npm(node),git(c),hexo(node)
3.用的最多的是node的命令行工具webpack,gulp,npm等

1.4一些资源

在这里插入图片描述
深入浅出:底层,纯理论,无实战
权威指南:api讲解,无实战

2.学习准备

2.1安装

判断是否安装成功:node -v
出现版本号表示成功

2.2js文件执行

1.创建js脚本文件,
2.打开终端(vs,cmd,git都行)定位到文件目录
3.输入node 文件名 执行文件
(文件名不可以叫node.js)

PS D:\desk\web学习\日常学习记录\10.22node1> node helloworld.js
hello world

3.node中的JavaScript

3.1读取文件

浏览器中的js是没有文件操作能力的,node中可以,
在node中想要操作文件,需要引入fs(file-system文件系统)模块
fs模块提供了所有文件操作相关的API,如fs.readFile就是用来读取文件的

//使用require方法加载fs核心模块
var fs = require('fs');
//读取文件
//第一个参数就是要读取的文件路径,第二个是回调函数
//回掉函数的参数中,如果读取成功,data获取到数据,error值为null
//读取失败data值为null,error为错误对象
fs.readFile('hello.txt', function (error, data) {
    //文件内存储的都是二进制数据,看到的结果是转化后的16进制,通过toString方法转化为字符形式
    console.log(data.toString());
    console.log(error);
})
PS D:\desk\web学习\日常学习记录\10.22node1> node helloworld.js
hello fs
null

3.2写文件

var fs = require('fs');
//第一个参数:文件路径
//第二个参数:文件内容
//第三个参数:回调函数,只有一个error参数
//写入成功,error为null,写入失败,error为错误对象
fs.writeFile('被写入.txt', '我是被写入的内容', function (error) {
    //错误处理
    if (error) {
        console.log('写入失败');
        console.log(error);
    } else {
        console.log('写入成功');
    }
})

注意:
①若没有对应的文件则会自动创建
②写入内容会覆盖原有内容

3.3搭建一个简单的http服务器

1.服务器的作用:提供服务
发请求,接收请求,处理请求,发送响应

2.http核心模块
引入http模块后可以简单的创建一个web服务器

3.http请求

var http = require('http');

//创建一个web服务器,返回一个server实例
var server = http.createServer();

//注册request请求事件,客户端发送请求就会触发该事件,然后执行回调函数
server.on('request', function () {
    console.log('收到客户端的请求了');
})

//绑定端口号,启动服务器
server.listen(3000, function () {
    console.log('服务器启动成功,可以访问http://127.0.0.1:3000/');
})
PS D:\desk\web学习\日常学习记录\10.22node1> node http.js
服务器启动成功,可以访问
收到客户端的请求了

注意:
①服务器启动后,就会占用控制台,控制台此时无法执行其他操作,如果关闭控制台,服务器就会关闭
②手动关闭控制台的方法:ctrl+c
③在浏览器访问端口时会触发请求事件,服务器返回响应,但没有处理请求,所以页面会一直加载
④如果端口号是80,访问时不需要输入端口号,是浏览器默认的端口号

4.http响应

var http = require('http');

var server = http.createServer();

//request请求事件处理函数需要接收两个参数
//1.request请求对象,可以获取来自客户端的一些信息,例如请求路径
//2.response响应对象,给客户端发送消息
server.on('request', function (request, response) {
    //request.url获取请求路径,就是端口号之后的部分
    //如http://127.0.0.1:3000/index,请求路径就是/index
    console.log('收到客户端的请求了,请求路径是'+request.url);
    
    //解决乱码
	response.setHeader("Content-type","text/html;charset='utf-8'");
    
    //response有一个方法:write,用来给用户发送相应数据
    var url = request.url;
    if (url==='/index') {
        response.write('首页');
    } else if(url==='/end'){
        response.write('末尾');
    } else {
        response.write('没找到')
    }
    
   
    response.end('<h2>后面什么都没了</h2>');


})

//绑定端口号,启动服务器
server.listen(3000, function () {
    console.log('服务器启动成功,可以访问http://127.0.0.1:3000/');
})

注意:
①write方法可以使用多次,但最后一定要有一个end方法,否则客户端会一直等待
②使用nodemon可以无需重复开启服务器
③返回响应中是汉字的话会乱码,可以添加上面一行代码解决
④如果content-type中为html,write和end中可以添加html标签,浏览器就可以进行解析,如果是plain则只能解析文本,当做字符串输出
⑤请求路径后如果什么都不加,会默认生成一个/
⑥响应内容只能是二进制数据或者字符串,如果要想赢其他类型(对象,数组等),使用response.end(JSON.stringify(products));转换为字符串

3.4js模块

js中的模块有三种,核心模块,自定义模块
如果是相对路径,要用./
模块文件的后缀名可以省略
node中没有全局作用域,只有模块作用域,外部访问不到内部,内部也访问不到外部

1.js核心模块
①fs核心模块
②http核心模块
③path路径操作模块
④os操作系统信息模块
核心模块的具体方法可以在node.js官网的文档中查看
加载方式:var http = require('http');

2.js自定义模块
自定义的一个js文件

3.第三方模块
art-templete
只有第三方模块需要npm下载之后才能使用

4.require
require是一个加载模块并执行里面的代码的方法,并能拿到被加载模块导出的接口对象
每个文件模块中都提供了一个空对象:exports,exports默认是一个空对象,我要做的就是把所有需要被外部成员访问的成员挂载到exports中
①a.js

var ex = require('./b');
console.log('aaa');
console.log(ex.foo);
console.log(ex.add(3,4));

②b.js

var foo = 'bbb';
console.log(foo);
exports.foo = 'export';
exports.add = function (x,y) {
    return x * y;
}

在这里插入图片描述

4.web服务器开发

4.1IP地址和端口号

IP地址用来定位计算机
端口号用来定位具体的应用程序
所有需要互联网那个通信的应用程序都会占用一个端口号
端口号范围从0-65536之间,端口号只是一个数字,并没有特殊含义
80端口是http中浏览器默认端口,不要使用
查看请求的IP地址:request.socket.remoteAddress
查看请求的端口号:request.socket.remotePort

可以开启多个服务,但要去也报不同服务占用的端口号不同

4.2content-type

http://tool.oschina.net/
可以查看其它的type类型
1.解决返回内容乱码问题
response.setHeader("Content-type","text/html;charset='utf-8'");
content-type中为html则可以解析write和end中的html标签,
如果是plain,则只能解析文本,当字符串输出

2.读取图片
res.setHeader("Content-type", "image/jpeg");
读取不同的类型要用不同的conten-type
一般只有字符需要指定文本编码,图片和其他类型不需要

3.读取案例
响应html文件也好,响应图片也好,都要通过fs读取功能获取到文件里的内容,data返回
响应的的不是文件,而是文件里的内容

var fs = require('fs');
var http = require('http');
var server = http.createServer();
server.on('request', function (req, res) {
    var url = req.url;
    if (url === '/') {
        fs.readFile('./fanhui.html', function (error, data) {
            if (error) {
                res.setHeader("Content-type", "text/plain;charset='utf-8'");
                res.end('出错啦');
            } else {
                res.setHeader("Content-type", "text/html;charset='utf-8'");
                res.end(data);
            }
           
        })
        
    } else if(url === '/img'){
        fs.readFile('./image.jpg', function (error, data) {
            if (error) {
                res.setHeader("Content-type", "text/plain;charset='utf-8'");
                res.end('出错啦');
            } else {
                res.setHeader("Content-type", "image/jpeg");
                res.end(data);
            }
           
        })
    }
})

server.listen(3000, function () {
    console.log('服务器已启动');
});

4.3初步实现apache功能

直接检索文件名的方式访问对应的响应

var http = require('http');
var fs = require('fs');
var server = http.createServer();
server.on('request', function (req, res) {
    var url = req.url;
    var wwwD = 'D:/desk/web学习/日常学习记录/10.22node1/www';
    var filepath = '/fanhui.html';
    if (url!=='/') {
        filepath = url;
    }

    fs.readFile(wwwD + filepath, function (error,data) {
        if (error) {
            //return此处作用:阻止代码继续执行
            return res.end('404 not found')
        }
        res.end(data)
    })


})

server.listen(3000, function () {
    console.log('服务器已启动');
})

还可以读取目录然后创建目录文件

4.4在node中使用模板引擎

1.安装模板引擎art-template
npm install art-template --save

2.引入方式
<script src="node_modules/art-template/lib/template-web.js"></script>

3.使用
模板引擎不关心字符内容,只关心自己的模板语法{{ }},哪怕里面写的是一个html文档也不影响
通过查询文档(github)使用模板引擎的api
①在浏览器中使用模板引擎

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script src="node_modules/art-template/lib/template-web.js"></script>
    <script type="text/template" id="tpl">

        大家好,我叫:{{name}}
        我今年{{age}}岁了
        我来自{{province}}
        我喜欢:{{each hobbies}} {{$value}} {{/each}}
	</script>
    <script>
        var ret = template('tpl', {
            name: 'jack',
            age: 18,
            province: '河北',
            hobbies: ['敲代码', '还是敲代码', '还还是敲代码']
        })
        console.log(ret);
    </script>
</body>

</html>

在这里插入图片描述
②在node中使用模板引擎

var template = require('art-template');
var fs = require('fs');
fs.readFile('./wenben.html', function (error,data) {
    if (error) {
       return  console.log('读取失败');
    }
    var ret = template.render(data.toString(), {
        name: 'jack',
        age: 18,
        province: '河北',
        hobbies: ['敲代码', '还是敲代码', '还还是敲代码']
    })
    console.log(ret);
})

在这里插入图片描述

4.5服务端渲染和客户端渲染

1.服务端渲染
在请求之后,在服务端把数据渲染完毕统一响应给客户端,客户端无需再做处理
特点:
①只发起一次请求
②加载可能较慢,但页面内容一次显示完成
③全局刷新,可以在f12审查元素里看到,可以被爬虫抓取
④有利于seo搜索引擎优化

2.客户端渲染
客户端收到响应的页面,从上到下依次解析,如果发现ajax异步请求,再次发起请求,拿到响应结果,再进行模板引擎渲染
特点:
①至少发起两次请求,一次拿到页面,一次拿到动态数据
②页面显示快,内容显示稍慢
③局部刷新,在审查元素看不到,爬虫很难抓取
④不利于seo搜索引擎优化

3.现在的网站都是两者结合来做的,比如商品列表使用客户端渲染,评论区使用服务端渲染

5.留言本案例

5.1统一处理静态资源

浏览器收到html响应内容后,就会从上到下依次解析,解析过程中,如果发现link,script,img,iframe,video,audio等带有src或者link,href属性标签时,浏览器会自动对这些资源发起新的请求
页面是一个请求,页面中的每个资源也都是一个请求,所以network中可以看到诸多请求

所以我们一般把所有静态资源都放在一个public文件夹里分类存放

**统一处理:**如果判断请求路径是/public/开头,name直接以文件路径作为路径地址进行访问,这个时候文件路径就不要写绝对路径或者相对路径了,统一写成/public/…
开头的/表示url路径

一般在网页中我们看不到html后缀,是因为采取了:
判断url=某个值,就去读取某个特定的文件

5.2案例

案例在node02文件夹中
具体思路
先引入各个核心模块
①在各个页面设置好url,
如果为静态资源则写文件地址/public开头
如果为跳转页面,则专门写一个对应的标识符
②在js文件中,针对各种请求进行对应的文件读取并响应
③处理特殊情况
填写好评论,响应时要让页面跳转到主页,可以使用重定向
跳转到主页时要对模板引擎进行渲染再响应

注意:
①页面文件统一放在view文件夹
②静态资源文件放在public中

5.3.node中的console控制台

直接在中断输入node
之后可以直接使用核心模块,无需加载
退出是两次ctrl+c
作用:做一些辅助性的api测试

零碎知识
①客户端软件版本概念比较重,网页版本概念很少涉及,网站的目的就是快,实时更新
②each是art-template的模板语法,专属的
用法:

        {{each 数组}}
                {{ $value.属性 }}
        {{/each}}

③forEach,是es5中的遍历方法,原生的
数组.forEach.(function(item,index){ })

④301永久重定向,第一次会请求,之后存到缓存,再之后就不会请求,而是读取缓存直接重定向,更快加载
302临时重定向,每次都会请求

6.node中的模块系统

6.1什么是模块化

拥有文件作用域和通信规则
在这里插入图片描述

6.2commonJS模块规范

node中的js有一个很重要的概念:模块系统
①模块作用域
②require加载模块
③exports接口对象导出模块成员

1.加载require
语法var 自定义变量名称 = require('模块');
作用:
①执行被加载模块中的代码
②得到被加载模块中exports导出接口对象

2.导出exports
node中是模块作用域,默认文件中所有成员都只在当前模块有效
对于希望可以被其他模块访问的成员,我们就需要把这些公开的成员都挂载到exports接口对象中
导出多个成员(存放于对象中,总之就是以对象形式把数据导出)

function add(x,y) {
    return x + y;
}
exports.add = add;
exports.a = 'hello';
exports.b=['sd']

module.exports = {
    add: function () {
       return x + y;
    },
    str:'hello'
}

导出单个成员(拿到的就是函数,字符串)
module.exports = 'add';
如果用多个,后者会覆盖前者

3.与案例解析
①在node中,每个模块中都有一个module对象,每个module对象中有一个exports对象
②中默认有一句var exports=module.exports,exports是module.exports的一个引用,两者等价,可以随意,混合使用
exports不能直接赋值的原因:因为一旦给它重新赋值,它就不再引用module.exports了,会指向新的对象空间,而导出的其实是module.exports和exports就没关系了
谁require,谁就获得module.exports
默认在代码中有一句return module.exports

6.3require加载规则

1.不会重复加载
多次加载,不会重复执行,执行过一次了就不再执行
如果a加载b和c,b里加载了c,那么a里的c就不会再加载了

2.模块加载规则
①自定义模块:require(‘./foo.js’);
.js可以省略

②核心模块:require(‘fs’);
直接写名字

③第三方模块
npm下载
require加载
没有任何一个第三方模块的名字和核心模块形同,放心加载
加载的是第三方包,实际上加载的还是包里的文件

3.包描述文件
package.json
就是当前包的说明书

6.4npm

npmjs.com
安装了node就意味着安装了npm
1.npm常用命令
①npm --version 查看版本
②npm install --global npm 升级npm
③npm init 跳过向导,快速生成
④npm install 包名 一次吧dependencies选项中的依赖项全部安装
简写npm i
⑤npm install --save 包名 下载保存依赖项
简写npm i -S
⑥npm uninstall 包名
简写npm un
⑦npm help 查看使用帮助
⑧npm 命令 --help 查看某个具体的命令

2.cnpm
npm的镜像
安装:npm install --global cnpm
之后安装只需要把npm改成cnpm
在这里插入图片描述

7.Express

原生http在某些方面表现不足以应对我们的开发需求,所以要是用框架加快开发
node中有很多web框架,这里血express

7.1模块路径和文件操作路径

文件操作中的文件路径的./可以省略
模块加载中的相对路径中的./不能省略

1.文件操作路径中
./相对于当前目录
不带./也是相对于当前目录
/是相对于磁盘根目录

2.模块加载路径
./相对于当前目录
/是相对于磁盘根目录

7.2基本路由

get和post
以对应方法请求的时候,会执行对应的处理函数

app.get('/', function (req,res) {
    res.send('hello express')
})

app.post('/', function (req,res) {
    res.send('logining')
})

7.3静态服务

通过检测后缀名开头路径确定访问某个路径的文件内的资源

//第一种,最常用的方式,如后缀为/public/a,就直接访问public/a文件
app.use('/public/', express.static('public'));

//第二种,默认方式,比如后缀为/a,就直接访问public/a文件
app.use(express.static('public'))

//第三种,别名方式,如后缀为/bieming/a,就直接访问public/a文件
app.use('/bieming/', express.static('public'));

7.4在express中使用art-template

1.安装
npm install --save art-template express-art-template

2.配置
前面的art就意味着识别art后缀的文件进行渲染,改成html就可以识别html文件

app.engine('art', require('express-art-template'));
app.engine('html', require('express-art-template'));

3.使用
express为response提供了一个方法render,默认不可用,配置了模板引擎才能用
第一个参数不能写路径,直接写文件名,默认会去项目中的views目录查找该模板文件
渲染并响应

app.get('/', function (req,res) {
    res.render('index.html', {
        title:'hello express'
    })
})

4.修改默认目录

app.set('views',想要修改的默认路径)

5.express的基本方法
完整项目在10.24feedback中

var express = require('express');
var app = express();
app.engine('html', require('express-art-template'));

var comments=[{
    name: '张三',
    message: '今天天气不错!',
    dateTime: '2015-10-16'
  },

]

app.get('/', function (req, res) {
    res.render('index.html',{comments:comments})
})
app.get('/post', function (req, res) {
    res.render('post.html')
})
app.get('/pinglun', function (req, res) {
    var comment = req.query
    comment.dateTime='2021-10-24'
    comments.unshift(comment)
    //重定向,不写状态码默认302
    res.redirect('/')
}) 
app.use('/public/', express.static('public'));
    
    
    
app.listen(3000, function () {
    console.log('running');
})

注意:
①req.query只能在get请求里用来获取请求体,post里不行
②在post中获取请求体要用官网的一个插件middleware
先安装
npm install --save body-parser
再引入
var bodyParser=require(‘body-parser’)
再配置
app.use(bodyParser.urlencoded({ extend: false }))
app.use(bodyParser.json())
配置完之后req就会出现一个属性req.body,可以获取请求体

7.5路由设计

在这里插入图片描述
敲代码之前先把路由表写出来

7.6入口模块和路由模块

1.入口模块
由于代码过多,为了实现模块化,常设置一个入口模块用来加载其他的功能模块
入口模块职责
①创建服务
②做一些相关配置,如模板引擎,body-parser,
③挂载路由
④监听端口启动服务

2.路由模块
路由模块通常只负责某一单一的功能
职责:
①处理路由
②根据不同的请求方法和请求路径设置不同的响应

7.7学生管理系统项目的思路步骤

1.处理模板
2.配置静态资源
3.配置模板引擎
4.设置简单路由。渲染出静态页面
5.路由设计
6.提取路由模块router
7.封装students.js处理文件数据
8.写好students的文件结构,再完善具体的功能

7.8router容器挂载和exports挂载的区别

exports挂载,好比蓝军军官投奔到红军,但军队没有一起过来,军官可以下令指挥军队,军队吃穿用的还是蓝军(依赖的还是原来文件里的模块方法等)
router容器挂载,好比蓝军军官带着自己军队投奔红军,交出指挥权,红军军官直接指挥军队,军队吃穿用的是红军的(依赖入口文件里的模板引擎,模块)

7.9其他

1.凡是要得到一个函数内部异步操作的结果(settimeout,readfile,writefile,ajax,readdir等),这些情况需要回调函数

2.js本身不支持模块化,使用node.js进行模块化
ecmascript市官方发布的标准,对js模块化进行了支持
commonjs,amd,cmd,umd等是民间模块化解决方案

3.package-lock.json
保存node_modues中所有的信息,再次npm安装的时候会更快
同时也是一个版本所,如果项目依赖了1.1.1版本,不希望升级,就可以防止自动升级版本

4.find和findindex的区别
这两个都是es6的方法

<script>
    var s = [1, 5, 10, 15].find(function (value, index, arr) {
        return value > 9
    })
    console.log(s);
    var t = [1, 5, 10, 15].findIndex(function (value, index, arr) {
        return value > 9
    })
    console.log(t);
</script>

find返回第一个满足条件的值,如果都不满足,返回undefined
findindex返回第一个满足条件的值的下标,都不满足返回-1

8.MongoDB

8.1关系型数据库和非关系型数据库

表就是关系,表与表之间存在关系
1.关系型数据库
所有的关系型数据库都需要通过sal语言来操作,在操作之前要设计表结构,数据表还支持约束(唯一,主键,默认值,非空)
2.非关系型数据库
非关系型数据库非常灵活,MongoDB是最像关系型数据库的非关系型数据库,不要设计表结构,可任意存放数据,没有结构性这么一说

8.2启动和关闭服务器

开启
mongodb默认使用执行mongod命令所在盘符根目录下的/data/db作为自己的数据存储目录
第一次执行前先手动创建一个/data/db
否则会执行失败,结尾有shuting down代表执行失败
在这里插入图片描述
控制台输入mongod

关闭
ctrl+c或者直接点叉号

修改默认存储目录
mongod --dbpath=数据存储目录路径

8.3连接与退出数据库

链接
在本机MongoDB服务开启状态下
输入mongo

退出
exit

8.4基本命令

show dbs 查看所有数据库
在这里插入图片描述
db 查看当前操作的数据库
在这里插入图片描述
use 数据库名称 切换到指定数据库,如果没有则会新建
在这里插入图片描述
db..insertOne({ })在当前数据库下插入数据
在这里插入图片描述
show collections 显示当前数据库的所有集合
在这里插入图片描述
db.
.find()查看集合详细内容
在这里插入图片描述

8.5 在node中操作MongoDB数据库

1.使用官方的mondodb包进行操作,在npm官网上搜索MongoDB
2.mongoose,是对mongodb官方包的封装
①先安装mongoose
②加载mongoose模块,引入代码

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

const Cat = mongoose.model('Cat', { name: String });

const kitty = new Cat({ name: 'Zildjian' });
kitty.save().then(() => console.log('meow'));

③启动服务器
在这里插入图片描述

④在控制台查看在这里插入图片描述

8.6MongoDB数据库的基本概念

可以有多个数据库,
一个数据库可以有多个集合(表)
一个集合可以有多个文档(表记录)
文档结构很灵活,没有任何限制
MongoDB非常灵活,不需要像Mysql一样要先创建数据库,表,设计表结构,MongoDB自动完成建库建表

1.开始
①连接数据库

var mongoose = require('mongoose')

var Schema = mongoose.Schema

// 1. 连接数据库
// 指定连接的数据库不需要存在,当你插入第一条数据之后就会自动被创建出来
mongoose.connect('mongodb://localhost/itcast')

②设计文档结构

// 2. 设计文档结构(表结构)
// 字段名称就是表结构中的属性名称
// 约束的目的是为了保证数据的完整性,不要有脏数据
var userSchema = new Schema({
  username: {
    type: String,
    required: true // 必须有
  },
  password: {
    type: String,
    required: true
  },
  email: {
    type: String
  }
})

③把文档结构发布为模型

// 3. 将文档结构发布为模型
//    mongoose.model 方法就是用来将一个架构发布为 model
//    第一个参数:传入一个大写名词单数字符串用来表示你的数据库名称
//                 mongoose 会自动将大写名词的字符串生成 小写复数 的集合名称
//                 例如这里的 User 最终会变为 users 集合名称
//    第二个参数:架构 Schema
//   
//    返回值:模型构造函数
var User = mongoose.model('User', userSchema)

2.增加数据

var admin = new User({
  username: 'zs',
  password: '123456',
  email: 'admin@admin.com'
})

admin.save(function (err, ret) {
  if (err) {
    console.log('保存失败')
  } else {
    console.log('保存成功')
    console.log(ret)
  }
})

3.查询数据

//查询所有
User.find(function (err, ret) {
    if (err) {
      console.log('查询失败')
    } else {
      console.log(ret)
    }
  })
  //指定条件查询所有
  User.find({
    username: 'zs'
  }, function (err, ret) {
    if (err) {
      console.log('查询失败')
    } else {
      console.log(ret)
    }
  })
  //查询指定条件的第一个
  User.findOne({
    username: 'zs'
  }, function (err, ret) {
    if (err) {
      console.log('查询失败')
    } else {
      console.log(ret)
    }
  })

3.删除数据和更新数据

//删除所有数据
User.remove({
    username: 'zs'
  }, function (err, ret) {
    if (err) {
      console.log('删除失败')
    } else {
      console.log('删除成功')
      console.log(ret)
    }
})
//根据条件删除一个
Model.findOneAndRemove(conditions,[options],[callback])
//根据id删除一个
Model.findByIdAndRemove(id,[options],[callback])
  

//更新所有数据
User.update(conditions,doc,[options],[callback])
  
//根据指定条件更新一个
User.findOneAndUpdate(conditions,[update],[options],[callback])
//根据id删除一个
User.findByIdAndUpdate('5a001b23d219eb00c8581184', {
    password: '123'
  }, function (err, ret) {
    if (err) {
      console.log('更新失败')
    } else {
      console.log('更新成功')
    }
})

9.Promise

callback hell回调地狱
并列的异步函数无法确定其执行顺序
解决方法:嵌套,逐个执行,后者放在前者的回调函数里,这样的嵌套称为回调地狱,很难维护

1.throw err抛出异常
阻止程序的执行,把错误消息打印到控制台

2.回调地狱解决方法promise
封装promise进行文件读取

var fs = require('fs')

function read(path) {
    return new Promise(function (resolve, reject) {
        fs.readFile(path, 'utf-8', function (err, data) {
            if (err) {
                reject(err)
            } else {
                resolve(data)
            }
        })
    })
}

read('./data/a.js')
    .then(function (data) {
        console.log(data);
        return read('./data/b.js')
    })
    .then(function (data) {
        console.log(data);
        return read('./data/c.js')
    })
    .then(function (data) {
        console.log(data);
    })

10.项目

1.include-block-extend
included:导入网页标签

{{include './header.html'}}

即可把对应网页内的标签导入此处

extend导入网页模板

{{extend './layout.html'}}

继承对应网页内的所有信息

block

{{block 'content'}}
<h1>预留信息</h1>
{{/block}}

继承之后,在本网页内使用相应的block可以替换原block里内容
理解为block挖坑,再次使用填坑

{{extend './layout.html'}}
{{block 'content'}}
<div>
    填坑
</div>
{{/block}}

案例书写步骤
①目录结构
②模板页
③路由设计
④模型设计
⑤功能实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值