{"record":{"id":"e2661af0a6c2ccd4","repo":"unknwon/the-way-to-go_ZH_CN","slug":"err-error-e2661a","errorCode":null,"errorMessage":"err.Error()","messagePattern":"err\\.Error\\(\\)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"eBook/19.8.md","lineNumber":86,"sourceCode":"\t\treturn errors.New(\"key already exists\")\n\t}\n\ts.urls[*key] = *url\n\treturn nil\n}\n```\n\n同样，当从 `load()` 调用 `Set()` 时，也必须做调整：\n```go\ns.Set(&r.Key, &r.URL)\n```\n\n还必须修改 HTTP 处理函数以适应 `URLStore` 上的更改。`Redirect()` 处理函数现在返回 `URLStore` 给出错误的字符串形式：\n```go\nfunc Redirect(w http.ResponseWriter, r *http.Request) {\n\tkey := r.URL.Path[1:]\n\tvar url string\n\tif err := store.Get(&key, &url); err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\thttp.Redirect(w, r, url, http.StatusFound)\n}\n```\n\n`Add()` 处理函数也以基本相同的方式修改：\n\n```go\nfunc Add(w http.ResponseWriter, r *http.Request) {\n\turl := r.FormValue(\"url\")\n\tif url == \"\" {\n\t\tfmt.Fprint(w, AddForm)\n\t\treturn\n\t}\n\tvar key string\n\tif err := store.Put(&url, &key); err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/unknwon/the-way-to-go_ZH_CN/blob/7a54d34d3657084b6a59e5618bd069b912d571aa/eBook/19.8.md#L68-L104","documentation":"In the URL shortener (19.8), the Redirect handler calls store.Get(&key, &url) and on error replies http.Error(w, err.Error(), 500). After the RPC-backed URLStore refactor, Get returns an error when the key is unknown or when the store/RPC layer fails to fetch it — and the raw internal error goes to the visitor.","triggerScenarios":"Requesting a path whose key was never stored (or whose mapping vanished after a restart because the gob data file did not persist it); the RPC client unable to reach the RPC server instance; a gob decode error on a corrupt store entry.","commonSituations":"Short links from an earlier run after the data file was reset or pointed elsewhere; starting an instance without -rpc while expecting a shared store; racing Put/Get against the persisted map on shutdown.","solutions":["Distinguish 'key not found' from real failures — return http.NotFound for unknown keys instead of a 500 with internal text","Keep the data-file path stable (make it a flag) so keys survive restarts","If -rpc is enabled, verify the RPC server's hostname/port are reachable and the store is registered","Log the error server-side; serve a friendly 'unknown short link' page to users"],"exampleFix":"// before\nif err := store.Get(&key, &url); err != nil {\n    http.Error(w, err.Error(), http.StatusInternalServerError)\n    return\n}\n\n// after\nif err := store.Get(&key, &url); err != nil {\n    log.Println(\"get failed for key\", key, \":\", err)\n    if err == ErrUnknownKey {\n        http.NotFound(w, r)\n    } else {\n        http.Error(w, \"shortener unavailable\", http.StatusInternalServerError)\n    }\n    return\n}","handlingStrategy":"fallback","validationCode":"// cheap format check before hitting the store: generated keys are short and alphanumeric\nvar keyRe = regexp.MustCompile(\"^[a-zA-Z0-9]{1,10}$\")\n\nkey := r.URL.Path[1:]\nif !keyRe.MatchString(key) {\n    http.NotFound(w, r) // clearly not one of our keys — 404, not 500\n    return\n}","typeGuard":null,"tryCatchPattern":"// degrade gracefully when the store can't answer\nif err := store.Get(&key, &url); err != nil {\n    log.Println(\"store.Get:\", err)\n    if errors.Is(err, ErrUnknownKey) {\n        http.NotFound(w, r)\n    } else {\n        http.Redirect(w, r, \"/\", http.StatusFound) // fall back to home page\n    }\n    return\n}","preventionTips":["Persist the store file to a fixed, backed-up path so keys survive restarts","Define a sentinel ErrUnknownKey so not-found maps to 404, not 500","Health-check the RPC backend before serving redirects when -rpc is on"],"tags":["go","http","url-shortener","rpc","key-not-found","gob"],"backgroundTag":null,"analyzedSha":"7a54d34d3657084b6a59e5618bd069b912d571aa","analyzedAt":"2026-08-15T15:13:06.026Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}