google-app-engine - 尝试读取 *http.Response Body 时出现运行时错误,已使用 urlfetch.Transport

标签 google-app-engine facebook-graph-api go

App Engine 不允许使用 DefaultClient,而是提供 urlfetch 服务。以下最小示例部署并按预期工作:

package app

import (
    "fmt"
    "net/http"
    "appengine"
    "appengine/urlfetch"
    "code.google.com/p/goauth2/oauth"
)

func init () {
    http.HandleFunc("/", home)
}

func home(w http.ResponseWriter, r *http.Request) {
    c := appengine.NewContext(r)
    config := &oauth.Config{
        ClientId:     "<redacted>",
        ClientSecret: "<redacted>",
        Scope:        "email",
        AuthURL:      "https://www.facebook.com/dialog/oauth",
        TokenURL:     "https://graph.facebook.com/oauth/access_token",
        RedirectURL:  "http://example.com/",
    }

    code := r.FormValue("code")
    if code == "" {
        http.Redirect(w, r, config.AuthCodeURL("foo"), http.StatusFound)
    }
    t := &oauth.Transport{Config: config, Transport: &urlfetch.Transport{Context: c}}
    tok, _ := t.Exchange(code)
    graphResponse, _ := t.Client().Get("https://graph.facebook.com/me")

    fmt.Fprintf(w, "<pre>%s<br />%s</pre>", tok, graphResponse)
}

使用正确的 ClientId、ClientSecret 和 RedirectURL,这会产生以下输出(为简洁起见进行了编辑):

&{AAADTWGsQ5<snip>kMdjh5VKwZDZD  0001-01-01 00:00:00 +0000 UTC}

&{200 OK %!s(int=200) HTTP/1.1 %!s(int=1) %!s(int=1) 
map[Connection:[keep-alive] Access-Control-Allow-Origin:[*] 
<snip>
Content-Type:[text/javascript; charset=UTF-8] 
Date:[Wed, 06 Feb 2013 12:06:45 GMT] X-Google-Cache-Control:[remote-fetch] 
Cache-Control:[private, no-cache, no-store, must-revalidate] Pragma:[no-cache] 
X-Fb-Rev:[729873] Via:[HTTP/1.1 GWA] Expires:[Sat, 01 Jan 2000 00:00:00 GMT]] 
%!s(*urlfetch.bodyReader=&{[123 34 105 100 <big snip> 48 48 34 125] false false}) 
%!s(int64=306) [] %!s(bool=true) map[] %!s(*http.Request=&{GET 0xf840087230 
HTTP/1.1 1 1 map[Authorization:[Bearer AAADTWGsQ5NsBAC4yT0x1shZAJAtODOIx0tZCb
TYTjxFC4esEqCjPDi3REMKHBUjZCX4FIKLO1UjMpJxhJZCfGFcOJlFu7UvehkMdjh5VKwZDZD]]
  0 [] false graph.facebook.com map[]  map[]   })}

肯定似乎我一直在收到 *http.Response 返回,所以我希望能够从响应正文中读取。但是,任何提及 Body——例如:

defer graphResponse.Body.Close()

编译、部署,但导致以下运行时错误:

panic: runtime error: invalid memory address or nil pointer dereference
runtime.panic go/src/pkg/runtime/proc.c:1442
runtime.panicstring go/src/pkg/runtime/runtime.c:128
runtime.sigpanic go/src/pkg/runtime/thread_linux.c:199
app.home app/app.go:33
net/http.HandlerFunc.ServeHTTP go/src/pkg/net/http/server.go:704
net/http.(*ServeMux).ServeHTTP go/src/pkg/net/http/server.go:942
appengine_internal.executeRequestSafely go/src/pkg/appengine_internal/api_prod.go:240
appengine_internal.(*server).HandleRequest go/src/pkg/appengine_internal/api_prod.go:190
reflect.Value.call go/src/pkg/reflect/value.go:526
reflect.Value.Call go/src/pkg/reflect/value.go:334
_ _.go:316
runtime.goexit go/src/pkg/runtime/proc.c:270

我错过了什么?这是因为使用了 urlfetch 而不是 DefaultClient 吗?

最佳答案

好吧,这当然是我自己的愚蠢错误,但我可以看到其他人如何落入同样的陷阱,所以这是由 Andrew Gerrand 和 Kyle Lemons 在 this google-appengine-go topic 中提出的解决方案。 (谢谢大家)。

首先,我没有处理对 favicon.ico 的请求。这可以按照说明进行处理 here并向 app.yaml 添加一个部分:

- url: /favicon\.ico
  static_files: images/favicon.ico
  upload: images/favicon\.ico

这修复了对 favicon 请求的 panic ,但不是对“/”请求的 panic 。问题是,我假设 http.Redirect 会在此时结束处理程序的执行。它没有。需要的是重定向后的 return 语句或 else 子句:

code := r.FormValue("code")
if code == "" {
    http.Redirect(w, r, config.AuthCodeURL("foo"), http.StatusFound)
} else {
    t := &oauth.Transport{Config: config, Transport: &urlfetch.Transport{Context: c}}
    tok, _ := t.Exchange(code)

    fmt.Fprintf(w, "%s", tok.AccessToken)
    // ...
}

我当然不建议忽略错误,但这会按预期部署和运行,生成有效 token 。

关于google-app-engine - 尝试读取 *http.Response Body 时出现运行时错误,已使用 urlfetch.Transport,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14729004/

相关文章:

json - Golang 转换 JSON

google-app-engine - 使用哪个区域的 Google 云服务来降低成本和延迟

python - Remote_api_stub 的路径问题

python - 将数据从应用程序引擎(python)发送到远程服务器(带 php 的 linux)

facebook-graph-api - Facebook 图形 API : Get user city (location)

Golang - 为什么这个错误发生在 ServeHTTP 函数 : reflect: call of reflect. Value.Call on zero Value

google-app-engine - 将 GAE 应用程序从一个 Google Apps 帐户转移到另一个

facebook - 交互式 Facebook 应用程序开放图对象

ios - 提供的 Facebook session token 已过期或无效

使用 Go 编程语言查找命名捕获组的正则表达式