2013-02-06 72 views
2

App Engine不允許使用DefaultClient,而是提供urlfetch服務。下面的小例子,部署和按預期工作相當多:嘗試讀取* http.Response Body時發生運行時錯誤,使用了urlfetch.Transport

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

有了正確的客戶端Id,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,所以我希望能夠從響應體中讀取。然而,身體的任何提及 - 例如使用:

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嗎?

+1

你是否檢查'.Get()'返回的錯誤?如果是的話,它說了什麼? – nemo

+0

對不起,應該提到所有的錯誤都只是爲了舉例的目的而被忽略。他們都經過測試,無。 –

回答

0

好的,這當然是我自己的愚蠢錯誤,但我可以看到其他人如何陷入同一個陷阱,所以這裏的解決方案,由安德魯Gerrand和凱爾檸檬在this google-appengine-go topic(謝謝你們)提示。

首先,我沒有處理對favicon.ico的請求。這可以通過以下的說明here並增加了部分app.yaml中得到照顧:

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

這個固定的恐慌上圖標的請求,但請求「/」不恐慌。問題是,我假定一個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) 
    // ... 
} 

我不建議忽略過程的錯誤,但這種部署和運行如預期,從而產生有效的標記。

相關問題