Negotiation
内容协商
MIME types
我们常用的数据格式:
const ( MIMEApplicationJSON = "application/json" MIMEApplicationJSONCharsetUTF8 = "application/json; charset=UTF-8" MIMEApplicationJavaScript = "application/javascript" MIMEApplicationJavaScriptCharsetUTF8 = "application/javascript; charset=UTF-8" MIMEApplicationXML = "application/xml" MIMEApplicationXMLCharsetUTF8 = "application/xml; charset=UTF-8" MIMETextXML = "text/xml" MIMETextXMLCharsetUTF8 = "text/xml; charset=UTF-8" MIMEApplicationForm = "application/x-www-form-urlencoded" MIMEApplicationProtobuf = "application/protobuf" MIMEApplicationMsgpack = "application/msgpack" MIMETextHTML = "text/html" MIMETextHTMLCharsetUTF8 = "text/html; charset=UTF-8" MIMETextPlain = "text/plain" MIMETextPlainCharsetUTF8 = "text/plain; charset=UTF-8" MIMEMultipartForm = "multipart/form-data" MIMEOctetStream = "application/octet-stream")Headers
一些常用的包头名称:
const ( HeaderAccept = "Accept" HeaderAcceptCharset = "Accept-Charset" HeaderAcceptEncoding = "Accept-Encoding" HeaderAcceptLanguage = "Accept-Language" // HeaderAllow is the name of the "Allow" header field used to list the set of methods // advertised as supported by the target resource. Returning an Allow header is mandatory // for status 405 (method not found) and useful for the OPTIONS method in responses. // See RFC 7231: https://datatracker.ietf.org/doc/html/rfc7231#section-7.4.1 HeaderAllow = "Allow" HeaderAuthorization = "Authorization" HeaderContentDisposition = "Content-Disposition" HeaderContentEncoding = "Content-Encoding" HeaderContentLength = "Content-Length" HeaderContentType = "Content-Type" HeaderCookie = "Cookie" HeaderSetCookie = "Set-Cookie" HeaderIfModifiedSince = "If-Modified-Since" HeaderLastModified = "Last-Modified" HeaderLocation = "Location" HeaderUpgrade = "Upgrade" HeaderVary = "Vary" HeaderWWWAuthenticate = "WWW-Authenticate" HeaderXForwardedFor = "X-Forwarded-For" HeaderXForwardedProto = "X-Forwarded-Proto" HeaderXForwardedProtocol = "X-Forwarded-Protocol" HeaderXForwardedSsl = "X-Forwarded-Ssl" HeaderXUrlScheme = "X-Url-Scheme" HeaderXHTTPMethodOverride = "X-HTTP-Method-Override" HeaderXRealIP = "X-Real-IP" HeaderXRequestID = "X-Request-ID" HeaderXRequestedWith = "X-Requested-With" HeaderServer = "Server" HeaderOrigin = "Origin" HeaderCacheControl = "Cache-Control" HeaderConnection = "Connection" // Access control HeaderAccessControlRequestMethod = "Access-Control-Request-Method" HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers" HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin" HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods" HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers" HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials" HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers" HeaderAccessControlMaxAge = "Access-Control-Max-Age" // Security HeaderStrictTransportSecurity = "Strict-Transport-Security" HeaderXContentTypeOptions = "X-Content-Type-Config" HeaderXXSSProtection = "X-XSS-Protection" HeaderXFrameOptions = "X-Frame-Config" HeaderContentSecurityPolicy = "Content-Security-Policy" HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only" HeaderXCSRFToken = "X-CSRF-Token" HeaderReferrerPolicy = "Referrer-Policy")type Negotiator
内容协商结构体
type Negotiator struct { // 缓存容量,当协商报头相同时我们复用解析结果的。 capacity int // 有些时候,解析出来的 Accept 并不是 W3C 所定义的 // 标准的值,我们通过该函数将其重写成标准格式的值。 onParse func(*Accept)}一个 HTTP 请求的内容协商工具,根据下面的报头来处理协商的:
- Accept,客户端可以处理的内容类型,这种内容类型用 MIME 类型来表示;
- Accept-Charset,客户端可以处理的字符集类型,比如
utf-8或iso-8859-1等; - Accept-Encoding,客户端提交的能够理解的内容编码方式,通常是某种压缩算法;
- Accept-Language,客户端声明它可以理解的自然语言,比如
zh等。
func NewNegotiator
func NewNegotiator(capacity int, onParse func(*Accept)) *Negotiator创建内容协商工具。
func (*Negotiator) Slice
func (n *Negotiator) Slice(header string) AcceptSlice解析 HTTP 的 Accept(-Charset|-Encoding|-Language) 报头,返回一个 AcceptSlice 实例, 该结果是根据值的类型和权重因子按照降序排列的,如果类型一致且权重一致,则使用出场的先后顺序排列。
我们可以查看标准:https://www.rfc-editor.org/rfc/rfc9110.html#name-accept
func (*Negotiator) Charset
func (n *Negotiator) Charset(r *http.Request, charsets ...string) string解析报头 Accept-Charset 并从给出字符集类型列表 charsets 中返回权重最高的,如果没有匹配的值,则返回空字符串。
func (*Negotiator) Encoding
func (n *Negotiator) Encoding(r *http.Request, encodings ...string) string解析报头 Accept-Encoding 并从给出内容编码方式列表 encodings 中返回权重最高的,如果没有匹配的值,则返回空字符串。
func (*Negotiator) Language
func (n *Negotiator) Language(r *http.Request, languages ...string) string解析报头 Accept-Language 并从给出语言列表 languages 中返回权重最高的,如果没有匹配的值,则返回空字符串。
func (*Negotiator) Type
func (n *Negotiator) Type(r *http.Request, types ...string) string解析报头 Accept 并从给出内容类型列表 types 中返回权重最高的,如果没有匹配的值,则返回空字符串。
其中,给出的参数 types 的值可以是标准的媒体类型(如 application/json),也可以是扩展名(如 json、xml 等)。
func (*Negotiator) Accepts
func (n *Negotiator) Accepts(header string, ctypes ...string) string解析报头 header 并从给出参数列表 ctypes 中返回权重最高的,如果没有匹配的值,则返回空字符串。
该方法属于上面 4 个方法的合并版本,但是与方法 Negotiator#Type 稍有区别,就是不支持通过扩展名来判断内容类型。
type Accept
type Accept struct { Type string Subtype string Quality float64 Extensions map[string]any}表示解析后的 Accept(-Charset|-Encoding|-Language) 这些报头的单元值。
type AcceptSlice
type AcceptSlice []Accept表示解析后的 Accept(-Charset|-Encoding|-Language) 这些报头的值,是有 Accept 结构切片。
func (AcceptSlice) Len()
func (as AcceptSlice) Len() int实现了 sort.Interface 接口的 Len() 方法。
func (AcceptSlice) Less
func (as AcceptSlice) Less(i, j int) bool实现了 sort.Interface 接口的 Less() 方法,是元素按优先级递减的顺序进行排序。
func (AcceptSlice) Swap
func (as AcceptSlice) Swap(i, j int)实现了 sort.Interface 接口的 Swap() 方法。
func (AcceptSlice) Negotiate
func (as AcceptSlice) Negotiate(ctypes ...string) (string, int, error)从切片中返回能够被客户端接受的类型,如果没有找到类型,则返回空字符串。
func (AcceptSlice) Accepts
func (as AcceptSlice) Accepts(ctype string) bool如果提供的类型 ctype 能够被客户端接受,就返回 true,相反就返回 false。