Web服务器(go net/http) 处理Get、Post请求

news2024/9/22 21:22:15

大家好 我是寸铁👊
总结了一篇Go Web服务器(go net/http) 处理Get、Post请求的文章✨
喜欢的小伙伴可以点点关注 💝

前言

go http请求如何编写简单的函数去拿到前端的请求(Get和Post) 服务器(后端)接收到请求后,又是怎么处理请求,再把响应返回给客户端?

在这里插入图片描述

操作步骤:

Step1:注册监听和服务的端口

一开始,我们需要注册监听和服务的端口

我们需要调用go中提供的net/http这个函数包的ListenAndServe函数

方式一:

http.ListenAndServe(":8080", nil)

注意:这里号要带上,不能只写8080(踩坑经历)

等价于

http.ListenAndServe("127.0.0.1:8080", nil)

方式二:

考虑到很多时候,可能并不是直接访问本机127.0.0.1:8080端口,这里可以写具体地址:端口号(其实就是一个Socket)

如:

http.ListenAndServe("192.168.0.1:3306", nil)

在知道怎么操作后,我们来了解一下底层源码具体是怎么实现?了解后,便于更清楚的知道整体的流程!

在这里插入图片描述

ListenAndServe()函数有两个参数,当前监听的端口号和事件处理器Handler。

事件处理器的Handler接口定义如下:

 type Handler interface {
     ServeHTTP(ResponseWriter, *Request)
 }

Handler 接口: Handler 是一个接口类型,声明了一个方法 ServeHTTP。这个接口规定了任何实现了 ServeHTTP 方法的类型都可以被视为一个 HTTP 请求处理器。

ServeHTTP 方法: ServeHTTP 方法有两个参数,分别是 ResponseWriter*Request

  • ResponseWriter 接口用于构建 HTTP 响应。它提供了一系列方法,允许你设置响应的状态码、头部信息以及响应主体内容。
  • *Request 类型表示 HTTP 请求。它包含了所有关于客户端请求的信息,比如请求方法、请求头、URL 等。

PS:实现Handle接口不用写ServeHttp方法,会比较方便。

后面的代码都是用的封装好的handler处理器,帮我们写好ResponseWriter*Request ,只需专注业务逻辑即可。

后续分析这两个参数的包含的具体信息

只要实现了这个接口,就可以实现自己的handler处理器。Go语言在net/http包中已经实现了这个接口的公共方法:

 type HandlerFunc func(ResponseWriter, *Request)// ServeHTTP calls f(w, r).
 func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
     f(w, r)
 }

如果ListenAndServe()传入的第一个参数地址为空,则服务器在启动后默认使用http://localhost:8080地址进行访问;

如果这个函数传入的第二个参数为nil,则服务器在启动后将使用默认的多路复用器DefaultServeMux

再来分析一下内层的server代码

server结构体

server := &Server{Addr: addr, Handler: handler}

这是一种原生的写法,我们也可以自己根据这段代码来对server进行更详细的定义。如下:

 s := &http.Server{
     Addr:           ":8081", //地址
     Handler:        myHandler,//处理器
     ReadTimeout:    20 * time.Second, //读的超时设置 
     WriteTimeout:   20 * time.Second, //写的超时设置
     MaxHeaderBytes: 1 << 10, //传输的最大头部字节
 }

net/http.ServerHTTP 服务器的主要结构体,用于控制 HTTP 服务器的行为。

其结构体定义为:

type Server struct {
//服务器监听的地址和端口号,格式为 "host:port",例如 "127.0.0.1:8080"
 Addr                         string
//HTTP 请求的处理器。对于每个收到的请求,服务器会将其路由到对应的处理器进行处理。通常使用 http.NewServeMux() 方法创建一个默认的多路复用器,并将其作为处理器。如果没有设置该字段,则使用 DefaultServeMux
 Handler                      Handler
//一个布尔值,用于指示是否禁用 OPTIONS 方法的默认实现。如果该值为 true,则在收到 OPTIONS 请求时,服务器不会自动返回 Allow 头部,而是交给用户自行处理。默认为 false,即启用 OPTIONS 方法的默认实现
 DisableGeneralOptionsHandler bool
//HTTPS 服务器的 TLS 配置,用于控制 HTTPS 服务器的加密方式、证书、密钥等安全相关的参数
 TLSConfig                    *tls.Config
//HTTP 请求的读取超时时间。如果服务器在该时间内没有读取到完整的请求,就会关闭连接。该字段为 time.Duration 类型,默认为 0,表示没有超时限制
 ReadTimeout                  time.Duration
//HTTP 请求头部读取超时时间。如果服务器在该时间内没有完成头部读取,就会关闭连接。该字段为 time.Duration 类型,默认为 0,表示没有超时限制
 ReadHeaderTimeout            time.Duration
//HTTP 响应的写入超时时间。如果服务器在该时间内没有完成对响应的写入操作,就会关闭连接。该字段为 time.Duration 类型,默认为 0,表示没有超时限制
 WriteTimeout                 time.Duration
//HTTP 连接的空闲超时时间。如果服务器在该时间内没有收到客户端的请求,就会关闭连接。该字段为 time.Duration 类型,默认为 0,表示没有超时限制
 IdleTimeout                  time.Duration
//HTTP 请求头部的最大大小。如果请求头部的大小超过该值,服务器就会关闭连接。该字段为 int 类型,默认为 1 << 20(1MB)
 MaxHeaderBytes               int
 TLSNextProto                 map[string]func(*Server, *tls.Conn, Handler)
//连接状态变化的回调函数,用于处理连接的打开、关闭等事件
 ConnState                    func(net.Conn, ConnState) 
//错误日志的输出目标。如果该字段为 nil,则使用 log.New(os.Stderr, "", log.LstdFlags) 创建一个默认的日志输出目标
 ErrorLog                     *log.Logger
//所有 HTTP 请求的基础上下文。当处理器函数被调用时,会将请求的上下文从基础上下文派生出来。默认为 context.Background()。
 BaseContext                  func(net.Listener) context.Context 
//连接上下文的回调函数,用于创建连接上下文。每个连接上下文都与一个客户端连接相关联。如果未设置该字段,则每个连接的上下文都是 BaseContext 的副本
 ConnContext                  func(ctx context.Context, c net.Conn) context.Context
//标志变量,用于表示服务器是否正在关闭。该变量在执行 Shutdown 方法时被设置为 true,用于避免新的连接被接受
 inShutdown                   atomic.Bool 
//标志变量,用于控制服务器是否支持 HTTP keep-alive。如果该变量为 true,则服务器在每次响应完成后都会关闭连接,即不支持 keep-alive。如果该变量为 false,则服务器会根据请求头部中的 Connection 字段来决定是否支持 keep-alive。该变量在执行 Shutdown 方法时被设置为 true,用于关闭正在进行的
 disableKeepAlives            atomic.Bool
// 一个 sync.Once 类型的值,用于确保在多线程环境下,NextProtoOnce 方法只被调用一次。NextProtoOnce 方法用于设置 Server.NextProto 字段
 nextProtoOnce                sync.Once 
// error 类型的值,用于记录 NextProto 方法的调用结果。该值在多个 goroutine 之间共享,用于检测 NextProto 方法是否成功
 nextProtoErr                 error 
//互斥锁,用于保护 Server 结构体的字段。因为 Server 结构体可能被多个 goroutine 并发访问,所以需要使用互斥锁来确保它们的安全性
 mu                           sync.Mutex    
//存储 HTTP 或 HTTPS 监听器的列表。每个监听器都是一个 net.Listener 接口类型的实例,用于接收客户端请求。当调用 Server.ListenAndServe() 或 Server.ListenAndServeTLS() 方法时,会为每个监听地址创建一个对应的监听器,并将其添加到该列表中
 listeners                    map[*net.Listener]struct{}
//表示当前处于活动状态的客户端连接的数量。该字段只是一个计数器,并不保证一定准确。该字段用于判断服务器是否处于繁忙状态,以及是否需要动态调整服务器的工作负载等
 activeConn                   map[*conn]struct{}                                    
//在服务器关闭时执行的回调函数列表。当服务器调用 Server.Shutdown() 方法时,会依次执行该列表中的每个回调函数,并等待它们全部执行完毕。该字段可以用于在服务器关闭时释放资源、保存数据等操作
 onShutdown                   []func()                                              
//表示所有监听器的组。该字段包含一个读写互斥锁 sync.RWMutex 和一个映射表 map[interface{}]struct{}。在监听器启动时,会将监听器地址作为键添加到映射表中。该字段主要用于实现优雅地关闭服务器。在服务器关闭时,会遍历所有监听器,逐个关闭它们,并等待所有连接关闭。如果在等待连接关闭时,有新的连接进来,服务器会先将新连接添加到 activeConn 字段中,并等待所有连接关闭后再退出。这样可以保证服务器在关闭过程中,不会丢失任何连接
 listenerGroup                sync.WaitGroup                                        
}

Step2.1: 调用HandleFunc函数处理get请求

HandleFunc函数

在上面的代码的基础上,开始调用常用的处理请求的函数HandleFunc函数

在调用前,不妨先了解一下HandleFunc函数的作用是什么?

HandleFunc 函数的作用是创建一个处理器并将其注册到指定的路径上。这个处理器会调用提供的函数处理请求。这种方式非常方便,因为你可以直接使用一个函数来处理请求,而不必实现完整的 http.Handler 接口。

有了上面的基础后,编写一个案例摸清HandleFunc函数。

测试案例

package main

import (
	"fmt"
	"net/http"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "Hello, World!")
}

func main() {
	http.ListenAndServe(":8080", nil)
	http.HandleFunc("/hello", helloHandler)
}

输出结果如下:

在这里插入图片描述

分析一下这段代码

在这里插入图片描述

在这个例子中helloHandler 函数处理 /hello 路径上的请求。通过 http.HandleFunc 将这个函数helloHandler 注册到指定的路径,然后使用 http.ListenAndServe 启动 HTTP 服务器。

当有请求访问 /hello 路径时,将调用 helloHandler 函数来处理请求。


有了HandleFunc函数的基础后,下面正式进入处理客户端发送过来的get请求

处理客户端的get请求
运行效果及逐行分析

代码

package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	//get请求
	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
        
		query := request.URL.Query() //接收到客户端发送的get请求的URL
		fmt.Print(request.URL.Path) //后端显示打印很多相关的内容
        
        
        //io包下提供的写方法,将服务端get到的id和name以字符串的形式写到客户端显示
		io.WriteString(writer, "query:"+query.Get("id")+query.Get("name"))
	})

    
    	http.ListenAndServe(":8080", nil)

}

运行上面这段代码后,我们来看一下运行的结果,从结果去不断梳理整个处理的过程。

运行结果如下

在这里插入图片描述

分析运行结果

在这里插入图片描述

逐行逐行详解:

http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) 
  • 这一行代码使用 http.HandleFunc 函数将一个匿名函数注册到根路径("/")上,也就是处理默认的请求。这个匿名函数接受两个参数,writer 是用于写入响应的 http.ResponseWriter 接口,而 request 是表示客户端请求的 http.Request 结构。
query := request.URL.Query()
  • 通过 request.URL.Query() 获取请求的 URL 中的查询参数,并将其存储在 query 变量中。查询参数通常是在 URL 中以 ? 后面的键值对形式出现的,例如:http://localhost:8080/?id=123&name=John
fmt.Print(request.URL.Path)
  • 在控制台上查看请求的路径信息
io.WriteString(writer, "query:"+query.Get("id")+query.Get("name"))
  • 使用 io.WriteString 将包含查询参数的字符串写入响应。它会将 “query:” 后面连接着 idname 参数的值。

总结:

当有请求访问根路径("/")时,打印请求的路径并返回包含查询参数的字符串响应。

request的api的具体信息

在演示了基本的get请求结果后,服务端往客户端返回的响应(写一句话)

下面开始在控制台输出request其他相关的具体信息

先来看一下可以调用request的哪些具体属性(字段)

在这里插入图片描述

request可调出的属性比较多,每个属性中对应的api方法也比较多。

这里演示常用的api,需要获取request的具体api方法可以直接查。

演示结果如下:

在这里插入图片描述

demo

package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	//get请求
	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {

		query := request.URL.Query()
		//设置request请求头部的字段 如设置name为hello

		fmt.Println("request.URL.Path内容:", request.URL.Path) //可以打印很多相关的内容
		fmt.Println("request.URL.Host内容:", request.URL.Host) //可以打印很多相关的内容
		fmt.Println("request.URL.Fragment内容:", request.URL.Fragment)
		fmt.Println("request.URL.Scheme内容:", request.URL.Scheme)
		fmt.Println("request.URL.User内容:", request.URL.User)
		fmt.Println("request.Header内容:", request.Header)
		fmt.Println("request.Body内容:", request.Body)
		fmt.Println("request.ContentLength内容为:", request.ContentLength)
		fmt.Println("request.Method内容为:", request.Method)
		fmt.Println("request.Close内容为:", request.Close)
		io.WriteString(writer, "query:"+query.Get("id")+query.Get("name"))
	})

	http.ListenAndServe(":8080", nil)

}

处理器writer和request的具体信息

在前面的应用基础上,下面正式分析处理器的writerrequest的来源和相关信息

http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) 
  • 先看writer http.ResponseWriter

http.ResponseWriter是一个接口类型:

// net/http/server.go
type ResponseWriter interface {
  Header() Header
  Write([]byte) (int, error)
  WriteHeader(statusCode int)
}

用于向客户端发送响应,实现了ResponseWriter接口的类型显然也实现了io.Writer接口。所以在处理函数index中,可以调用fmt.Fprintln()ResponseWriter写入响应信息。

这也很好的解释了前面代码调用io.writeString方法将返回的响应信息写入实现了ResponseWriter接口的对象writer,再调用方法返回响应信息。

io.WriteString(writer, "query:"+query.Get("id")+query.Get("name"))

代码剖析

定义了一个接口 ResponseWriter,该接口规定了用于写入 HTTP 响应的方法。

接口中的每个方法如下:

Header() Header:

Header() 方法返回一个 Header 类型的值。Header 是一个映射(map),用于表示 HTTP 响应头。响应头包括一系列的键值对,每个键值对表示一个响应头字段和它的值。


Write([]byte) (int, error):

Write 方法接受一个字节切片([]byte)作为参数,并返回写入的字节数和可能的错误。这个方法用于将字节数据写入 HTTP 响应体。


WriteHeader(statusCode int):

WriteHeader 方法接受一个整数参数 statusCode,用于设置 HTTP 响应的状态码。HTTP 状态码是一个三位数的代码,用于表示服务器对请求的处理结果。例如,200 表示成功,404 表示资源未找到,500 表示服务器内部错误等。

编写一个 HTTP 处理器时,会接收到一个实现了 ResponseWriter 接口的对象writer,可以通过该对象来设置响应头、写入响应体以及设置状态码等信息。

补充:

在 Go 中,通常会使用http.ResponseWriter类型的变量来表示实现了 ResponseWriter 接口的对象。例如,在你的 HTTP 处理器函数中,如下:

func MyHandler(writer http.ResponseWriter, r *http.Request) {
    // 使用 writer来设置响应头、写入响应体等
}

这样,便可以通过 writer 对象来操作 HTTP 响应。


  • 再看request的具体信息

net/http中的 Request结构体表示一个HTTP请求,包含请求方法URL请求头请求体等信息。信息主要在文件 net/http/request.go中。

结构体中字段的信息:

type Request struct {
 Method           string                    
 //HTTP请求方法,如GET、POST等

 URL              *url.URL
 //HTTP请求的URL地址,是一个指向url.URL类型的指针。

 Proto            string                        
 //HTTP协议版本,如"HTTP/1.0"或者"HTTP/1.1"

 ProtoMajor       int                          
 //HTTP协议的主版本号,整数类型。如1

 ProtoMinor       int                           
 //HTTP协议的次版本号,整数类型。如0

 Header           Header                       
 //HTTP请求头信息,是一个http.Header类型的映射,用于存储HTTP请求头。

 Body             io.ReadCloser                 
 //HTTP请求体,是一个io.ReadCloser类型的接口,表示一个可读可关闭的数据流。

 GetBody          func() (io.ReadCloser, error) 
 //HTTP请求体获取函数

 ContentLength    int64                        
 //HTTP请求体的长度,整数类型。

 TransferEncoding []string                      
 //HTTP传输编码,如"chunked"等。

 Close            bool                          
 //表示在请求结束后是否关闭连接。

 Host             string                        
 //HTTP请求的主机名或IP地址,字符串类型。
 Form             url.Values                    
 //HTTP请求的表单数据,是一个url.Values类型的映射,用于存储表单字段和对应的值。

 PostForm         url.Values                    
 //HTTP POST请求的表单数据,同样是一个url.Values类型的映射。

 MultipartForm    *multipart.Form             
 //HTTP请求的multipart表单数据,是一个multipart.Form类型的结构体。

 Trailer          Header                        
 //HTTP Trailer头信息,是一个http.Header类型的映射,用于存储Trailer头部字段和对应的值。

 RemoteAddr       string                       
 //请求客户端的地址。

 RequestURI       string                        
 //请求的URI,包括查询字符串。

 TLS              *tls.ConnectionState          
 //如果请求是使用TLS加密的,则该字段存储TLS连接的状态信息。

 Cancel           <-chan struct{}               
 //一个只读通道,用于在请求被取消时发送信号。

 Response         *Response                     
 //一个指向http.Response类型的指针,表示HTTP响应信息。

 ctx              context.Context               
 //一个context.Context类型的上下文,用于控制请求的超时和取消。

}

Step2.2: 调用HandleFunc函数处理post请求

http.HandleFunc("/user/add", func(writer http.ResponseWriter, request *http.Request) {
    // ...
})

这里使用 http.HandleFunc 函数注册了一个处理 “/user/add” 路径的回调函数。当有请求访问 “/user/add” 路径时,Go 将调用这个函数来处理请求。

这是注册的回调函数的签名,它接收两个参数,一个是 http.ResponseWriter,用于构建 HTTP 响应,另一个是 http.Request,包含了客户端的 HTTP 请求信息。

var params map[string]string //创建map
decoder := json.NewDecoder(request.Body)
//调用NewDecoder() 创建body的json解码器
decoder.Decode(&params)
//json解码成map后存储到params变量 

这段代码使用 Go 标准库的 encoding/json 包创建了一个 JSON 解码器 decoder,然后将 HTTP 请求的主体(body)中的 JSON 数据解码到 params 变量中。params 是一个 map[string]string 类型,用于存储 JSON 解析后的键值对。

其实就是将json转换为map

io.WriteString(writer, "postjson:"+params["name"])

最后,通过 io.WriteStringhttp.ResponseWriter 写入响应。这个响应是一个字符串,包含了 “postjson:” 和从 JSON 中提取的名为 “name” 的字段的值。

总结:

代码用于处理 POST 请求,解析请求主体中的 JSON 数据,并返回一个字符串响应,其中包含从 JSON 中提取的 "name" 字段的值。

运行结果如下:

在这里插入图片描述


http.HandleFunc("/user/del", func(writer http.ResponseWriter, request *http.Request) 

这里使用 http.HandleFunc 函数注册了一个处理 “/user/del” 路径的回调函数。当有请求访问 “/user/del” 路径时,Go 将调用这个函数来处理请求。

接着是注册的回调函数的签名,它接收两个参数,一个是 http.ResponseWriter,用于构建 HTTP 响应,另一个是 http.Request,包含了客户端的 HTTP 请求信息。

request.ParseForm()

这行代码调用了 ParseForm 方法,用于解析请求的表单数据(包括 URL 中的查询参数和请求体中的表单数据)。这是因为后面的代码使用了 request.Form.Get("name") 来获取表单中名为 “name” 的字段的值。

io.WriteString(writer, "form:"+request.Form.Get("name"))

最后,通过 io.WriteStringhttp.ResponseWriter 写入响应。这个响应是一个字符串,包含了 “form:” 和从表单中提取的名为 “name” 的字段的值。

总结

其实就是用于处理·"/user/del"路径的请求,解析表单数据,并返回一个字符串响应,其中包含从表单中提取的 "name" 字段的值。

运行结果如下:

在这里插入图片描述


demo

package main

import (
	"encoding/json"
	"io"
	"net/http"
)

func main() {

	//Post请求
	//添加用户 post client - server post entype postman JSON client ajax
	//客户端向服务端发送请求
	http.HandleFunc("/user/add", func(writer http.ResponseWriter, request *http.Request) {
		//POST DATA ENTYPE JSON
		var params map[string]string
		decoder := json.NewDecoder(request.Body)
		decoder.Decode(&params)
		//传入地址 将传入的json转换为对应的map格式
		io.WriteString(writer, "postjson:"+params["name"]) //通过map获取对应的值
	})

	http.HandleFunc("/user/del", func(writer http.ResponseWriter, request *http.Request) {
		request.ParseForm() //不能直接使用Get 需要转换一下
		io.WriteString(writer, "form:"+request.Form.Get("name"))
	})

	http.ListenAndServe(":8080", nil)

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1244808.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu安装CUDA驱动

Ubuntu安装CUDA驱动 前言官网安装确认安装版本安装CUDA Toolkit 前言 CUDA驱动一般指CUDA Toolkit&#xff0c;可通过Nvidia官网下载安装。本文介绍安装方法。 官网 CUDA Toolkit 最新版&#xff1a;CUDA Toolkit Downloads | NVIDIA Developer CUDA Toolkit 最新版文档&…

致远M3 反序列化RCE漏洞复现(XVE-2023-24878)

0x01 产品简介 M3移动办公是致远互联打造的一站式智能工作平台&#xff0c;提供全方位的企业移动业务管理&#xff0c;致力于构建以人为中心的智能化移动应用场景&#xff0c;促进人员工作积极性和创造力&#xff0c;提升企业效率和效能&#xff0c;是为企业量身定制的移动智慧…

Python----类对象和实例对象

目录 一.类和类的实例 二.类属性和实例属性 三.私有属性和公有属性 四.静态方法和类方法 五.__init__方法&#xff0c;__new__方法和__del__方法&#xff1a; 六.私有方法和公有方法 七.方法的重载 八.方法的继承 九.方法的重写 十.对象的特殊方法 十一.对象的引用&a…

selenium下拉框的操作这样做,阿里p10都直呼牛逼

下拉框处理 web页面上经常会有下拉框&#xff0c;对下拉框的处理比较简单&#xff0c;一般分为两种情况&#xff1a; 一、下拉框通过元素定位识别 driver.find_element(By.XPATH,//option[value"peach"]).click() 二、创建一个select的对象&#xff0c;然后通过相…

C/C++小写字母的判断 2022年3月电子学会中小学生软件编程(C/C++)等级考试一级真题答案解析

目录 C/C小写字母的判断 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C小写字母的判断 2022年3月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 输入一个字符&#xff0c;判断是否是英文小…

2023亚太杯数学建模C题思路分析 - 我国新能源电动汽车的发展趋势

1 赛题 问题C 我国新能源电动汽车的发展趋势 新能源汽车是指以先进技术原理、新技术、新结构的非常规汽车燃料为动力来源( 非常规汽车燃料指汽油、柴油以外的燃料&#xff09;&#xff0c;将先进技术进行汽车动力控制和驱动相结 合的汽车。新能源汽车主要包括四种类型&#x…

面试:RabbitMQ相关问题

文章目录 简单介绍RabbitMQRabbitMQ架构什么是 RabbitMQ&#xff1f;有什么显著的特点&#xff1f;RabbitMQ 有那些基本概念&#xff1f;RabbitMQ routing 路由模式消息怎么路由&#xff1f;RabbitMQ publish/subscribe 发布订阅(共享资源)能够在地理上分开的不同数据中心使用 …

用于计算机屏幕安全摄像头系统:Screen Anytime Crack

Screen Anytime 是一款软件&#xff0c;旨在自动将整个用户会话或 PC/服务器/VM/Kiosk 的 /RDP/Citrix/RemoteApp 会话的屏幕活动记录到视频日志文件中&#xff0c;以用于记录、审核和监控目的。通过重播其高度压缩的视频&#xff0c;您可以轻松回顾单台计算机或一组服务器/PC …

/etc/sudoers visudo

允许不输入密码 %wheel ALL(ALL) NOPASSWD: ALL %sudo ALL(ALL) NOPASSWD: ALL %wheel ALL(ALL:ALL) NOPASSWD: ALL %sudo ALL(ALL:ALL) NOPASSWD: ALLFedora39 对比 Ubuntu22.04.3 的 /etc/sudoers ## Next comes the main part: which users can run what software on ## …

由红黑树引出的HashMap扩容机制的思考

红黑树是什么&#xff1f; 三大特点&#xff1a; 根节点是黑色&#xff0c;叶节点是不存储数据的黑色空节点 任何相邻的两个节点不能同时为红色 任意节点到其可到达的节点间包含相同数量的黑色节点 联想&#xff1a;Java HashMap底层红黑树原理 HashMap基于哈希表Map接口实…

【Docker】从零开始:9.Docker命令:Push推送仓库(Docker Hub,阿里云)

【Docker】从零开始&#xff1a;9.Docker命令:Push推送仓库 知识点1.Docker Push有什么作用&#xff1f;2.Docker仓库有哪几种2.1 公有仓库2.2 第三方仓库2.3 私有仓库2.4 搭建私有仓库的方法有哪几种 3.Docker公有仓库与私有仓库的优缺点对比 Docker Push 命令标准语法操作参数…

补充:如何提高selenium的运行速度?

已经通读该专栏文章的同学,或许对UI自动化测试有了一定的掌握,细心的同学肯定会发现一个问题,当用例量达到一定程度时,对于整体用例的执行速度肯定不会很满意。除了应用多线程运行用例的方式加快速度,有没有其他的方法呢? 今天告诉大家,方法是有的!也是本人新学的。即…

golang学习笔记——创建项目

创建项目 从Go 1.8开始&#xff0c;将GOPATH设置为环境变量不是必需的。如果我们没有设置一个&#xff0c;Go使用默认的GOPATH为$HOME/go。可以使用go env查看环境变量信息。 创建项目 # 创建项目目录 mkdir helloLog cd helloLog # 使用go mod初始化项目,生成go.mod文件 go…

请你说一下Vue中v-if和v-for的优先级谁更高

v-if 与 v-for简介 v-ifv-forv-if & v-for使用 v-if 与 v-for优先级比较 vue2 中&#xff0c;v-for的优先级高于v-if 例子进行分析 vue3 v-if 具有比 v-for 更高的优先级 例子进行分析 总结 在vue2中&#xff0c;v-for的优先级高于v-if在vue3中&#xff0c;v-if的优先级高…

二叉树的顺序结构及实现

目录 1 二叉树的顺序结构2. 堆的概念及结构3 .堆的实现(小堆) 1 二叉树的顺序结构 普通的二叉树是不适合用数组来存储的&#xff0c;因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储&#xff0c;…

windows11上enable WSL

Windows电脑上要配置linux&#xff08;这里指ubuntu&#xff09;开发环境&#xff0c;主要有三种方式&#xff1a; 1&#xff09;在windows上装个虚拟机&#xff08;比如vmware&#xff09;。缺点是vmware加载ubuntu后系统会变慢很多&#xff0c;而且需要通过samba来实现window…

基于DCT变换的图像压缩解压缩算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1、DCT变换原理 4.2、基于DCT的图像压缩 4.3、基于DCT的图像解压缩 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ...................…

消息中间件——RabbitMQ(六)理解Exchange交换机核心概念!

前言 来了解RabbitMQ一个重要的概念&#xff1a;Exchange交换机 1. Exchange概念 Exchange&#xff1a;接收消息&#xff0c;并根据路由键转发消息所绑定的队列。 蓝色框&#xff1a;客户端发送消息至交换机&#xff0c;通过路由键路由至指定的队列。 黄色框&#xff1a;交换…

案例022:基于微信小程序的行政复议在线预约系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

微信小程序实现【点击 滑动 评分 评星(5星)】功能

wxml文件&#xff1a; <view class"wxpl_xing"><view class"manyidu">{{scoreContent}}</view><view><block wx:for{{scoreArray}} wx:for-item"item"><view classstarLen bindtapchangeScore data-sy"{{…