mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-14 12:12:12 +08:00
Merge 22ae924b10f959da8fcd360b84281553f03f633a into c3d1092b3b48addf6f9cd00fe274ec3bd14650eb
This commit is contained in:
commit
823fb36ba1
60
context.go
60
context.go
@ -1280,32 +1280,64 @@ type Negotiate struct {
|
|||||||
TOMLData any
|
TOMLData any
|
||||||
}
|
}
|
||||||
|
|
||||||
// Negotiate calls different Render according to acceptable Accept format.
|
func NewNegotiate(offered []string) Negotiate {
|
||||||
func (c *Context) Negotiate(code int, config Negotiate) {
|
return Negotiate{Offered: offered}
|
||||||
switch c.NegotiateFormat(config.Offered...) {
|
}
|
||||||
case binding.MIMEJSON:
|
func (receiver Negotiate) WithData(data any) Negotiate {
|
||||||
|
receiver.Data = data
|
||||||
|
return receiver
|
||||||
|
}
|
||||||
|
|
||||||
|
// NegotiationRenderFunc is responsible for rendering data in a specific format.
|
||||||
|
type NegotiationRenderFunc func(status int, config Negotiate, c *Context)
|
||||||
|
|
||||||
|
func AddNegotiationRenderMapping(mimeType string, binding NegotiationRenderFunc) {
|
||||||
|
negotiationRenderMappings[mimeType] = binding
|
||||||
|
}
|
||||||
|
|
||||||
|
// All predefined negotiationRenderMappings - associate a content type
|
||||||
|
// with a NegotiationRenderFunc, which is responsible for rendering
|
||||||
|
// data in a specific format.
|
||||||
|
var negotiationRenderMappings = map[string]NegotiationRenderFunc{
|
||||||
|
binding.MIMEJSON: func(code int, config Negotiate, c *Context) {
|
||||||
data := chooseData(config.JSONData, config.Data)
|
data := chooseData(config.JSONData, config.Data)
|
||||||
c.JSON(code, data)
|
c.JSON(code, data)
|
||||||
|
},
|
||||||
case binding.MIMEHTML:
|
binding.MIMEHTML: func(code int, config Negotiate, c *Context) {
|
||||||
data := chooseData(config.HTMLData, config.Data)
|
data := chooseData(config.HTMLData, config.Data)
|
||||||
c.HTML(code, config.HTMLName, data)
|
c.HTML(code, config.HTMLName, data)
|
||||||
|
},
|
||||||
case binding.MIMEXML:
|
binding.MIMEXML: func(code int, config Negotiate, c *Context) {
|
||||||
data := chooseData(config.XMLData, config.Data)
|
data := chooseData(config.XMLData, config.Data)
|
||||||
c.XML(code, data)
|
c.XML(code, data)
|
||||||
|
},
|
||||||
case binding.MIMEYAML, binding.MIMEYAML2:
|
binding.MIMEYAML: func(code int, config Negotiate, c *Context) {
|
||||||
data := chooseData(config.YAMLData, config.Data)
|
data := chooseData(config.YAMLData, config.Data)
|
||||||
c.YAML(code, data)
|
c.YAML(code, data)
|
||||||
|
},
|
||||||
case binding.MIMETOML:
|
binding.MIMEYAML2: func(code int, config Negotiate, c *Context) {
|
||||||
|
data := chooseData(config.YAMLData, config.Data)
|
||||||
|
c.YAML(code, data)
|
||||||
|
},
|
||||||
|
binding.MIMETOML: func(code int, config Negotiate, c *Context) {
|
||||||
data := chooseData(config.TOMLData, config.Data)
|
data := chooseData(config.TOMLData, config.Data)
|
||||||
c.TOML(code, data)
|
c.TOML(code, data)
|
||||||
|
},
|
||||||
|
binding.MIMEPROTOBUF: func(code int, config Negotiate, c *Context) {
|
||||||
|
c.ProtoBuf(code, config.Data)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
// Negotiate calls different Render according to acceptable Accept format.
|
||||||
c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) //nolint: errcheck
|
func (c *Context) Negotiate(code int, config Negotiate) {
|
||||||
|
|
||||||
|
accepted := c.NegotiateFormat(config.Offered...)
|
||||||
|
if fn, ok := negotiationRenderMappings[accepted]; ok {
|
||||||
|
fn(code, config, c)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) //nolint: errcheck
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NegotiateFormat returns an acceptable Accept format.
|
// NegotiateFormat returns an acceptable Accept format.
|
||||||
|
@ -1615,6 +1615,44 @@ func TestContextNegotiationWithHTML(t *testing.T) {
|
|||||||
assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContextNegotiationWithProto(t *testing.T) {
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
c, _ := CreateTestContext(w)
|
||||||
|
c.Request, _ = http.NewRequest(http.MethodPost, "", nil)
|
||||||
|
|
||||||
|
c.Negotiate(http.StatusOK, Negotiate{
|
||||||
|
Offered: []string{binding.MIMEPROTOBUF},
|
||||||
|
Data: &testdata.Test{},
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
assert.Equal(t, 0, w.Body.Len())
|
||||||
|
assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContextNegotiationWithCustom(t *testing.T) {
|
||||||
|
|
||||||
|
contentType := "application/whatever"
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
c, _ := CreateTestContext(w)
|
||||||
|
c.Request, _ = http.NewRequest(http.MethodPost, "", nil)
|
||||||
|
|
||||||
|
AddNegotiationRenderMapping(contentType, func(status int, config Negotiate, c *Context) {
|
||||||
|
data := config.Data.([]byte)
|
||||||
|
c.Data(status, contentType, data)
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Negotiate(http.StatusOK, Negotiate{
|
||||||
|
Offered: []string{contentType},
|
||||||
|
Data: []byte("Hello World"),
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
assert.Equal(t, "Hello World", w.Body.String())
|
||||||
|
assert.Equal(t, contentType, w.Header().Get("Content-Type"))
|
||||||
|
}
|
||||||
|
|
||||||
func TestContextNegotiationNotSupport(t *testing.T) {
|
func TestContextNegotiationNotSupport(t *testing.T) {
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
c, _ := CreateTestContext(w)
|
c, _ := CreateTestContext(w)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user