Fetch the repository succeeded.
package colite
import (
"bytes"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
"sync/atomic"
)
// Request 请求类
type Request struct {
// ID 请求标识符
ID uint32
// URL 请求网址
URL *url.URL
// Method 请求方法
Method string
// Headers 请求头
Headers *http.Header
// Body 请求主体(POST/PUT)
Body io.Reader
// Ctx 上下文环境
Ctx *Context
// ResponseCharacterEncoding 响应体字符编码(为空自动检测)
ResponseCharacterEncoding string
// ProxyURL 代理地址
ProxyURL string
collector *Collector
baseURL *url.URL
abort bool // 是否终止请求
}
// New 在原有请求基础上创建新请求实例(共享Collector、Context)
func (r *Request) New(URL, method string, body io.Reader) (*Request, error) {
u, err := url.Parse(URL)
if err != nil {
return nil, err
}
return &Request{
ID: atomic.AddUint32(&r.collector.requestCount, 1),
URL: u,
Method: method,
Headers: &http.Header{},
Body: body,
Ctx: r.Ctx, // 共享
collector: r.collector, // 共享
}, nil
}
// Abort 取消请求
func (r *Request) Abort() {
r.abort = true
}
// AbsoluteURL 解析为绝对网址(不包含Fragment部分)
func (r *Request) AbsoluteURL(u string) string {
if strings.HasPrefix(u, "#") {
return ""
}
var base *url.URL
if r.baseURL != nil {
base = r.baseURL
} else {
base = r.URL
}
absURL, err := base.Parse(u)
if err != nil {
return ""
}
absURL.Fragment = ""
if absURL.Scheme == "//" {
absURL.Scheme = r.URL.Scheme
}
return absURL.String()
}
// Visit 发送GET请求(保留上下文环境)
func (r *Request) Visit(URL string) error {
return r.collector.scrape(r.AbsoluteURL(URL), "GET", nil, r.Ctx, nil, true)
}
// HasVisited 检查指定网址是否已经访问
func (r *Request) HasVisited(URL string) (bool, error) {
return r.collector.HasVisited(URL)
}
// Post 发送POST请求(包含提交数据,保留上下文环境)
func (r *Request) Post(URL string, requestData map[string]string) error {
return r.collector.scrape(r.AbsoluteURL(URL), "POST", createFormReader(requestData), r.Ctx, nil, true)
}
// PostRaw 发送POST请求(包含实体数据,保留上下文环境)
func (r *Request) PostRaw(URL string, requestData []byte) error {
return r.collector.scrape(r.AbsoluteURL(URL), "POST", bytes.NewReader(requestData), r.Ctx, nil, true)
}
// PostMultipart 发送多部分实体POST请求(包含多部分实体数据,保留上下文环境)
func (r *Request) PostMultipart(URL string, requestData map[string][]byte) error {
boundary := randomBoundary()
hdr := http.Header{}
hdr.Set("Content-Type", "multipart/form-data; boundary="+boundary)
hdr.Set("User-Agent", r.collector.UserAgent)
return r.collector.scrape(r.AbsoluteURL(URL), "POST", createMultipartReader(boundary, requestData), r.Ctx, hdr, true)
}
// Do 执行请求
func (r *Request) Do() error {
return r.collector.scrape(r.URL.String(), r.Method, r.Body, r.Ctx, *r.Headers, !r.collector.AllowURLRevisit)
}
// Retry 重新提交请求
func (r *Request) Retry() error {
r.Headers.Del("Cookie")
return r.collector.scrape(r.URL.String(), r.Method, r.Body, r.Ctx, *r.Headers, false)
}
// Marshal 将请求序列化为JSON
func (r *Request) Marshal() ([]byte, error) {
// 转存上下文环境
ctx := make(map[string]interface{})
if r.Ctx != nil {
r.Ctx.ForEach(func(k string, v interface{}) interface{} {
ctx[k] = v
return nil
})
}
// 转存请求主体
var err error
var body []byte
if r.Body != nil {
body, err = ioutil.ReadAll(r.Body)
if err != nil {
return nil, err
}
}
// 创建序列化请求
sr := &serializableRequest{
ID: r.ID,
URL: r.URL.String(),
Method: r.Method,
Body: body,
Ctx: ctx,
}
if r.Headers != nil {
sr.Headers = *r.Headers
}
return json.Marshal(sr)
}
// serializableRequest 序列化请求类
type serializableRequest struct {
ID uint32
URL string
Method string
Headers http.Header
Body []byte
Ctx map[string]interface{}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。