2 回答
TA贡献1820条经验 获得超10个赞
有两种方法可以将文件写入 blobstore
一种是使用 Blobstore 页面末尾记录的已弃用 API。他们的示例代码如下。
他们将要改用的方法是将文件存储在 Google 云存储中并通过 blobstore 为它们提供服务。
另一种方法是以某种方式模拟用户上传。Go 有一个 http 客户端,可以将要上传的文件发送到网址。不过,这将是一种黑客方法。
var k appengine.BlobKey
w, err := blobstore.Create(c, "application/octet-stream")
if err != nil {
return k, err
}
_, err = w.Write([]byte("... some data ..."))
if err != nil {
return k, err
}
err = w.Close()
if err != nil {
return k, err
}
return w.Key()
TA贡献1936条经验 获得超6个赞
正如@yumaikas 所说,不推荐使用Files API。如果此数据来自某种用户上传,您应该修改上传表单以使用 Blobstore 上传 URL(特别是,将编码设置为multipart/form-dataormultipart/mixed并命名所有文件上传字段file,除了您不想的那些存储在 blobstore 中)。
但是,如果这是不可能的(例如,您无法控制用户输入,或者您必须在将数据存储到 Blobstore 之前在服务器上预处理数据),那么您要么必须使用已弃用的Files API,或使用URLFetch API上传数据。
这是一个完整的示例应用程序,它将在 Blobstore 中为您存储一个示例文件。
package sample
import (
"bytes"
"net/http"
"mime/multipart"
"appengine"
"appengine/blobstore"
"appengine/urlfetch"
)
const SampleData = `foo,bar,spam,eggs`
func init() {
http.HandleFunc("/test", StoreSomeData)
http.HandleFunc("/upload", Upload)
}
func StoreSomeData(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
// First you need to create the upload URL:
u, err := blobstore.UploadURL(c, "/upload", nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
c.Errorf("%s", err)
return
}
// Now you can prepare a form that you will submit to that URL.
var b bytes.Buffer
fw := multipart.NewWriter(&b)
// Do not change the form field, it must be "file"!
// You are free to change the filename though, it will be stored in the BlobInfo.
file, err := fw.CreateFormFile("file", "example.csv")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
c.Errorf("%s", err)
return
}
if _, err = file.Write([]byte(SampleData)); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
c.Errorf("%s", err)
return
}
// Don't forget to close the multipart writer.
// If you don't close it, your request will be missing the terminating boundary.
fw.Close()
// Now that you have a form, you can submit it to your handler.
req, err := http.NewRequest("POST", u.String(), &b)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
c.Errorf("%s", err)
return
}
// Don't forget to set the content type, this will contain the boundary.
req.Header.Set("Content-Type", fw.FormDataContentType())
// Now submit the request.
client := urlfetch.Client(c)
res, err := client.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
c.Errorf("%s", err)
return
}
// Check the response status, it should be whatever you return in the `/upload` handler.
if res.StatusCode != http.StatusCreated {
http.Error(w, err.Error(), http.StatusInternalServerError)
c.Errorf("bad status: %s", res.Status)
return
}
// Everything went fine.
w.WriteHeader(res.StatusCode)
}
func Upload(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
// Here we just checked that the upload went through as expected.
if _, _, err := blobstore.ParseUpload(r); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
c.Errorf("%s", err)
return
}
// Everything seems fine. Signal the other handler using the status code.
w.WriteHeader(http.StatusCreated)
}
现在,如果你curl http://localhost:8080/test,它将在 Blobstore 中存储一个文件。
重要提示:我不确定您对自己的应用程序发出的请求的带宽费用如何收费。在最坏的情况下,您将被收取内部流量费用,这比正常带宽 iirc 便宜。
- 2 回答
- 0 关注
- 198 浏览
添加回答
举报