十三.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}}
案例书写步骤
①目录结构
②模板页
③路由设计
④模型设计
⑤功能实现