从GAE将Json Array上传到GO中的云存储(Upload Json Array from GAE to Cloud Storage in GO)

编程入门 行业动态 更新时间:2024-10-23 10:30:24
从GAE将Json Array上传到GO中的云存储(Upload Json Array from GAE to Cloud Storage in GO)

我尝试使用以下代码上传到谷歌云存储json数组,该数组由应用引擎应用程序发布:

saveData : function saveData() { var _this = this, save = this.shadowRoot.querySelector('#save-data'), subData = JSON.stringify(_this.app.userSession); save.url="url"; save.body = subData; save.go(); }

发布的消息将使用下面发布的代码处理。 使用此代码,我可以在云存储桶上创建一个文件夹,该文件夹以用户ID命名。 我想要做的是将整个json数组复制到文件夹中 - 即下面代码中的变量f。 我尝试使用io.Copy(wc,f),但它给了我以下错误:

不能使用内容(类型userData)作为io.Copy参数中的类型io.Reader:userData没有实现io.Reader(缺少Read方法)

显然我做错了什么,但我很新,我完全陷入了困境。 有人能帮我吗?

package expt import ( "bytes" "encoding/json" "io/ioutil" "log" "net/http" "golang.org/x/net/context" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/appengine" "google.golang.org/appengine/file" "google.golang.org/appengine/urlfetch" "google.golang.org/cloud" "google.golang.org/cloud/storage" ) var bucket = "expt" func init() { http.HandleFunc("/", handleStatic) http.HandleFunc("/save", saveJson) } func handleStatic(w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "no-cache") http.ServeFile(w, r, "static/"+r.URL.Path) } type Result map[string]interface { } type userData struct { id string age string gender string } func testA(r *http.Request) userData { defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) var userDataCurr userData if err != nil { log.Printf("Couldn't read request body: %s", err) } else { var f Result err := json.Unmarshal(body, &f) if err != nil { log.Println("Error: %s", err) } else { user := f["user"].(map[string]interface{}) userDataCurr.id = user["id"].(string) } } return userDataCurr } // saveData struct holds information needed to run the various saving functions. type saveData struct { c context.Context r *http.Request w http.ResponseWriter ctx context.Context // cleanUp is a list of filenames that need cleaning up at the end of the saving. cleanUp []string // failed indicates that one or more of the saving steps failed. failed bool } func (d *saveData) errorf(format string, args ...interface{}) { d.failed = true // log.Errorf(d.c, format, args...) } // testSave is the main saving entry point that calls the GCS operations. func saveJson(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) if bucket == "" { var err error if bucket, err = file.DefaultBucketName(c); err != nil { // log.Errorf(c, "failed to get default GCS bucket name: %v", err) return } } hc := &http.Client{ Transport: &oauth2.Transport{ Source: google.AppEngineTokenSource(c, storage.ScopeFullControl), Base: &urlfetch.Transport{Context: c}, }, } ctx := cloud.NewContext(appengine.AppID(c), hc) d := &saveData{ c: c, r: r, w: w, ctx: ctx, } d.createUserFolder() } // createFile creates a file in Google Cloud Storage. func (d *saveData) createFile(fileName string) { wc := storage.NewWriter(d.ctx, bucket, fileName) wc.ContentType = "text/plain" d.cleanUp = append(d.cleanUp, fileName) if err := wc.Close(); err != nil { d.errorf("createFile: unable to close bucket %q, file %q: %v", bucket, fileName, err) return } } //create files that will be used by listBucket. func (d *saveData) createUserFolder() { var ( content = testA(d.r) buffer bytes.Buffer ) buffer.WriteString(content.id) buffer.WriteString("/") d.createFile(buffer.String()) }

I trying to upload to google cloud storage a json array which is posted by an app engine application using the following code:

saveData : function saveData() { var _this = this, save = this.shadowRoot.querySelector('#save-data'), subData = JSON.stringify(_this.app.userSession); save.url="url"; save.body = subData; save.go(); }

The posted message is handled in go with the code posted below. With this code I'm able to create a folder on the cloud storage bucket which is named with the user ID. What I would love to do is to copy into the folder the entire json array -i.e. the variable f in the code below. I tried with io.Copy(wc, f) but it gives me the following error:

cannot use content (type userData) as type io.Reader in argument to io.Copy: userData does not implement io.Reader (missing Read method)

Obviously I'm doing something wrong, but I'm quite new to go and I'm totally stuck. Can someone help me?

package expt import ( "bytes" "encoding/json" "io/ioutil" "log" "net/http" "golang.org/x/net/context" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/appengine" "google.golang.org/appengine/file" "google.golang.org/appengine/urlfetch" "google.golang.org/cloud" "google.golang.org/cloud/storage" ) var bucket = "expt" func init() { http.HandleFunc("/", handleStatic) http.HandleFunc("/save", saveJson) } func handleStatic(w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "no-cache") http.ServeFile(w, r, "static/"+r.URL.Path) } type Result map[string]interface { } type userData struct { id string age string gender string } func testA(r *http.Request) userData { defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) var userDataCurr userData if err != nil { log.Printf("Couldn't read request body: %s", err) } else { var f Result err := json.Unmarshal(body, &f) if err != nil { log.Println("Error: %s", err) } else { user := f["user"].(map[string]interface{}) userDataCurr.id = user["id"].(string) } } return userDataCurr } // saveData struct holds information needed to run the various saving functions. type saveData struct { c context.Context r *http.Request w http.ResponseWriter ctx context.Context // cleanUp is a list of filenames that need cleaning up at the end of the saving. cleanUp []string // failed indicates that one or more of the saving steps failed. failed bool } func (d *saveData) errorf(format string, args ...interface{}) { d.failed = true // log.Errorf(d.c, format, args...) } // testSave is the main saving entry point that calls the GCS operations. func saveJson(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) if bucket == "" { var err error if bucket, err = file.DefaultBucketName(c); err != nil { // log.Errorf(c, "failed to get default GCS bucket name: %v", err) return } } hc := &http.Client{ Transport: &oauth2.Transport{ Source: google.AppEngineTokenSource(c, storage.ScopeFullControl), Base: &urlfetch.Transport{Context: c}, }, } ctx := cloud.NewContext(appengine.AppID(c), hc) d := &saveData{ c: c, r: r, w: w, ctx: ctx, } d.createUserFolder() } // createFile creates a file in Google Cloud Storage. func (d *saveData) createFile(fileName string) { wc := storage.NewWriter(d.ctx, bucket, fileName) wc.ContentType = "text/plain" d.cleanUp = append(d.cleanUp, fileName) if err := wc.Close(); err != nil { d.errorf("createFile: unable to close bucket %q, file %q: %v", bucket, fileName, err) return } } //create files that will be used by listBucket. func (d *saveData) createUserFolder() { var ( content = testA(d.r) buffer bytes.Buffer ) buffer.WriteString(content.id) buffer.WriteString("/") d.createFile(buffer.String()) }

最满意答案

这段代码非常令人困惑,但据我所知,你试图这样做:

func (d *saveData) createFile(fileName string, content userData) { wc := storage.NewWriter(d.ctx, bucket, fileName) wc.ContentType = "text/plain" d.cleanUp = append(d.cleanUp, fileName) //*** new code ******* io.Copy(wc, content) //******************** if err := wc.Close(); err != nil { d.errorf("createFile: unable to close bucket %q, file %q: %v", bucket, fileName, err) return } }

您无法直接将对象写入文件,需要先对其进行编码。 我假设你想要json。 你可以这样做:

bs, err := json.Marshal(content) if err != nil { return err } io.Copy(wc, bytes.NewReader(bs))

但是最好使用json.NewEncoder :

json.NewEncoder(wc).Encode(content)

您的createUserFolder也可以简化(您不需要缓冲区来连接字符串):

func (d *saveData) createUserFolder() { content := testA(d.r) d.createFile(content.id + "/") }

我不知道testA应该是什么意思,但它也可以简化:

type UserData { ID string `json:"id"` Age string `json:"age"` Gender string `json:"gender"` } func testA(r *http.Request) UserData { defer r.Body.Close() var obj struct { User UserData `json:"user"` } err := json.NewDecoder(r.Body).Decode(&obj) if err != nil { log.Println("Error: %s", err) } return obj.User }

使用大写字段名称,以便json可以为您处理转换。

可能还有很多重构需要完成,但也许这就足以开始了。

This code is very confusing but from what I can tell are you trying to do this:

func (d *saveData) createFile(fileName string, content userData) { wc := storage.NewWriter(d.ctx, bucket, fileName) wc.ContentType = "text/plain" d.cleanUp = append(d.cleanUp, fileName) //*** new code ******* io.Copy(wc, content) //******************** if err := wc.Close(); err != nil { d.errorf("createFile: unable to close bucket %q, file %q: %v", bucket, fileName, err) return } }

You can't write an object directly to a file, it needs to be encoded first. I'm assuming you want json. You could do it this way:

bs, err := json.Marshal(content) if err != nil { return err } io.Copy(wc, bytes.NewReader(bs))

But it would be better to use json.NewEncoder:

json.NewEncoder(wc).Encode(content)

Your createUserFolder can also be simplified (you don't need a buffer to concatenate strings):

func (d *saveData) createUserFolder() { content := testA(d.r) d.createFile(content.id + "/") }

I don't know what testA is supposed to mean, but it too can be simplified:

type UserData { ID string `json:"id"` Age string `json:"age"` Gender string `json:"gender"` } func testA(r *http.Request) UserData { defer r.Body.Close() var obj struct { User UserData `json:"user"` } err := json.NewDecoder(r.Body).Decode(&obj) if err != nil { log.Println("Error: %s", err) } return obj.User }

Use uppercase field names so that json can handle the conversion for you.

There's probably a lot more refactoring to be done, but maybe that's enough to get started.

更多推荐

本文发布于:2023-08-01 13:39:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1359142.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Array   Json   GAE   Storage   Cloud

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!