{"record":{"id":"0fb86f7ddaeec2f6","repo":"unknwon/the-way-to-go_ZH_CN","slug":"key-not-found","errorCode":null,"errorMessage":"key not found","messagePattern":"key not found","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"eBook/19.8.md","lineNumber":40,"sourceCode":"```\n\n要使 `URLStore` 成为 RPC 服务，需要修改 `Put()` 和 `Get()` 方法使它们符合上述函数签名。以下是修改后的签名：\n```go\nfunc (s *URLStore) Get(key, url *string) error\nfunc (s *URLStore) Put(url, key *string) error\n```\n\n`Get()` 代码变更为：\n\n```go\nfunc (s *URLStore) Get(key, url *string) error {\n\ts.mu.RLock()\n\tdefer s.mu.RUnlock()\n\tif u, ok := s.urls[*key]; ok {\n\t\t*url = u\n\t\treturn nil\n\t}\n\treturn errors.New(\"key not found\")\n}\n```\n\n现在，键和长 URL 都变成了指针，必须加上前缀 `*` 来取得它们的值，例如 `*key` 这种形式。`u` 是一个值，可以用 `*url = u` 来将其赋值给指针。\n\n接着对 `Put()` 代码做同样的改动：\n```go\nfunc (s *URLStore) Put(url, key *string) error {\n\tfor {\n\t\t*key = genKey(s.Count())\n\t\t\tif err := s.Set(key, url); err == nil {\n\t\t\tbreak\n\t\t}\n\t}\n\tif s.save != nil {\n\t\ts.save <- record{*key, *url}\n\t}\n\treturn nil","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/unknwon/the-way-to-go_ZH_CN/blob/7a54d34d3657084b6a59e5618bd069b912d571aa/eBook/19.8.md#L22-L58","documentation":"Returned by URLStore.Get in the chapter 19 URL-shortener after the RPC-style refactor: Get(key, url *string) takes a read lock (s.mu.RLock with defer RUnlock), and when the map lookup s.urls[*key] misses it returns errors.New(\"key not found\"). The Redirect HTTP handler prints the error's string form — effectively the 404 cause for an unknown short key.","triggerScenarios":"The Redirect handler receives /somekey that was never Put: the key is absent from s.urls. Also key-format mismatches (keys come from genKey(s.Count()) and are short strings), keys lost because the service restarted without load() replaying the persisted store, or typo'd/garbled short URLs.","commonSituations":"Persistence bugs: the save channel dropped records, data_store.txt was not loaded on startup, or Count() desynchronized after load causing genKey to emit colliding keys; hand-typed keys with case errors; multi-instance deployments where only one replica holds the key.","solutions":["On startup, always run load() to replay the persisted store before serving traffic, so previously issued keys stop missing","In Redirect, treat this error as 404: if err := store.Get(&key, &url); err != nil { http.NotFound(w, req); return } — or redirect to the homepage per the book's variant","Promote the string to a sentinel (var ErrKeyNotFound = errors.New(\"key not found\")) and branch with errors.Is so refactors keep the 404 mapping working","If keys vanish under load, verify Get's RLock/RUnlock pairing and that Put still writes records through save <- record{*key, *url}"],"exampleFix":"// before\nerr := store.Get(&key, &url)\nif err != nil {\n\tfmt.Println(\"Error:\", err) // raw 'key not found' leaked to stdout\n}\n\n// after\nvar url string\nif err := store.Get(&key, &url); err != nil {\n\thttp.Error(w, \"no such key: \"+key, http.StatusNotFound)\n\treturn\n}\nhttp.Redirect(w, req, url, http.StatusFound)","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"var url string\nif err := store.Get(&key, &url); err != nil {\n\t// unknown short key: degrade gracefully\n\thttp.NotFound(w, req) // or redirect to the homepage\n\treturn\n}\nhttp.Redirect(w, req, url, http.StatusFound)","preventionTips":["Replay persisted records via load() before the server starts listening, so issued keys survive restarts","Treat 'key not found' as an expected branch: map it to 404 or a homepage redirect, never a 500","Promote the message to an exported sentinel (ErrKeyNotFound) and match with errors.Is so refactors keep the mapping","Monitor the miss rate: a spike usually means persistence or replication broke, not user typos"],"tags":["go","url-shortener","map-lookup","not-found","http"],"backgroundTag":null,"analyzedSha":"7a54d34d3657084b6a59e5618bd069b912d571aa","analyzedAt":"2026-08-15T15:13:06.026Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}