最新代码请关注:
简介
一款基于 net/http 二次封装的客户端请求库,支持返回更丰富的响应结构和内容;
包含多种方法: 目前支持[HEAD/GET/POST]
使用
示例代码不具有时效性,最新代码请查看GitHub: https://github.com/birdy02-com/request
go get github.com/birdy02-com/request
优点
POST一键获取请求体;对比:net/http无法直接获取请求body
根据响应内容多层判断获取编码格式
默认返回目标站点的基本信息:Title、Description、Keyword、Favicon路径
增加请求响应时长
丰富默认请求头,使请求看起来像真人一样
主要功能
HEAD 请求方法
GET 请求方法
POST 请求方法
Result 格式化响应内容
IsIpv4 检查一个IP字符串是否为IPv4地址
GetRandomIP 生成一个随机的IP地址
IsPrivateIP 判断IP是否为私有地址
ParseUrl 格式化URL
GetHeader 获取默认请求头
GetSiteBasic 提取网站的基本信息
GetFaviconPath 获取favicon.ico的路径
响应返回格式
// Response 请求的返回结构
type Response struct {
Basic struct {
Title string // 网页标题
Description string // 网页描述
Keywords string // 网页关键字
Favicon string // 网页图标路径
}
Redirect string // 重定向地址
Url string // 响应url
StatusCode int // 响应状态码
Status string // 响应状态 200 ok
Timer float64 // 响应时长
Headers http.Header // 响应头
Body string // 响应体(str)
Charset string // 检测到的编码方式
Content []byte // 响应体(byte)
Json map[string]interface{} // 响应的Json内容
Length int // 响应字节
Proto string // 响应协议
ProtoMajor int // 响应版本号-主
ProtoMinor int // 响应版本号-子
Request struct {
URL string // 请求url
Method string //请求方法
Headers http.Header //请求头
Body []byte // 请求体
}
}
其实封装自己的请求结构也还是有好处的,可以适配自己的使用习惯,直接默认就自定义好了请求头来模拟真实用户请求,but 实现的代码也是用了一百多行😭
请求使用演示
请求参数结构
// GetRequest 请求的参数结构
type GetRequest struct {
Timeout int // 超时时长
AllowRedirects bool // 是否跟随跳转
Verify bool // ssl验证证书忽略
Headers map[string]string // 请求头
Params map[string]string // 请求参数
Stream bool
Engine bool
Data string // post请求体
DataJson map[string]string // json格式传入post请求体,会格式化成 xx=xx
Json map[string]any // post请求
File map[string][]string // 上传的文件,格式参考 file:['文件名','内容','文件类型']
}
简单请求
if r, e := request.GET(uri); e == nil {
fmt.Println(res.Basic.Title)
}
自定义参数请求
res, err := request.GET(uri, request.GetRequest{Timeout: 16})
if err != nil {
return nil, err
}
POST请求参数
// 参数类型参考‘1. 请求参数示例’
res, err = request.POST(uri, request.GetRequest{Headers: Header, Data: r.Data, DataJson: r.DataJson, Json: r.Json, File: r.File})
if err == nil{
fmt.Println(res.Basic.Title)
}
其他
初始化请求参数
// GetRequestGetArg 获取请求参数
func GetRequestGetArg(baseurl string, args GetRequest) (*GetRequest, http.Client, string) {
baseurl = strings.TrimSpace(baseurl)
reqArg := GetRequestInit() // 获取请求配置
// 处理传入参数
// 超时时长
if args.Timeout != 0 && args.Timeout != reqArg.Timeout {
reqArg.Timeout = args.Timeout
}
// 是否跟随跳转
if args.AllowRedirects != reqArg.AllowRedirects {
reqArg.AllowRedirects = args.AllowRedirects
}
// 是否忽略证书
if args.Verify != reqArg.Verify {
reqArg.Verify = args.Verify
}
// 是否添加Headers
if args.Headers != nil {
reqArg.Headers = args.Headers
}
// 是否有Params参数
if args.Params != nil {
reqArg.Params = args.Params
}
// 是否流式传输
if args.Stream != reqArg.Stream {
reqArg.Stream = args.Stream
}
//proxyURL, err := url.Parse("http://127.0.0.1:8080")
//if err != nil { }
// 请求参数设置
// 创建一个自定义的Transport,并禁用证书验证
transport := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
//Proxy: http.ProxyURL(proxyURL),
}
// 设置Params
params := url.Values{}
for k, v := range reqArg.Params {
params.Set(k, v)
}
uParse, _ := url.Parse(baseurl)
Params := params.Encode()
tmpParams := strings.TrimPrefix(strings.TrimPrefix(uParse.RequestURI(), uParse.Path), "?")
if tmpParams != "" {
if Params != "" {
Params = fmt.Sprintf("%s&%s", Params, tmpParams)
} else {
Params = tmpParams
}
}
fullURL := fmt.Sprintf("%s://%s%s?%s", uParse.Scheme, uParse.Host, uParse.Path, Params)
suffixToRemove := "?"
if strings.HasSuffix(fullURL, suffixToRemove) {
fullURL = strings.TrimSuffix(fullURL, suffixToRemove)
}
var client http.Client
// 重定向策略
if !reqArg.AllowRedirects {
client = http.Client{
Timeout: time.Duration(reqArg.Timeout) * time.Second, // 转换为time.Duration
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
Transport: transport,
}
} else {
client = http.Client{ // 创建http.Client并配置Timeout
Timeout: time.Duration(reqArg.Timeout) * time.Second, // 转换为time.Duration
Transport: transport,
}
}
return reqArg, client, fullURL
}
在安全工作中,为了请求方便,默认禁止了ssl证书可信度报错
默认请求头
// GetHeader 获取请求头
func GetHeader(args *GetHeaderArgs) http.Header {
// 预设的User-Agent列表
userAgents := []string{
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 OPR/112.0.0.0",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.289 Safari/537.36 ",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.202.400 QQBrowser/11.9.5355.400",
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
}
randIp := GetRandomIP()
// 初始化HTTP头
header := http.Header{}
rand.Seed(time.Now().UnixNano())
if args.Engine {
header.Set("User-Agent", "Baiduspider+(+https://www.baidu.com/search/spider.htm);google|baiduspider|baidu|spider|sogou|bing|yahoo|soso|sosospider|360spider|youdao|jikeSpider;)")
} else {
header.Set("User-Agent", userAgents[rand.Intn(len(userAgents))])
}
header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
header.Set("Accept-Language", "zh-CN,zh;q=0.9")
header.Set("Cache-Control", "no-cache")
header.Set("Pragma", "no-cache")
header.Set("CLIENT-IP", randIp)
header.Set("X-Remote-Ip", randIp)
header.Set("X-Remote-Addr", randIp)
header.Set("X-Originating-Ip", randIp)
header.Set("X-FORWARDED-FOR", randIp)
header.Set("Connection", "keep-alive")
header.Set("Upgrade-Insecure-Requests", "1")
// 根据参数更新HTTP头
if args.Switch == "Bing" {
header.Set("Host", "cn.bing.com")
header.Set("Referer", "https://www.bing.com")
}
if args.api != "" {
if parse, err := url.Parse(args.api); err == nil {
header.Set("Host", parse.Host) // 提取Host和Referer
}
header.Set("Referer", args.api)
}
// 传入的header参数
for k, v := range args.header {
header.Set(k, v)
}
return header
}
默认配置好了请求头,支持每次自定义请求头【替换默认】,使每次请求看起来都像真人
持续更新中...
评论