unknwon/the-way-to-go_ZH_CN · warning
err.Error()
Error message
err.Error()
What it means
The section-20.5 handler checks the error from user.LoginURL(c, r.URL.String()) and responds http.Error(w, err.Error(), 500). The doc itself notes errors here are unlikely ('尽管这里不太可能发生错误') — the check is defensive practice for the App Engine users service failing (misconfigured context or service unavailable).
Source
Thrown at eBook/20.5.md:70
`appengine.NewContext()` 函数在这里返回一个名为 `c` 的 `appengine.Context` 值:这是 Go App Engine SDK 中许多函数用来与 App Engine 服务通信的值。然后我们从这个上下文中测试是否已经有一个用户在此时登录,方法是:
```go
u := user.Current(c)
```
如果是这样的话,`user.Current` 会返回一个指向用户的 `user.User` 值的指针;否则会返回 `nil`。如果用户还没有登录,即 `u == nil` 时,通过调用用户的浏览器重定向到谷歌账户的登录界面。
```go
url, err := user.LoginURL(c, r.URL.String())
```
第 2 个参数 `r.URL.String()` 是当前请求的 url,这样谷歌账户登录机制可以在成功登录后进行*重定向*:它将在用户登录或注册新账户后将其送回这里。登录界面的发送是通过设置一个 Location 数据头并返回一个 HTTP 状态代码 302“Found”来完成的。
`LoginURL()` 函数返回一个 error 值作为其第二个参数。尽管这里不太可能发生错误,但检查它并在适当的时候向用户显示错误是很好的做法(在这种情况下,用 http.Error helper):
```go
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
```
当用户登录后,我们使用与用户账户相关的名字显示一条个性化的信息:
```go
fmt.Fprintf(w, "Hello, %v!", u)
```
在这种情况下,`fmt.Fprintf()` 函数调用 `*user.User` 的 `String()` 方法来获得字符串形式的用户名称。更多信息可以在这个参考资料中找到:http://code.google.com/appengine/docs/go/users/
## 链接
- [目录](directory.md)
- 上一节:[建造你自己的 Hello world 应用](20.4.md)
- 下一节:[处理窗口](20.6.md)
View on GitHub (pinned to 7a54d34d36)
Solutions
- Restart (and if needed clear state on) the dev appserver, then retry the login flow
- Align the SDK and app.yaml runtime versions and redeploy
- Log err server-side and render a friendly 'login unavailable, please retry' page instead of the raw error
- If it persists in production, check the App Engine status dashboard for the users service
Example fix
// before
url, err := user.LoginURL(c, r.URL.String())
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// after
url, err := user.LoginURL(c, r.URL.String())
if err != nil {
log.Println("LoginURL:", err)
http.Error(w, "login unavailable, please retry", http.StatusInternalServerError)
return
} Defensive patterns
Strategy: retry
Validate before calling
// make drift visible before the handler runs: verify context and SDK match at startup // (appengine context is request-scoped; sanity-check config in app.yaml: runtime: go, and // that the dev server is the same SDK version as deployment)
Try / catch
// one bounded retry for a transient users-service hiccup, then degrade
url, err := user.LoginURL(c, r.URL.String())
if err != nil {
time.Sleep(200 * time.Millisecond)
url, err = user.LoginURL(c, r.URL.String())
}
if err != nil {
log.Println("LoginURL:", err)
http.Error(w, "login unavailable, please retry", http.StatusInternalServerError)
return
} Prevention
- Keep the local dev server's state clean; restart it after SDK or app.yaml changes
- Pin the SDK/runtime version so dev and production behave identically
- Log these rare errors — they are the earliest signal of a users-service or config problem
When it happens
Trigger: user.Current returns nil (visitor not logged in) and LoginURL then errors: dev_appserver state misconfiguration, stale app.yaml/runtime mismatch, or the users service being briefly unavailable.
Common situations: Local dev server with corrupted datastore/session state; SDK and app.yaml runtime version drift after an upgrade; transient users-service outage on App Engine.
Related errors
AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15).
Data as JSON: /api/errors/ec76951178abbdc2.
Report an issue: GitHub.