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

  1. Restart (and if needed clear state on) the dev appserver, then retry the login flow
  2. Align the SDK and app.yaml runtime versions and redeploy
  3. Log err server-side and render a friendly 'login unavailable, please retry' page instead of the raw error
  4. 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

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.