引言 HTTP状态码是客户端(浏览器)和服务器之间进行通信的基础。当浏览器请求网页时,服务器会返回一个状态码,告诉浏览器请求的网页是否成功、失败或有其他问题。在本文中,将讨论HTTP状态码及使用Nginx做代理模拟常见状态码。
本文分为两部分
HTTP状态码基础介绍
什么是HTTP状态码?
HTTP状态码是指由Web服务器返回给Web浏览器的3位数字代码。它们指示Web服务器在处理请求时发生了什么。它们帮助我们确定请求是否成功,并在请求失败时提供有关错误的详细信息。HTTP状态码由五个类别组成:信息性状态码(1xx)、成功状态码(2xx)、重定向状态码(3xx)、客户端错误状态码(4xx)和服务器错误状态码(5xx)。
信息性状态码
信息性状态码表示请求已经被接收,继续处理。例如,100状态码表示服务器已经接收了请求头,并且客户端应该继续发送请求主体。
成功状态码
成功状态码表示请求已成功被服务器接收、理解、并接受。例如,200状态码表示请求成功,而204状态码表示请求成功,但没有响应主体来返回。201状态码表示服务器成功创建了一个新的资源,并将其URI作为响应返回。
重定向状态码
重定向状态码表示客户端必须采取进一步的措施才能完成请求。例如,301状态码表示请求的资源已永久移动到新的URL地址,并且搜索引擎应该把旧的URL地址从它们的索引中删除。302状态码表示请求的资源已经暂时移动到新的URL地址。
客户端错误状态码
4xx 客户端错误状态码通常由客户端发起的请求有误造成的,常见的状态码有:
- 400 Bad Request:客户端发送的请求有误,服务器无法处理;
- 401 Unauthorized:客户端没有经过身份验证或没有正确的授权信息;
- 403 Forbidden:客户端已经经过身份验证,但没有访问所请求的资源的权限;
- 404 Not Found:客户端请求的资源不存在;
- 405 Method Not Allowed:客户端使用的 HTTP 方法不被允许;
- 408 Request Timeout:客户端在规定的时间内未向服务器发送请求。
服务器错误状态码
- 500 Internal Server Error:服务器在处理请求时发生了未知错误;
- 501 Not Implemented:服务器无法处理客户端的请求,因为请求的功能还没有被实现;
- 502 Bad Gateway:服务器作为网关或代理,从上游服务器收到了无效的响应;
- 503 Service Unavailable:服务器暂时无法处理客户端的请求,一般是由于服务器正在进行维护或过载;
- 504 Gateway Timeout:服务器作为网关或代理,没有在规定的时间内收到上游服务器的响应。
HTTP状态码模拟实战
首先安装Nginx作为网关,代理后端服务器服务,转发我们的请求至相应服务器端口处理。我们主要模拟以下几种常见的状态码 404,500,502,503,504
安装Nginx(Mac版)
命令 brew info nginx 查看本机nginx安装情况
可以看到nginx未安装,缺少依赖包
安装两个依赖包
命令 brew install openssl@1.1
命令 brew install pcre2
使用brew info nginx命令看到依赖包安装完成
依赖包安装完成后,安装Nginx
下图中红框框起来的部分需要注意
我们来构建几个返回状态码的服务请求
package main
import (
"errors"
"fmt"
"log"
"net/http"
"time"
)
// 状态码直接返回部分逻辑
func Service200(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析参数
fmt.Println("Form:", r.Form)
fmt.Println("path:", r.URL.Path)
fmt.Println("scheme", r.URL.Scheme)
fmt.Println(r.Form["url_long"])
for key, val := range r.Form {
fmt.Println("key:", key)
fmt.Println("val:", val)
}
fmt.Fprintf(w, "hello,world!")
}
func Service500(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析参数
for key, val := range r.Form {
fmt.Println("key:", key)
fmt.Println("val:", val)
}
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("internal server error"))
}
func Service502(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析参数
for key, val := range r.Form {
fmt.Println("key:", key)
fmt.Println("val:", val)
}
w.WriteHeader(http.StatusBadGateway)
w.Write([]byte("bad gateway"))
}
func Service503(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析参数
for key, val := range r.Form {
fmt.Println("key:", key)
fmt.Println("val:", val)
}
w.WriteHeader(http.StatusServiceUnavailable)
w.Write([]byte("service unavailable"))
}
func Service504(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析参数
for key, val := range r.Form {
fmt.Println("key:", key)
fmt.Println("val:", val)
}
w.WriteHeader(http.StatusGatewayTimeout)
w.Write([]byte("gateway time out"))
}
func Logic500(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析参数
time.Sleep(20 * time.Second)
if err := OneFunc(); err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("internal server error"))
return
}
w.Write([]byte("ok 200"))
}
func OneFunc() error {
// 具体业务逻辑
// 产生一个error
return errors.New("one error occurred")
}
func Logic502(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析参数
}
func Logic503(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析参数
time.Sleep(10 * time.Second)
w.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprint(w, "Service is temporarily unavailable")
}
func Logic504(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析参数
timeout := time.After(15 * time.Second) //15s超时时间
select {
case <-r.Context().Done():
return
case <-timeout:
w.WriteHeader(http.StatusGatewayTimeout)
fmt.Fprint(w, "Gateway timeout")
}
}
func main() {
http.HandleFunc("/httpcode200", Service200)
http.HandleFunc("/httpcode500", Service500)
http.HandleFunc("/httpcode502", Service502)
http.HandleFunc("/httpcode503", Service503)
http.HandleFunc("/httpcode504", Service504)
http.HandleFunc("/logic500", Logic500)
http.HandleFunc("/logic502", Logic502)
http.HandleFunc("/logic503", Logic503)
http.HandleFunc("/logic504", Logic504)
err := http.ListenAndServe(":9999", nil)
if err != nil {
log.Fatal("ListenAndServe : ", err)
}
}
我们在本地的9999端口,启动后端服务。
服务启动完成之后,我们配置Nginx代理的配置文件(配置文件位置在6.png中) 命令 nginx -s reload 使nginx重新加载配置文件 命令 brew services start/restart/stop nginx 启动/重启/停止 nginx 服务(nginx服务启动在本地的8080端口)
我们先请求一下后端服务器的服务,观察是否正确运行
再通过nginx代理来请求我们后端的服务,可以看到nginx直接将后端服务器的返回信息透传过来嘞
如果我们想让nginx帮我们处理后端返回的状态码,并展示我们自定义的页面信息(如下)
我们需要找到nginx存放静态资源的根目录,如下图
在根目录下添加我们自定义的静态页面
网关配置超时等待时间
超时响应
请求一个不存在的资源,会返回404
总结
HTTP状态码是Web开发中的重要组成部分。它们告诉我们请求是否成功、失败或有其他问题。在本文中,介绍了HTTP状态码的五个类别,我们可以测试我们的应用程序在不同的HTTP状态码下的响应,以确保应用程序对各种情况做出适当的响应。
常见问题解答
- 什么是HTTP状态码?
HTTP状态码是指由Web服务器返回给Web浏览器的3位数字代码。它们指示Web服务器在处理请求时发生了什么。
- HTTP状态码的五个类别是什么?
HTTP状态码由五个类别组成:信息性状态码、成功状态码、重定向状态码、客户端错误状态码和服务器错误状态码。
- HTTP状态码模拟的目的是什么?
HTTP状态码模拟的目的是测试我们的应用程序对不同HTTP状态码的响应。
写在最后
感谢大家的阅读,晴天将继续努力,分享更多有趣且实用的主题,如有错误和纰漏,欢迎给予指正。 更多文章敬请关注作者个人公众号 晴天码字