unknwon/the-way-to-go_ZH_CN · error
err.Error()
Error message
err.Error()
What it means
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.
Source
Thrown at eBook/19.8.md:86
return errors.New("key already exists")
}
s.urls[*key] = *url
return nil
}
```
同样,当从 `load()` 调用 `Set()` 时,也必须做调整:
```go
s.Set(&r.Key, &r.URL)
```
还必须修改 HTTP 处理函数以适应 `URLStore` 上的更改。`Redirect()` 处理函数现在返回 `URLStore` 给出错误的字符串形式:
```go
func Redirect(w http.ResponseWriter, r *http.Request) {
key := r.URL.Path[1:]
var url string
if err := store.Get(&key, &url); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, url, http.StatusFound)
}
```
`Add()` 处理函数也以基本相同的方式修改:
```go
func Add(w http.ResponseWriter, r *http.Request) {
url := r.FormValue("url")
if url == "" {
fmt.Fprint(w, AddForm)
return
}
var key string
if err := store.Put(&url, &key); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)View on GitHub (pinned to 7a54d34d36)
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
Example fix
// before
if err := store.Get(&key, &url); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// after
if err := store.Get(&key, &url); err != nil {
log.Println("get failed for key", key, ":", err)
if err == ErrUnknownKey {
http.NotFound(w, r)
} else {
http.Error(w, "shortener unavailable", http.StatusInternalServerError)
}
return
} Defensive patterns
Strategy: fallback
Validate before calling
// cheap format check before hitting the store: generated keys are short and alphanumeric
var keyRe = regexp.MustCompile("^[a-zA-Z0-9]{1,10}$")
key := r.URL.Path[1:]
if !keyRe.MatchString(key) {
http.NotFound(w, r) // clearly not one of our keys — 404, not 500
return
} Try / catch
// degrade gracefully when the store can't answer
if err := store.Get(&key, &url); err != nil {
log.Println("store.Get:", err)
if errors.Is(err, ErrUnknownKey) {
http.NotFound(w, r)
} else {
http.Redirect(w, r, "/", http.StatusFound) // fall back to home page
}
return
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15).
Data as JSON: /api/errors/e2661af0a6c2ccd4.
Report an issue: GitHub.