HTTP 状态码
这篇文章主要来讲讲 HTTP 状态码这个东西,因为在工作中,经常出现 429、404、503... 这些数字,但是我看不懂...
所以写这篇文章用于学习一些常见的状态码,想表示的是什么
先写一份文件用于 HTTP 请求吧,这里使用 Go 语言进行编写,因为路由非常方便
请求程序
cat > http_status.go << 'EOF'
package main
import (
"fmt"
"log"
"net/http"
"strings"
"time"
)
func main() {
// 200
http.HandleFunc("/200", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, "200 OK")
})
// 204
http.HandleFunc("/204", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Demo", "204-has-header-but-no-body")
w.WriteHeader(http.StatusNoContent)
})
// 206
http.HandleFunc("/206", func(w http.ResponseWriter, r *http.Request) {
content := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("Accept-Ranges", "bytes")
http.ServeContent(
w,
r,
"demo.txt",
time.Now(),
strings.NewReader(content),
)
})
// 最终重定向目标
http.HandleFunc("/target", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "method=%s\n", r.Method)
})
// 301
http.HandleFunc("/301", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/target", http.StatusMovedPermanently)
})
// 302
http.HandleFunc("/302", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/target", http.StatusFound)
})
// 303
http.HandleFunc("/303", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/target", http.StatusSeeOther)
})
// 307
http.HandleFunc("/307", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/target", http.StatusTemporaryRedirect)
})
// 304
http.HandleFunc("/304", func(w http.ResponseWriter, r *http.Request) {
const etag = `"article-v1"`
w.Header().Set("ETag", etag)
if r.Header.Get("If-None-Match") == etag {
w.WriteHeader(http.StatusNotModified)
return
}
fmt.Fprintln(w, "This is cached content.")
})
// 400
http.HandleFunc("/400", func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "bad request", http.StatusBadRequest)
})
// 401
http.HandleFunc("/401", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("WWW-Authenticate", `Basic realm="HTTP Demo"`)
http.Error(w, "authentication required", http.StatusUnauthorized)
})
// 402
http.HandleFunc("/402", func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "payment required", http.StatusPaymentRequired)
})
// 403
http.HandleFunc("/403", func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "forbidden", http.StatusForbidden)
})
// 404
http.HandleFunc("/404", func(w http.ResponseWriter, r *http.Request) {
http.NotFound(w, r)
})
// 500
http.HandleFunc("/500", func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "internal server error", http.StatusInternalServerError)
})
// 501
http.HandleFunc("/501", func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "not implemented", http.StatusNotImplemented)
})
// 503
http.HandleFunc("/503", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Retry-After", "60")
http.Error(w, "service unavailable", http.StatusServiceUnavailable)
})
log.Println("HTTP demo server listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
EOF
go run http_status.go
# 导入环境变量
export SERVER_IP=xx.xx.xx.xx
# 输出 IP
echo $SERVER_IP
信息响应( 1xx )
1xx 状态码好像没有什么常见的,就跳过了
成功响应( 2xx )
200 OK
200 状态码表示 请求成功,常见于 HTTP 的请求,比如 GET、PUT、POST 等方法
curl -v "http://${SERVER_IP}:8080/200"

204 No Content
204 状态码表示服务器成功处理了请求,但不需要返回响应正文
curl -i "http://${SERVER_IP}:8080/204"

206 Partial Content
这里我们通过两种方式请求 206 这个路由,返回的结果非常的直观
- 第一个请求,正常返回完整的资源,但是并没有体现出 206 这个状态码
- 第二个请求,我们通过 Range 请求头表示"只要第 0 到第 9 个字节"
客户端通过 Range 请求资源的,一部分;然后服务器成功返回指定范围,所以返回状态码是 206 Partial Content
bash curl -i -H 'Range: bytes=0-9' "http://${SERVER_IP}:8080/206"
重定向响应( 3xx )
301 Moved Permanently
301 状态码表示 永久重定向,也就是当前请求的资源已经永久移动到了另一个地址
curl -i "http://${SERVER_IP}:8080/301"
这里可以看到 Location ,表示这个资源已经移动到了 /target

-L 参数
curl -i -L "http://${SERVER_IP}:8080/301"
这时候整个过程就变成了 访问 /301 ,发现重定向到了 /target,然后跟随到 /target,响应成功,返回 200 OK

302 Found
302 表示 临时重定向
curl -i "http://${SERVER_IP}:8080/302"
同样可以看到 Location 以及 /target,它和 301 其实非常相似,唯一的不同是,302 是临时性的重定向

当然,同样可以通过 -L 自动跟随
curl -i -L "http://${SERVER_IP}:8080/302"

303 See Other
303 也是一种重定向,但是它有一个比较明确的意思:当前请求已经处理,接下来使用 GET 请求访问 Location 指定的资源
-d 'xx=xx' 表示发送 POST 数据,数据为 'xx=xx'
curl -i -L -d 'name=ray' "http://${SERVER_IP}:8080/303"
可以看到,我们 使用 POST 发送数据后,响应为 303,并且重定向到了 /target,然后自动跟随重定向,响应 200 OK

304 Not Modified
304 表示 资源没有发生修改,这个状态码和前面的重定向不太一样,它主要用于 HTTP 缓存,表示客户端已经有资源了,服务器只需要告诉客户端资源有没有变化,没有变化就继续使用缓存,避免重复传输资源
根据响应我们可以看到 ETag 以及一句话 This is cached content.;ETag 可以当作这个资源的版本标识,客户端拿到资源以后,可以把资源和它的 ETag 一起缓存下来,下一次再访问的时候,客户端可以告诉服务器,当前已经有 ETag 这个版本了,如果资源一致,就不需要重复发资源给我了
curl -i "http://${SERVER_IP}:8080/304"
通过 If-None-Match 请求头进行条件判断,当客户端、服务端发现版本一致,就返回 304 Not Modified
curl -i -H 'If-None-Match: "article-v1"' "http://${SERVER_IP}:8080/304"

307 Temporary Redirect
307 也表示 临时重定向,但是与 303 不太一样,它重定向之后必须保留原来的 HTTP Method 和请求体
curl -i "http://${SERVER_IP}:8080/307"
使用 POST 请求
curl -i -L -d 'name=ray' "http://${SERVER_IP}:8080/307"
可以看到 method=POST,这是与 303 很明显的区别

- 303 → 明确让客户端使用 GET 去访问另一个资源
- 307 → 临时换个地址,但是原来的请求方法不能变
客户端错误响应( 4xx )
4xx 表示客户端发送的请求存在问题,这里的"客户端问题"范围比较大,比如:
- 请求格式错误
- 没有进行身份认证
- 没有权限
- 请求的资源不存在
- 请求过于频繁
这些情况都可能返回 4xx
400 Bad Request
400 表示 服务器认为客户端发送的请求存在问题,无法按照预期进行处理
curl -i "http://${SERVER_IP}:8080/400"

{
"name": "ray"
}
但客户端发送了一个错误的 JSON:
{
"name":
}
服务器解析失败,就可能返回 400 Bad Request
401 Unauthorized
401 表示 当前请求需要进行身份认证,或者提供的认证信息无效
curl -i "http://${SERVER_IP}:8080/401"
可以看到 401 Unauthorized 响应以及 WWW-Authenticate,它用于告诉客户端应该使用什么认证方式,比如这里是 Basic 表示使用 用户名密码;如果是 Bearer 则是 JWT Token 之类的

402 Payment Required
402 最初是为未来的数字支付系统预留的状态码,目前并没有一个统一、标准化的实际使用方式,但一些 Web API 会自己使用 402 Payment Required,表示"需要付款";比如 余额不足、套餐到期等...
curl -i "http://${SERVER_IP}:8080/402"

403 Forbidden
403 表示 服务器接受客户端的请求,但拒绝执行,一般就是 权限不足 的问题
curl -i "http://${SERVER_IP}:8080/403"

404 Not Found
404 应该是平时见得最多的 HTTP 状态码之一,表示 服务器找不到客户端请求的资源
curl -i "http://${SERVER_IP}:8080/404"

429 Too Many Requests
429 在调用 API 的时候也比较常见,它表示 客户端在一段时间内发送了太多请求,被服务器限流了
curl -i "http://${SERVER_IP}:8080/429"
这里可以看到一个参数 Retry-After: 10 表示 可以等待 10 秒之后再尝试请求

它和 5xx 这种服务端错误是不同的,429 并不一定发生了故障,可能只是主动拒绝过多的请求罢了
服务端错误响应( 5xx )
5xx 表示 服务器已经接收到了请求,但是服务器在处理请求的过程中出现了问题
500 Internal Server Error
500 表示 服务器内部发生错误,导致请求无法正常完成
curl -i "http://${SERVER_IP}:8080/500"

501 Not Implemented
501 表示 服务器不支持完成当前请求所需要的功能
curl -i "http://${SERVER_IP}:8080/501"

- 500 表示 我实现了这个功能,但是服务器处理有问题导致错误
- 501 表示 我没有实现这个功能
## 502 Bad Gateway
502 表示 网关或代理从上游服务器收到了无效响应,这里就不用代码展示了,看个真实的响应吧;也就是上游给的响应是有问题的,然后进行了拦截
## 503 Service Unavailable 503 表示 服务器当前暂时无法处理请求
bash curl -i "http://${SERVER_IP}:8080/503"可以看到一个熟悉的参数 Retry-After: 60,表示当前暂时无法提供服务,可以在 60 秒后尝试 503 常见于 服务器正在维护、服务暂时不可用、服务器过载、上游服务暂时不可用等
与 500 不同,503 表示的是 服务端没有能力处理而不是处理有问题
504 Gateway Timeout
504 表示 网关或代理等待上游服务器响应超时
curl -i "http://${SERVER_IP}:8080/504"

总结
当然,这篇教程并不是非常的规范,因为使用的路由都是这些状态码,并且有些输出可能看不出这些响应具体想表达什么,以及可能不经常使用会忘记
但我认为,有印象就足够了
愿诸君顺遂