背景

本文有一个疑问一直没有解决,诚心请教,有知道的大佬可以留言一下,不胜感激,点击这里跳转

最近在写一个图床小工具,
整合
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 partHeader字段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)
}

疑问

在线蹲一个大佬,下面的问题依然没有解决,如果您知道的话,诚求您的留言,不胜感激

这是正常的请求,注意划线部分

下面是通过协议发的请求

这两处划线的地方不一样,没找到在哪生成的,

分类: go

浙公网安备33011302000604

辽ICP备20003309号