{"record":{"id":"ec76951178abbdc2","repo":"unknwon/the-way-to-go_ZH_CN","slug":"err-error-ec7695","errorCode":null,"errorMessage":"err.Error()","messagePattern":"err\\.Error\\(\\)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"warning","filePath":"eBook/20.5.md","lineNumber":70,"sourceCode":"`appengine.NewContext()` 函数在这里返回一个名为 `c` 的 `appengine.Context` 值：这是 Go App Engine SDK 中许多函数用来与 App Engine 服务通信的值。然后我们从这个上下文中测试是否已经有一个用户在此时登录，方法是：\n\n```go\n u := user.Current(c)\n```\n\n如果是这样的话，`user.Current` 会返回一个指向用户的 `user.User` 值的指针；否则会返回 `nil`。如果用户还没有登录，即 `u == nil` 时，通过调用用户的浏览器重定向到谷歌账户的登录界面。\n\n```go\nurl, err := user.LoginURL(c, r.URL.String())\n```\n\n第 2 个参数 `r.URL.String()` 是当前请求的 url，这样谷歌账户登录机制可以在成功登录后进行*重定向*：它将在用户登录或注册新账户后将其送回这里。登录界面的发送是通过设置一个 Location 数据头并返回一个 HTTP 状态代码 302“Found”来完成的。\n\n`LoginURL()` 函数返回一个 error 值作为其第二个参数。尽管这里不太可能发生错误，但检查它并在适当的时候向用户显示错误是很好的做法（在这种情况下，用 http.Error helper）：\n\n```go\nif err != nil {\n\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\treturn\n}\n```\n\n当用户登录后，我们使用与用户账户相关的名字显示一条个性化的信息： \n\n```go\nfmt.Fprintf(w, \"Hello, %v!\", u)\n```\n\n在这种情况下，`fmt.Fprintf()` 函数调用 `*user.User` 的 `String()` 方法来获得字符串形式的用户名称。更多信息可以在这个参考资料中找到：http://code.google.com/appengine/docs/go/users/\n\n## 链接\n\n- [目录](directory.md)\n- 上一节：[建造你自己的 Hello world 应用](20.4.md)\n- 下一节：[处理窗口](20.6.md)\n","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/unknwon/the-way-to-go_ZH_CN/blob/7a54d34d3657084b6a59e5618bd069b912d571aa/eBook/20.5.md#L52-L88","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nurl, err := user.LoginURL(c, r.URL.String())\nif err != nil {\n    http.Error(w, err.Error(), http.StatusInternalServerError)\n    return\n}\n\n// after\nurl, err := user.LoginURL(c, r.URL.String())\nif err != nil {\n    log.Println(\"LoginURL:\", err)\n    http.Error(w, \"login unavailable, please retry\", http.StatusInternalServerError)\n    return\n}","handlingStrategy":"retry","validationCode":"// make drift visible before the handler runs: verify context and SDK match at startup\n// (appengine context is request-scoped; sanity-check config in app.yaml: runtime: go, and\n// that the dev server is the same SDK version as deployment)","typeGuard":null,"tryCatchPattern":"// one bounded retry for a transient users-service hiccup, then degrade\nurl, err := user.LoginURL(c, r.URL.String())\nif err != nil {\n    time.Sleep(200 * time.Millisecond)\n    url, err = user.LoginURL(c, r.URL.String())\n}\nif err != nil {\n    log.Println(\"LoginURL:\", err)\n    http.Error(w, \"login unavailable, please retry\", http.StatusInternalServerError)\n    return\n}","preventionTips":["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"],"tags":["go","appengine","authentication","login","http-error"],"backgroundTag":null,"analyzedSha":"7a54d34d3657084b6a59e5618bd069b912d571aa","analyzedAt":"2026-08-15T15:13:06.026Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}