Go 1.19.4 HTTP编程-Day 20

1. HTTP协议

1.1 基本介绍

  • HTTP协议又称超文本传输协议,属于应用层协议,在传输层使用TCP协议。
  • HTTP协议属是无状态的,对事务处理没有记忆能力,如果需要保存状态需要引用其他技术,如Cookie。
  • HTTP协议属是无连接的,每次连接只处理一个请求。因为早期带宽和计算资源有限,这么做是为了加快传输速度,后来通过Connection:Keep-Alive实现了长连接。
  • http1.1废弃了Keep-Alive,默认支持长连接。

1.2 http requst(请求报文)

(1)请求行:GET / HTTP/1.1

  • GET:请求方法。
  • /:URL(请求路径)
  • 协议版本:HTTP/1.1

(2)请求头

  • Host: www.baidu.com:告诉服务器请求的目标地址。
  • User-Agent: curl/7.65.0:表明请求是由curl工具发起的,版本是7.65.0。
  • Accept: */*:表示客户端可以接受任何类型的响应内容。

如果是POST请求,那么请求头中的内容更多。如:

  • Accept-Language: en-US,en:客户端可接受的语言。
  • Accept-Encoding: gzip, deflate, br:客户端能够处理的压缩格式。
  • Authorization: Bearer token_value:如果需要认证,此处包含认证(证书)信息。
  • Cache-Control: no-cache:指定请求和响应遵循的缓存机制。no-cache表示无缓存机制。
  • 等等其他内容。

(3)空行

就Accept: */*下面那个空行。


(4)请求正文

注意:GET请求,是没有请求正文的。举例一个POST请求:

name=John+Doe&age=30,这就是POST请求的请求主正文。

1.3 请求方法介绍

请求方法含义
GET请求获取Request-URI所标识的资源,如下载一张图片。
POST向服务器提交数据进行处理,比如提交表单或者上传文件。数据通常放在请求正文中。
HEAD类似于GET,但是返回的响应中没有具体的内容。主要用于获取响应头部。
PUT上传文件或提交资源到服务器,通常指定了资源的URI。
DELETE请求服务器删除指定的页面。
OPTIONS查看服务端的性能。
TRACE类似于链路追踪,可以看到请求经过了哪些节点以及耗时等。
PATCH类似PUT,但它可以只对资源的一部分进行更新,资源不存在时则创建。

注意:

  • 实际工作中,服务端对各种请求方法的处理方式可能不是按照我们标准的协议来的,比如服务端收到的是PUT请求,但执行的是删除操作,具体还要看开发者怎么定义。
  • 大多数浏览器只支持GET和POST。

1.4 http response(响应报文)

(1)响应状态行:HTTP/1.1 200 OK

  • HTTP/1.1:表示请求协议版本。
  • 200:表示请求状态码。
  • OK:表示状态消息。

(2)响应头

  • Accept-Ranges: bytes:表示服务器能够接受以字节为单位的范围请求。
  • Cache-Control:指示响应不能被缓存。
  • Connection: keep-alive:表示这个TCP连接在发送完响应后不会关闭,可以被重用。
  • Content-Length: 2381:响应体的长度是2381字节。
  • Content-Type: text/html:响应体的类型是HTML。
  • Date:响应生成的日期和时间。
  • Etag:资源的一个特定版本的标识。
  • Last-Modified:资源最后被修改的日期和时间。
  • Pragma: no-cache:一个指令,要求请求和响应遵循HTTP/1.0的缓存机制,不要缓存。
  • Server: bfe/1.0.8.18:服务器使用的软件信息。
  • Set-Cookie:服务器设置了一个名为BDOZ的cookie,有效期为86400秒,域名为.baidu.com。

(3)空行


(4)响应报文主体

  • <!DOCTYPE html> ... </html>

1.5 URL和URI

1.5.1 基本介绍

  • URI:统一资源标识符(Uniform Resource Identifier),是一个用于标识资源的字符串。它提供了一种方式,通过该方式可以唯一地标识互联网上的资源,但没有提供访问方式
  • URL:统一资源定位符(Uniform Resource Locator),是URI的一种,用于定位资源。它不仅标识资源,还提供了如何通过互联网访问该资源的具体信息

1.5.2 示例

2. go语言http标准库

在go中实现http编程,主要是使用go包中的net/http。

net:net包为网络I/O提供了一个可移植的接口,包括TCP/IP、UDP、域名解析和Unix域套接字。

  • http:http 包提供了 HTTP 客户端和服务器实现。
  • 其余协议参考官网。

2.1 GET请求

2.1.1 http服务端

2.1.1.1 编辑代码
package main

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

// w http.ResponseWriter, r *http.Request: 为固定写法
func BoyHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "Hello Boy")
}

func GirlHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "Hello Girl")
}

func main() {
	// 定义路由
	// 请求"/boy"路径,就调用BoyHandler函数
	http.HandleFunc("/boy", BoyHandler)
	http.HandleFunc("/gir", GirlHandler)

	// 服务启动后的端口号
	err := http.ListenAndServe(":5656", nil) // 注意:成功启动的话,就会一直阻塞(没有输出)。
	if err != nil {
		log.Panic(err)
	}
}
2.1.1.2 浏览器请求服务端

2.1.2 http客户端

2.1.2.1 编辑代码并发起GET请求
package main

import (
	"io"
	"log"
	"net/http"
	"os"
)

func get() {
	// 定义一个GET请求
	r, err := http.Get("http://localhost:5656/gir")
	if err != nil {
		log.Panic(err)
	}
	defer r.Body.Close() // 用完关闭,否则会协程泄露

	// 因为Body方法没有办法直接打印出来,所以把它复制到标准输出。
	io.Copy(os.Stdout, r.Body)
}

func main() {
	get()
}
============调试结果============
Hello Girl

2.1.3 增加其他http信息

2.1.3.1 服务端
package main

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

// w http.ResponseWriter, r *http.Request: 为固定写法
func BoyHandler(w http.ResponseWriter, r *http.Request) {

	// 显示请求头
	for k, v := range r.Header {
		fmt.Printf("%v: %v\n", k, v)
	}

	fmt.Fprint(w, "Hello Boy\n")
}

func GirlHandler(w http.ResponseWriter, r *http.Request) {
	for k, v := range r.Header {
		fmt.Printf("%v: %v\n", k, v)
	}

	fmt.Fprint(w, "Hello Girl\n")
}

func main() {
	http.HandleFunc("/boy", BoyHandler)
	http.HandleFunc("/gir", GirlHandler)

	err := http.ListenAndServe(":5656", nil)
	if err != nil {
		log.Panic(err)
	}
}
2.1.3.2 客户端
package main

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

func get() {
	r, err := http.Get("http://localhost:5656/boy")
	if err != nil {
		log.Panic(err)
	}
	defer r.Body.Close()

	io.Copy(os.Stdout, r.Body)

	// 显示响应头
	for k, v := range r.Header {
		fmt.Printf("%v: %v\n", k, v)
	}

	// 显示请求协议
	fmt.Printf("Proto:%v\n", r.Proto)

	fmt.Printf("Close: %v\n", r.Close)

	// 显示请求内容长度
	fmt.Printf("ContentLength: %v\n", r.ContentLength)

	// 请求协议主版本号
	fmt.Printf("ProtoMajor: %+v\n", r.ProtoMajor)

	// 请求协议次版本号
	fmt.Printf("ProtoMinor: %+v\n", r.ProtoMinor)

	// 原始请求
	fmt.Printf("Request: %+v\n", r.Request)

	// 请求状态,含状态码和OK与否
	fmt.Printf("Status: %+v\n", r.Status)

	// 请求状态码
	fmt.Printf("StatusCode: %+v\n", r.StatusCode)

	// 请求方法
	fmt.Printf("Request.Method: %+v\n", r.Request.Method)

	// 请求地址
	fmt.Printf("%+v\n", r.Request.URL)

    // 还有很多内容,这里只展示部分。
}

func main() {
	get()
}

2.1.4 请求测试

2.1.4.1 客户端

2.1.4.2 服务端

2.2 POST请求

2.2.1 服务端代码

package main

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

func BoyHandler(w http.ResponseWriter, r *http.Request) {
	// 关闭请求主体
	defer r.Body.Close()

	// 显示请求主体
	io.Copy(os.Stdout, r.Body)

	for k, v := range r.Header {
		fmt.Printf("%v: %v\n", k, v)
	}

	fmt.Fprint(w, "Hello Boy\n")
}

func GirlHandler(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	// 显示请求主体
	io.Copy(os.Stdout, r.Body)

	for k, v := range r.Header {
		fmt.Printf("%v: %v\n", k, v)
	}

	fmt.Fprint(w, "Hello Girl\n")
}

func main() {
	http.HandleFunc("/boy", BoyHandler)
	http.HandleFunc("/gir", GirlHandler)

	err := http.ListenAndServe(":5656", nil)
	if err != nil {
		log.Panic(err)
	}
}

2.2.2 客户端代码

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
)

func get() {
	r, err := http.Get("http://localhost:5656/boy")
	if err != nil {
		log.Panic(err)
	}
	defer r.Body.Close()

	io.Copy(os.Stdout, r.Body)

	// 显示响应头
	for k, v := range r.Header {
		fmt.Printf("%v: %v\n", k, v)
	}
}

func post() {
	// 请求服务端要发送的内容(请求主体)
	r := strings.NewReader("hello server\n")

	// 构建post请求
	r2, err := http.Post("http://localhost:5656/boy", "text/plain", r)
	if err != nil {
		log.Panic(err)
	}
	defer r2.Body.Close()

	io.Copy(os.Stdout, r2.Body)

	for k, v := range r2.Header {
		fmt.Printf("%v: %v\n", k, v)
	}
}

func main() {
	post()
}

2.2.3 请求测试

2.3 POST请求进阶版

使用函数:

  • http.NewRequest(method string, url string, body io.Reader) (*http.Request, error)

参数:

  • method string:请求的方法,比如 "GET"、"POST"、"PUT"、"DELETE" 等。
  • url string:请求的 URL,可以是一个完整的 URL 字符串。
  • body io.Reader:请求的主体(body),它是一个 io.Reader 接口,可以是 nil,表示没有请求体。

返回值:

  • *http.Request:一个新建的 HTTP 请求对象。
  • error:如果在创建请求的过程中出现错误,这个错误对象会被返回,否则为 nil

2.3.1 服务端代码编辑

package main

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

func BoyHandler(w http.ResponseWriter, r *http.Request) {
	// 关闭请求主体
	defer r.Body.Close()

	// 显示请求主体
	io.Copy(os.Stdout, r.Body)

	// 显示请求头
	for k, v := range r.Header {
		fmt.Printf("%v: %v\n", k, v)
	}

	// 显示Cookies
	for _, cokkie := range r.Cookies() {
		fmt.Printf("%v: %v\n", cokkie.Name, cokkie.Value)
	}

	fmt.Fprint(w, "Hello Boy\n")
}

func GirlHandler(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	// 显示请求主体
	io.Copy(os.Stdout, r.Body)

	for k, v := range r.Header {
		fmt.Printf("%v: %v\n", k, v)
	}

	fmt.Fprint(w, "Hello Girl\n")
}

func main() {
	http.HandleFunc("/boy", BoyHandler)
	http.HandleFunc("/gir", GirlHandler)

	err := http.ListenAndServe(":5656", nil)
	if err != nil {
		log.Panic(err)
	}
}

2.3.2 客户端代码编辑

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
)

func complexHttpRequest() {
	reader := strings.NewReader("hello server\n")
	req, err := http.NewRequest("POST", "http://localhost:5656/boy", reader)
	if err != nil {
		log.Panic(err)
	} else {
		// 增加自定义请求头
		req.Header.Add("User-Agent", "中国")
		req.Header.Add("MyHeaderKey", "MyHeaderValue")

		// 增加自定义Cokkie
		req.AddCookie(&http.Cookie{
			// 传给服务端的信息
			Name:  "auth",
			Value: "passwd",

			// 下面这3行信息,主要是作为记录,并不传给服务端
			Path:    "/",
			Domain:  "localhost",
			Expires: time.Now().Add(time.Duration(time.Hour)),
		})

		client := &http.Client{
			// Timeout: 100 * time.Microsecond, // 客户端等待服务端响应的超时时间为100毫秒
			Timeout: 10 * time.Second, // 客户端等待服务端响应的超时时间为10秒
		}

		// 提交http请求
		resp, err2 := client.Do(req)
		if err2 != nil {
			log.Panic(err2)
		} else {
			// 成功提交请求且拿到响应后,第一件事就是关闭请求
			defer resp.Body.Close()

			// 显示响应内容
			io.Copy(os.Stdout, resp.Body)
			for k, v := range resp.Header {
				fmt.Printf("%s: %v\n", k, v)
			}
			fmt.Println(resp.Proto)
			fmt.Println(resp.Status)
		}
	}

}

func main() {
	complexHttpRequest()
}

2.3.3 请求测试

2.3.3.1 客户端请求

2.3.3.2 服务端

3. http router

3.1 基本介绍

http routerGo语言 中用于处理 HTTP请求 的组件。它能够识别 URLHTTP方法(如GET、POST),并将请求分发到对应的处理函数。

  • 下载:go get -u github.com/julienschmidt/httprouter
  • Router实现了http.Handler接口。
  • 为各种request method提供了便捷的路由方式。
  • 支持restful请求方式。
  • 支持ServerFiles访问静态文件(如html)。
  • 可以自定义捕获panic的方法。

3.2 编辑服务端代码

package main

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

	"github.com/julienschmidt/httprouter"
)

func handle(method string, w http.ResponseWriter, r *http.Request) {
	fmt.Printf("request method: %v\n", r.Method)
	fmt.Print("request boy: \n")
	io.Copy(os.Stdout, r.Body)
	// defer r.Body.Close()

	// fmt.Fprint(w, "Hello boy")
	// 或者(上下等价)
	w.Write([]byte("Hello boy, your request method is " + method))
}

func get(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	handle("GET", w, r)
}

func post(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	handle("POST", w, r)
}

func main() {
	// 定义一个router
	router := httprouter.New()

	router.GET("/", get)
	router.POST("/", post)

	// 服务启动后监听的端口号
	http.ListenAndServe(":5656", router)
}

3.3 测试

3.3.1 GET方法测试

3.3.2 POST方法测试

3.4 RESTful风格(POST传参)

3.4.1 服务端代码

package main

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

	"github.com/julienschmidt/httprouter"
)

func handle(method string, w http.ResponseWriter, r *http.Request) {
	fmt.Printf("request method: %v\n", r.Method)
	// fmt.Print("request boy: \n")
	io.Copy(os.Stdout, r.Body)
	// defer r.Body.Close()

	// fmt.Fprint(w, "Hello boy")
	// 或者(上下等价)
	w.Write([]byte("Hello boy, your request method is " + method))
}

func get(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	handle("GET", w, r)
}

func post(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	handle("POST", w, r)
}

func main() {
	// 定义一个router
	router := httprouter.New()

	router.GET("/", get)
	router.POST("/", post)

	// /user:是我们请求的路径。
	// :name:占位符,假定为请求时传递的用户名(参数)
	// :type:占位符,假定为请求时传递的类型(参数)
	// *addr:占位符,*表示可以匹配多级路径(参数)
	router.POST("/user/:name/:type/*addr", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		fmt.Printf("name: %v\ntype: %v\naddr: %v", p.ByName("name"), p.ByName("type"), p.ByName("addr"))
	})

	// 服务启动后监听的端口号
	http.ListenAndServe(":5656", router)
}

3.4.2 客户端代码

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
)

func complexHttpRequest() {
	reader := strings.NewReader("hello server\n")
	req, err := http.NewRequest("POST", "http://localhost:5656/user/sanhua/vip/shahnghai/changning/GDAS", reader)
	if err != nil {
		log.Panic(err)
	} else {
		// 增加自定义请求头
		req.Header.Add("User-Agent", "中国")
		req.Header.Add("MyHeaderKey", "MyHeaderValue")

		// 增加自定义Cokkie
		req.AddCookie(&http.Cookie{
			// 传给服务端的信息
			Name:  "auth",
			Value: "passwd",

			// 下面这3行信息,主要是作为记录,并不传给服务端
			Path:    "/",
			Domain:  "localhost",
			Expires: time.Now().Add(time.Duration(time.Hour)),
		})

		client := &http.Client{
			// Timeout: 100 * time.Microsecond, // 客户端等待服务端响应的超时时间为100毫秒
			Timeout: 10 * time.Second, // 客户端等待服务端响应的超时时间为10秒
		}

		// 提交http请求
		resp, err2 := client.Do(req)
		if err2 != nil {
			log.Panic(err2)
		} else {
			// 成功提交请求且拿到响应后,第一件事就是关闭请求
			defer resp.Body.Close()

			// 显示响应内容
			io.Copy(os.Stdout, resp.Body)
			for k, v := range resp.Header {
				fmt.Printf("%s: %v\n", k, v)
			}
			fmt.Println(resp.Proto)
			fmt.Println(resp.Status)
		}
	}

}

func main() {
	complexHttpRequest()
}

3.4.3 请求测试

3.4.3.1 客户端

3.4.3.2 服务端

下图可以看到,服务端把客户端请求时的传参,提取出来了。

3.5 指定静态html文件

3.5.1 准备html文件

这是我在网上随便找的一个静态页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style>
        * {
            margin: 0;
            padding: 0;
        }
        html {
            height: 100%;
        }
        body {
            height: 100%;
        }
        .container {
            height: 100%;
            background-image: linear-gradient(to right, #999999, #330867);
        }
        .login-wrapper {
            background-color: bisque;
            width: 358px;
            height: 588px;
            border-radius: 15px;
            padding: 0 50px;
            position: relative;
            left: 50%;
            top: 50%;
            transform: translate(-50%,-50%);
        }
        .header {
            font-size: 38px;
            font-weight: bold;
            text-align: center;
            line-height: 200px;
        }
        .input-item {
            display: block;
            width: 100%;
            margin-bottom: 20px;
            border: 0;
            padding: 10px;
            border-bottom: 1px solid rgb(128,125,125);
            font-size: 15px;
            outline: none;
        }
        .input-item::placeholder {
            text-transform: uppercase;
        }
        .btn {
            text-align: center;
            padding: 10px;
            width: 100%;
            margin-top: 40px;
            background-image: linear-gradient(to right,#a6c1ee, #fbc2eb);
            color: #fff;
        }
        .msg {
            text-align: center;
            line-height: 88px;
        }
        a {
            text-decoration-line: none;
            color: #abc1ee;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="login-wrapper">
            <div class="header">Login</div>
            <div class="form-wrapper">
                <input type="text" name="username" placeholder="username" class="input-item">
                <input type="password" name="password" placeholder="password" class="input-item">
                <div class="btn">Login</div>
            </div>
            <div class="msg">
                Don't have account?
                <a href="#">Sign up</a>
            </div>
        </div>
    </div>
</body>
</html>

3.5.2 服务端代码

package main

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

	"github.com/julienschmidt/httprouter"
)

func handle(method string, w http.ResponseWriter, r *http.Request) {
	fmt.Printf("request method: %v\n", r.Method)
	// fmt.Print("request boy: \n")
	io.Copy(os.Stdout, r.Body)
	// defer r.Body.Close()

	// fmt.Fprint(w, "Hello boy")
	// 或者(上下等价)
	w.Write([]byte("Hello boy, your request method is " + method))
}

func get(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	handle("GET", w, r)
}

func post(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	handle("POST", w, r)
}

func main() {
	// 定义一个router
	router := httprouter.New()

	router.GET("/", get)
	router.POST("/", post)

	// 请求/file路径,服务端就会去static目录下读取a.html文件中的内容
	router.ServeFiles("/file/*filepath", http.Dir("D:/个人/GO开发/20240624/static"))

	// 服务启动后监听的端口号
	http.ListenAndServe(":5656", router)
}

3.5.3 请求测试

3.6 错误处理

在实际工作中,可能会有很多路由规则,在任何一处都有可能会报错,所以需要定义一个统一的告警处理。

3.6.1 服务端代码

package main

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

	"github.com/julienschmidt/httprouter"
)

func handle(method string, w http.ResponseWriter, r *http.Request) {
	fmt.Printf("request method: %v\n", r.Method)
	// fmt.Print("request boy: \n")
	io.Copy(os.Stdout, r.Body)
	// defer r.Body.Close()

	// fmt.Fprint(w, "Hello boy")
	// 或者(上下等价)
	w.Write([]byte("Hello boy, your request method is " + method))
}

func get(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	handle("GET", w, r)

	// 手动定义一个数组超界的异常,触发panic
	var arr []int
	_ = arr[1]
}

func post(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	handle("POST", w, r)
}

func main() {
	// 定义一个router
	router := httprouter.New()

	// 错误处理
	router.PanicHandler = func(w http.ResponseWriter, r *http.Request, i interface{}) {
		fmt.Fprintf(w, "server panic %v", i)
	}

	router.GET("/", get)
	router.POST("/", post)

	// 服务启动后监听的端口号
	http.ListenAndServe(":5656", router)
}

3.6.2 请求测试

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【SpringBoot】使用IDEA创建SpringBoot项目

1、使用SpringBoot脚手架创建 我们使用SpringBoot的脚手架Spring Initializr创建&#xff0c;如图所示&#xff1a; 2、选择SpringBoot版本 最开始做项目时候&#xff0c;组长说创建一个 springboot 2.5.4 的项目&#xff0c;mysql使用 5.6.X &#xff0c;maven使用是3.6.X…

使用Oracle通过gateway连接MSSQL

环境概述 某医院的his系统Oracle数据库要和体检系统进行数据通讯&#xff0c;需要从Oracle能查到sqlserver的数据。本次通过Oracle gateway来解决此问题。 HIS服务器&#xff1a;windows server 2016数据库oracle11.2.0.4&#xff0c;假设IP是192.168.100.9 体检服务器&…

leetcode 之 二分查找(java)(2)

文章目录 74、搜索二维矩阵33、搜素旋转排序数组 74、搜索二维矩阵 题目描述&#xff1a; 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff…

Linux中的信号

目录 生活中的信号 Linux中的信号 前台进程与后台进程 信号的产生 核心转储 core dump ​编辑信号的其他相关概念 信号处理的三种方式 信号在内核中的表示示意图 sigset_t 类型 信号集操作函数 sigprocmask sigpending 综合练习 用户态与内核态 信号的捕捉过程 …

基于STM32F4实现步进电机闭环控制实现(无PID)

文章目录 概要整体流程代码实现TIM8 PWM控制TIM5 编码器计数TIM13 闭环控制 效果展示小结 概要 因客户外部负载较大&#xff0c;步进电机出现丢步现象&#xff0c;所以需要进行闭环控制&#xff0c;保证最后走到相应的位置即可&#xff0c;所以我采用的是电机停止后与编码器值…

第4章:颜色和背景 --[CSS零基础入门]

在 CSS 中&#xff0c;颜色和背景属性是用于美化网页元素的重要工具。你可以通过多种方式定义颜色&#xff0c;并且可以设置元素的背景颜色、图像、渐变等。以下是关于如何在 CSS 中使用颜色和背景的一些关键点和示例。 1.颜色表示法 当然&#xff01;以下是使用不同颜色表示…

二叉树概述

目录 一、二叉树的基本结构 二、二叉树的遍历 1.前序 2.中序 3.后序 4.层序遍历 三.计算二叉树的相关参数 1.计算节点总个数 2.计算叶子节点的个数 3.计算树的高度 4.计算第k层的子树个数 5.查找树中val为x的节点 四.刷题 1.单值二叉树 2.检查两棵树是否相同 3.一…

04 创建一个属于爬虫的主虚拟环境

文章目录 回顾conda常用指令创建一个爬虫虚拟主环境Win R 调出终端查看当前conda的虚拟环境创建 spider_base 的虚拟环境安装完成查看环境是否存在 为 pycharm 配置创建的爬虫主虚拟环境选一个盘符来存储之后学习所写的爬虫文件用 pycharm 打开创建的文件夹pycharm 配置解释器…

weblogic开启https

JSK证书生成 生成密钥库和证书 使用Java的keytool命令来生成一个Java密钥库&#xff08;Keystore&#xff09;和证书。keytool是Java开发工具包&#xff08;JDK&#xff09;中用于管理密钥库和证书的命令行工具。 #创建证书存放目录 [weblogicosb1 jksHL]$ mkdir -p /home/w…

学习记录,正则表达式, 隐式转换

正则表达式 \\&#xff1a;表示正则表达式 W: 表示一个非字&#xff08;不是一个字&#xff0c;例如&#xff1a;空格&#xff0c;逗号&#xff0c;句号&#xff09; W: 多个非字 基本组成部分 1.字符字面量&#xff1a; 普通字符&#xff1a;在正则表达式中&#xff0c;大…

防火墙有什么作用

防火墙的作用&#xff1a;1. 提供网络安全防护&#xff1b;2. 实施访问控制和流量过滤&#xff1b;3. 检测和阻止恶意攻击&#xff1b;4. 保护内部网络免受未经授权的访问&#xff1b;5. 监控网络流量和安全事件&#xff1b;6. 支持虚拟专用网络&#xff08;VPN&#xff09;。防…

linux中启动oracle19c操作过程及详解

1.登录Oracle用户 su - oracle2.启动监听程序 监听器&#xff08;Listener&#xff09;是Oracle数据库与客户端通信的桥梁。使用以下命令启动监听器&#xff1a; lsnrctl start如图情况监控程序启动成功。 3.启动数据库实例 使用 sqlplus 工具以 SYSDBA 权限连接到数据库&a…

ainiworth 在分布式目标的方程中 与正常互易性可以形成的方程不同 多引入了协方差元素未知 但可解,因为此时只有一个串扰参数且已经解出来了

这个散射互易性&#xff0c;在不考虑AB时 方程应该只剩两个即 HVHV VHVH 和VHHV相位(虚部) 0 但是这一组方程却可以解4个参数未知数。C元素是观测的已知。 β表示真实协方差矩阵&#xff0c;Σ是恢复的协方差&#xff08;也可以认为是真实协方差元素&#xff09; 1、首先把方…

10a大电流稳压芯片_24v转3.3v稳压芯片,高效率DC-DC变换器10A输出电流芯片-AH1514

### AH1514——高性能的大电流稳压芯片 在现代电子电路设计中&#xff0c;对于能够满足大电流、高效率转换以及稳定电压输出的芯片需求日益增长。AH1514芯片作为一款出色的DC-DC变换器&#xff0c;以其独特的性能特点&#xff0c;在众多应用场景中展现出了卓越的优势. ### 一…

【网络篇】HTTP知识

键入网址到网页显示&#xff0c;期间发生了什么&#xff1f; 浏览器第一步是解析URL&#xff0c;这样就得到了服务器名称和文件的路径名&#xff0c;然后根据这些信息生成http请求&#xff0c;通过DNS查询得到我们要请求的服务器地址&#xff0c;然后添加TCP头、IP头以及MAC头&…

pdf转word/markdown等格式——MinerU的部署:2024最新的智能数据提取工具

一、简介 MinerU是开源、高质量的数据提取工具&#xff0c;支持多源数据、深度挖掘、自定义规则、快速提取等。含数据采集、处理、存储模块及用户界面&#xff0c;适用于学术、商业、金融、法律等多领域&#xff0c;提高数据获取效率。一站式、开源、高质量的数据提取工具&…

github使用SSH进行克隆仓库

SSH 密钥拉取git 查询密钥是否存在 s -al ~/.ssh这个文件夹下 known_hosts 就是存在的密钥文件 创建密钥文件 ssh-keygen -t rsa -b 4096 -C "testtt.com"-t rsa 是 rsa 算法加密 -b 是指定密钥的长度&#xff08;以位为单位&#xff09;。 -C 是用于给密钥添加注…

【MARL】MAT论文阅读笔记

文章目录 前言一、如何产生这个想法(TRPO -> ) PPO -> MAPPO -> HAPPO -> MAT 二、多智能体优势值分解定理三、transformer 在MAT的应用四、伪代码简述五、实验效果 前言 正好有节课让我们调研最新的自己的方向的新论文&#xff0c;找到一篇自己觉得比较可行&…

代码随想录32 动态规划理论基础,509. 斐波那契数,70. 爬楼梯,746. 使用最小花费爬楼梯。

1.动态规划理论基础 动态规划刷题大纲 什么是动态规划 动态规划&#xff0c;英文&#xff1a;Dynamic Programming&#xff0c;简称DP&#xff0c;如果某一问题有很多重叠子问题&#xff0c;使用动态规划是最有效的。 所以动态规划中每一个状态一定是由上一个状态推导出来的…

基于SpringBoot的社区医院管理系统(代码+论文)

&#x1f389;博主介绍&#xff1a;Java领域优质创作者&#xff0c;阿里云博客专家&#xff0c;计算机毕设实战导师。专注Java项目实战、毕设定制/协助 &#x1f4e2;主要服务内容&#xff1a;选题定题、开题报告、任务书、程序开发、项目定制、论文辅导 &#x1f496;精彩专栏…