为了账号安全,请及时绑定邮箱和手机立即绑定

是否可以在 GAE Golang Blobstore 中存储任意数据?

是否可以在 GAE Golang Blobstore 中存储任意数据?

Go
梦里花落0921 2021-07-02 14:04:29
我正在 Google App Engine Go 中创建一个大型数据库应用程序。我的大部分数据都很小,所以我将它们存储在 Datastore 中没有问题。但是,我知道我会遇到一些大小为几兆字节的条目,因此我将不得不使用 Blobstore 来保存它们。看在了Blob存储参考,看来该服务的主要目的在于使用的文件被上传到该服务。我需要调用哪些函数来像在 Datastore 中一样在 Blobstore 中存储任意数据?我已经可以将数据转换为 []byte 并且我不需要在 blob 中索引任何东西,只需通过 ID 存储和获取它。
查看完整描述

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()


查看完整回答
反对 回复 2021-07-12
?
LEATH

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 便宜。


查看完整回答
反对 回复 2021-07-12
  • 2 回答
  • 0 关注
  • 198 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信