背景
本文有一个疑问一直没有解决,诚心请教,有知道的大佬可以留言一下,不胜感激,点击这里跳转
最近在写一个图床小工具,
整合
1. 读写剪贴板中的图像
2. 读取到内存添加水印,(可供选择的文字水印和图像水印)
3. 将图像通过协议发送到图床,(目前是对接的自己的图床)
遇到的难点
1. 从剪贴板中读取图像
2. 保存剪贴板中的图像
3. multipart/form-data
发送
multipart/form-data``code
以及抓包代理配置
代理
这样配置代理,让代码请求走抓包软件,方便分析请求
// http https都可以抓到
proxy_raw := "127.0.0.1:8889"
proxy_str := fmt.Sprintf("http://%s", proxy_raw)
fmt.Println(proxy_str)
proxy, err := url.Parse(proxy_str)
if err != nil {
fmt.Println(err)
}
client := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxy)}}
multipart/form-data code
func PostImg(filename string) {
filePath := "./out/new_" + filename
client := &http.Client{}
bodyBuf := &bytes.Buffer{}
bodyWriter := multipart.NewWriter(bodyBuf)
//添加表单属性
// 参数1 (File参数)添加文件
f, err := os.Open(filePath)
if err != nil {
return
}
fw1, err := bodyWriter.CreateFormFile("file", filepath.Base(filePath))
//把文件流写入到缓冲区里去
_, err1 := io.Copy(fw1, f)
if err1 != nil {
return
}
err = bodyWriter.Close()
if err != nil {
logrus.Errorf("bodyWriter close error: %v", err.Error())
return
}
//http://logrus.Info("请求报文:", requst.JSONString())
//发送post请求
uri := "https://xxxxxxxxxxx"
req, err := http.NewRequest("POST", uri, bodyBuf)
if err != nil {
return
}
// 设置cookie
req.AddCookie(&http.Cookie{Name: "user", Value: "superman"})
req.AddCookie(&http.Cookie{Name: "token", Value: "xxxxxxxxxxxxxxxxxxxxx"})
//添加头文件
// req.Header.Add("Content-Type", "multipart/form-data")用这句大概率报错,他添加了一个字段,会导致识别不了文件
req.Header.Add("User-Agent", "Mozi")
req.Header.Add("Content-Type", bodyWriter.FormDataContentType())
req.Header.Add("Accept-Language", "zh-CN,zh;q=0.9,en")
// req.Header.Add("cookie", "user=superman; token=xxxxxxxxx")
resp, err := client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
fmt.Println(string(body))
// fmt.Println(ioutil.ReadFile(filePath))
return
}
使用上面代码请求是这样的
直接在浏览器请求是这样的,
这时候,我们发现Content-Type: image/png
这个字段不一样
无论待上传的文件是什么类型,
CreateFormFile
均将Content-Type
置为application/octet-stream
这一默认值。如果我们要自定义file part
中Header
字段Content-Type
的值,我们就不能直接使用CreateFormFile
,
要定制这个的话也有办法,可以使用下面的代码
bodyWriter := multipart.NewWriter(bodyBuf)
//添加表单属性
// 参数1 (File参数)
//添加文件
f, err := os.Open(filePath)
if err != nil {
return
}
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition",
fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
escapeQuotes("file"), escapeQuotes("new_"+filename)))
h.Set("Content-Type", "image/png")
fw1, _ := bodyWriter.CreatePart(h)
if err != nil {
return
}
_, err1 := io.Copy(fw1, f)
// 依赖
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
func escapeQuotes(s string) string {
return quoteEscaper.Replace(s)
}
这样的话,就达到目的了
补充
要达到这样的效果,需要下面的代码
// 参数2 fileType (普通参数)
fileWriter2, err := bodyWriter.CreateFormField("Content-Disposition")
if err != nil {
return
}
_, errs2 := fileWriter2.Write([]byte("form-data; name=\"file\"; filename=\"" + filepath.Base(filename) + "\""))
if errs2 != nil {
return
}
fileWriter3, _ := bodyWriter.CreateFormField("Content-Type")
_, errs3 := fileWriter3.Write([]byte("image/png"))
if errs3 != nil {
return
}
// 完整代码
func PostImg(filename string) {
filePath := "./out/new_" + filename
client := &http.Client{}
bodyBuf := &bytes.Buffer{}
bodyWriter := multipart.NewWriter(bodyBuf)
//添加表单属性
// 参数1 (File参数)添加文件
f, err := os.Open(filePath)
if err != nil {
return
}
fw1, err := bodyWriter.CreateFormFile("file", filepath.Base(filePath))
//把文件流写入到缓冲区里去
_, err1 := io.Copy(fw1, f)
if err1 != nil {
return
}
// 参数2 fileType (普通参数)
fileWriter2, err := bodyWriter.CreateFormField("Content-Disposition")
if err != nil {
return
}
_, errs2 := fileWriter2.Write([]byte("form-data; name=\"file\"; filename=\"" + filepath.Base(filename) + "\""))
if errs2 != nil {
return
}
fileWriter3, _ := bodyWriter.CreateFormField("Content-Type")
_, errs3 := fileWriter3.Write([]byte("image/png"))
if errs3 != nil {
return
}
// 接剩下的逻辑
err = bodyWriter.Close()
if err != nil {
logrus.Errorf("bodyWriter close error: %v", err.Error())
return
}
//http://logrus.Info("请求报文:", requst.JSONString())
//发送post请求
uri := "https://xxxxxxxxxxx"
req, err := http.NewRequest("POST", uri, bodyBuf)
if err != nil {
return
}
// 设置cookie
req.AddCookie(&http.Cookie{Name: "user", Value: "superman"})
req.AddCookie(&http.Cookie{Name: "token", Value: "xxxxxxxxxxxxxxxxxxxxx"})
//添加头文件
// req.Header.Add("Content-Type", "multipart/form-data")用这句大概率报错,他添加了一个字段,会导致识别不了文件
req.Header.Add("User-Agent", "Mozi")
req.Header.Add("Content-Type", bodyWriter.FormDataContentType())
req.Header.Add("Accept-Language", "zh-CN,zh;q=0.9,en")
// req.Header.Add("cookie", "user=superman; token=xxxxxxxxx")
resp, err := client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
fmt.Println(string(body))
// fmt.Println(ioutil.ReadFile(filePath))
return
}
// 依赖
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
func escapeQuotes(s string) string {
return quoteEscaper.Replace(s)
}
疑问
在线蹲一个大佬,下面的问题依然没有解决,如果您知道的话,诚求您的留言,不胜感激
这是正常的请求,注意划线部分
下面是通过协议发的请求
这两处划线的地方不一样,没找到在哪生成的,