**有时服务器应用程序需要在同一URI上提供资源的不同表示形式。** 当然,这可以手动完成,手动检查“接受”请求标头并推送请求的内容形式。但是,随着你的应用管理更多的资源和不同类型的表示形式,这可能会非常痛苦 ,因为你可能需要检查 Accept-Charset, Accept-Encoding,放置一些服务器端优先级,正确处理错误以及进行其他操作。
GO 中有一些Web框架已经添加了实现这样的功能,但是它们没有正确实现:
* 它们根本不处理接受字符集
* 它们根本不处理接受编码
* 它们 不会像RFC所建议的那样发送错误状态代码(不接受406)以及更多...
但是,对我们来说幸运的是,**Iris 始终遵循最佳实践和Web标准。**
基于:
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding
实施于:
* https://github.com/kataras/iris/pull/1316/commits/8ee0de51c593fe0483fbea38117c3c88e065f2ef
## 示例
```
type testdata struct {
Name string `json:"name" xml:"Name"`
Age int `json:"age" xml:"Age"`
}
```
使用 "gzip" 编码算法呈现资源为 application/json 或者 text/xml 或者 application/xml 格式。
* 如果 accept 为空,当客户端的 accept 头包含它们其中的一个
* 或 JSON(第一个声明的)
* 和当客户端的 accept-encoding 头包含"gzip"或为空时。
```
app.Get("/resource", func(ctx iris.Context) {
data := testdata{
Name: "test name",
Age: 26,
}
ctx.Negotiation().JSON().XML().EncodingGzip()
_, err := ctx.Negotiate(data)
if err != nil {
ctx.Writef("%v", err)
}
})
```
**或** 在中间件中定义它们,并在最终处理程序中使用 Negotiate(nil)。
```
ctx.Negotiation().JSON(data).XML(data).Any("content for */*")
ctx.Negotiate(nil)
```
```
app.Get("/resource2", func(ctx iris.Context) {
jsonAndXML := testdata{
Name: "test name",
Age: 26,
}
ctx.Negotiation().
JSON(jsonAndXML).
XML(jsonAndXML).
HTML("<h1>Test Name</h1><h2>Age 26</h2>")
ctx.Negotiate(nil)
})
```
[阅读完整的示例。](https://github.com/kataras/iris/blob/8ee0de51c593fe0483fbea38117c3c88e065f2ef/_examples/http_responsewriter/content-negotiation/main.go#L22)
## 文档
[Context.Negotiation](https://github.com/kataras/iris/blob/8ee0de51c593fe0483fbea38117c3c88e065f2ef/context/context.go#L3342) 方法创建一次,然后返回协商生成器以构建特定内容的服务器端可用优先级内容类型,字符集和编码算法。
```
Context.Negotiation() *context.NegotiationBuilder
```
[Context.Negotiation](https://github.com/kataras/iris/blob/8ee0de51c593fe0483fbea38117c3c88e065f2ef/context/context.go#L3342) 方法用于在同一 URI 上提供资源的不同表示形式。 当没有匹配到任何 mime 类型时候,它返回 `context.ErrContentNotSupported`。
* "v" 可以是单个 [ iris.N](https://github.com/kataras/iris/blob/8ee0de51c593fe0483fbea38117c3c88e065f2ef/context/context.go#L3298-L3309) struct 值。
* "v" 可以是完成了 [context.ContentSelector](https://github.com/kataras/iris/blob/8ee0de51c593fe0483fbea38117c3c88e065f2ef/context/context.go#L3272) 接口的任何值。
* "v" 可以是完成了 [context.ContentNegotiator](https://github.com/kataras/iris/blob/8ee0de51c593fe0483fbea38117c3c88e065f2ef/context/context.go#L3281) 接口的任何值。
* "v" 可以是任意 struct (JSON, JSONP, XML, YAML) 或者 string(TEXT, HTML) 或者 []byte(Markdown, Binary) 或者 任何匹配 mime 类型的 []byte。
* 如果 "v" 是 nil,则将改用 `Context.Negotitation()`构建器的内容,否则, "v" 将覆盖构建器的内容 (服务 mime 类型 仍通过它已注册的, 支持的, mime 列表检索。)
* 设置 mime 类型优先级,通过 [Negotiation().MIME.Text.JSON.XML.HTML....](https://github.com/kataras/iris/blob/8ee0de51c593fe0483fbea38117c3c88e065f2ef/context/context.go#L3500-L3621)
* 通过字符集优先级,通过 [Negotiation().Charset(...).](https://github.com/kataras/iris/blob/8ee0de51c593fe0483fbea38117c3c88e065f2ef/context/context.go#L3640)
* 通过编码算法优先级, [Negotiation().Encoding(...).](hhttps://github.com/kataras/iris/blob/8ee0de51c593fe0483fbea38117c3c88e065f2ef/context/context.go#L3652-L3665)
* 更新 [Negotiation().Accept./Override()/.XML().JSON().Charset(...).Encoding(...)....](https://github.com/kataras/iris/blob/8ee0de51c593fe0483fbea38117c3c88e065f2ef/context/context.go#L3774-L3877) 接受的。
*
```
Context.Negotiate(v interface{}) (int, error)
```