从URL发送文件到Cloudflare Images失败

huangapple go评论65阅读模式
英文:

Send a File from url to cloudflare images fails

问题

我正在使用Google App Engine,这意味着只能通过云存储来写入文件。当API被调用时,我可以获取文件并将其存储在Google云存储中,没有问题。该函数只返回保存文件的URL。
我想获取该图像的URL,然后将其发送到Cloudflare图像,因为他们允许您创建变体。

上面是表示Cloudflare响应的结构体。下面是将Google云存储URL直接"下载"并发送到Cloudflare的函数。

type ImageResult struct {
	Result struct {
		ID                string    `json:"id"`
		Filename          string    `json:"filename"`
		Uploaded          time.Time `json:"uploaded"`
		RequireSignedURLs bool      `json:"requireSignedURLs"`
		Variants          []string  `json:"variants"`
	} `json:"result"`
	ResultInfo interface{}   `json:"result_info"`
	Success    bool          `json:"success"`
	Errors     []interface{} `json:"errors"`
	Messages   []interface{} `json:"messages"`
}

func CloudFlareURL(url, filename string) (*ImageResult, error) {
	cloudFlareUrl := "https://api.cloudflare.com/client/v4/accounts/" + konsts.CloudFlareAcc + "/images/v1"
	cloudFlareAuth := "Bearer " + konsts.CloudFlareApi
	r, err := http.Get(url)
	if err != nil {
		return nil, errors.Wrap(err, "Couldn't get the file")
	}
	if r.StatusCode != 200 {
		return nil, errors.New("Couldn't get the file")
	}
	defer r.Body.Close()
	buff := make([]byte, 4096)
	_, err = r.Body.Read(buff)

	req, err := http.NewRequest("POST", cloudFlareUrl, bytes.NewReader(buff))
	if err != nil {
		return nil, errors.Wrap(err, "Couldn't create the request")
	}
	req.Header.Set("Content-Type", "multipart/form-data")
	req.Header.Set("Authorization", cloudFlareAuth)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, errors.Wrap(err, "Couldn't send the request")
	}

	var result ImageResult
	bodi := &bytes.Buffer{}
	_, err = bodi.ReadFrom(resp.Body)
	if err != nil {
		return nil, errors.Wrap(err, "Couldn't read the response body")
	}
	resp.Body.Close()
	err = json.Unmarshal(bodi.Bytes(), &result)
	if err != nil {
		return nil, errors.Wrap(err, "Couldn't unmarshal the response body")
	}
	return &result, nil
}

这是错误消息:
invalid character 'E' looking for beginning of value
Couldn't unmarshal the response body

现在在我的笔记本电脑上,如果我运行API服务器,一旦文件被发送,我可以将其保存在磁盘上,打开它并无问题地发送到Cloudflare。以下是该代码:

func CloudFlareFile(params map[string]string, paramName, path string) (*ImageResult, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	part, err := writer.CreateFormFile(paramName, filepath.Base(path))
	if err != nil {
		return nil, err
	}
	_, err = io.Copy(part, file)

	for key, val := range params {
		_ = writer.WriteField(key, val)
	}
	err = writer.Close()
	if err != nil {
		return nil, err
	}
	cloudFlareUrl := "https://api.cloudflare.com/client/v4/accounts/" + konsts.CloudFlareAcc + "/images/v1"
	cloudFlareAuth := "Bearer " + konsts.CloudFlareApi
	req, err := http.NewRequest("POST", cloudFlareUrl, body)
	req.Header.Set("Content-Type", writer.FormDataContentType())
	req.Header.Set("Authorization", cloudFlareAuth)
	var result ImageResult
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, errors.Wrap(err, "Couldn't send the request")
	} else {
		body := &bytes.Buffer{}
		_, err := body.ReadFrom(resp.Body)
		if err != nil {
			return nil, errors.Wrap(err, "Couldn't read the response body")
		}
		resp.Body.Close()
		err = json.Unmarshal(body.Bytes(), &result)
		if err != nil {
			return nil, errors.Wrap(err, "Couldn't unmarshal the response body")
		}
	}
	return &result, nil
}

我尝试了各种变化,但始终失败。例如:

req, err := http.NewRequest("POST", cloudFlareUrl, r.body)
	if err != nil {
		return nil, errors.Wrap(err, "Couldn't create the request")
	}
	req.Header.Set("Content-Type", "multipart/form-data")
	req.Header.Set("Authorization", cloudFlareAuth)

希望对你有帮助!

英文:

I'm using Google App engine so that means writing files is only allowed through cloud storage. When the API is hit, I can grab the file and store it in google cloud storage without issues. That function just returns the URL where it is saved.
I want to get that image URL and then send it to Cloudflare images because they let you create variants.

type ImageResult struct {
Result struct {
ID                string    `json:"id"`
Filename          string    `json:"filename"`
Uploaded          time.Time `json:"uploaded"`
RequireSignedURLs bool      `json:"requireSignedURLs"`
Variants          []string  `json:"variants"`
} `json:"result"`
ResultInfo interface{}   `json:"result_info"`
Success    bool          `json:"success"`
Errors     []interface{} `json:"errors"`
Messages   []interface{} `json:"messages"`
}

The above is the struct that represents the Cloudflare response. Below is the function to take the google cloud storage URL directly and "download" it before sending it off to Cloudflare.

func CloudFlareURL(url, filename string) (*ImageResult, error) {
cloudFlareUrl := "https://api.cloudflare.com/client/v4/accounts/" + konsts.CloudFlareAcc + "/images/v1"
cloudFlareAuth := "Bearer " + konsts.CloudFlareApi
r, err := http.Get(url)
if err != nil {
return nil, errors.Wrap(err, "Couldn't get the file")
}
if r.StatusCode != 200 {
return nil, errors.New("Couldn't get the file")
}
defer r.Body.Close()
buff := make([]byte, 4096)
_, err = r.Body.Read(buff)
req, err := http.NewRequest("POST", cloudFlareUrl, bytes.NewReader(buff))
if err != nil {
return nil, errors.Wrap(err, "Couldn't create the request")
}
req.Header.Set("Content-Type", "multipart/form-data")
req.Header.Set("Authorization", cloudFlareAuth)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, errors.Wrap(err, "Couldn't send the request")
}
var result ImageResult
bodi := &bytes.Buffer{}
_, err = bodi.ReadFrom(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "Couldn't read the response body")
}
resp.Body.Close()
err = json.Unmarshal(bodi.Bytes(), &result)
if err != nil {
return nil, errors.Wrap(err, "Couldn't unmarshal the response body")
}
return &result, nil
}

This is the error message;
invalid character 'E' looking for beginning of value
Couldn't unmarshal the response body

Now on my laptop if I'm running the api server once a file has been sent I can save it on disk, open it and send to cloudflare with no problems. Here's the code for that

func CloudFlareFile(params map[string]string, paramName, path string) (*ImageResult, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile(paramName, filepath.Base(path))
if err != nil {
return nil, err
}
_, err = io.Copy(part, file)
for key, val := range params {
_ = writer.WriteField(key, val)
}
err = writer.Close()
if err != nil {
return nil, err
}
cloudFlareUrl := "https://api.cloudflare.com/client/v4/accounts/" + konsts.CloudFlareAcc + "/images/v1"
cloudFlareAuth := "Bearer " + konsts.CloudFlareApi
req, err := http.NewRequest("POST", cloudFlareUrl, body)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Authorization", cloudFlareAuth)
var result ImageResult
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, errors.Wrap(err, "Couldn't send the request")
} else {
body := &bytes.Buffer{}
_, err := body.ReadFrom(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "Couldn't read the response body")
}
resp.Body.Close()
err = json.Unmarshal(body.Bytes(), &result)
if err != nil {
return nil, errors.Wrap(err, "Couldn't unmarshal the response body")
}
}
return &result, nil
}

I've tried variations and it always fails. For example;

req, err := http.NewRequest("POST", cloudFlareUrl, r.body)
if err != nil {
return nil, errors.Wrap(err, "Couldn't create the request")
}
req.Header.Set("Content-Type", "multipart/form-data")
req.Header.Set("Authorization", cloudFlareAuth)

答案1

得分: 1

好的,以下是翻译好的代码部分:

r, err := http.Get(url)
if err != nil {
    return nil, errors.Wrap(err, "无法获取文件")
}
if r.StatusCode != 200 {
    return nil, errors.New("无法获取文件")
}
defer r.Body.Close()
b := &bytes.Buffer{}
a := make([]byte, 4096)
wr := multipart.NewWriter(b)
part, err := wr.CreateFormFile("file", filename)
if err != nil {
    return nil, errors.Wrap(err, "无法创建表单文件")
}
_, err = io.CopyBuffer(part, r.Body, a)
wr.Close()

req, err := http.NewRequest("POST", cloudFlareUrl, bytes.NewReader(b.Bytes()))
if err != nil {
    return nil, errors.Wrap(err, "无法创建请求")
}
// req.Header.Set("Content-Type", "multipart/form-data")
req.Header.Set("Content-Type", wr.FormDataContentType())
req.Header.Set("Authorization", cloudFlareAuth)

希望对你有帮助!

英文:

Ok for anyone else having this issue. I solved it.

r, err := http.Get(url)
if err != nil {
return nil, errors.Wrap(err, "Couldn't get the file")
}
if r.StatusCode != 200 {
return nil, errors.New("Couldn't get the file")
}
defer r.Body.Close()
b := &bytes.Buffer{}
a := make([]byte, 4096)
wr := multipart.NewWriter(b)
part, err := wr.CreateFormFile("file", filename)
if err != nil {
return nil, errors.Wrap(err, "Couldn't create the form file")
}
_, err = io.CopyBuffer(part, r.Body, a)
wr.Close()
req, err := http.NewRequest("POST", cloudFlareUrl, bytes.NewReader(b.Bytes()))
if err != nil {
return nil, errors.Wrap(err, "Couldn't create the request")
}
// req.Header.Set("Content-Type", "multipart/form-data")
req.Header.Set("Content-Type", wr.FormDataContentType())
req.Header.Set("Authorization", cloudFlareAuth)

huangapple
  • 本文由 发表于 2022年4月3日 17:15:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/71724526.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定