fix(render): improve JsonpJSON content type handling and simplify Context.JSONP

This commit is contained in:
1911860538 2025-11-08 13:35:02 +08:00
parent c3d5a28ed6
commit b7afe5a6af
3 changed files with 22 additions and 14 deletions

View File

@ -1135,13 +1135,10 @@ func (c *Context) SecureJSON(code int, obj any) {
// JSONP serializes the given struct as JSON into the response body.
// It adds padding to response body to request data from a server residing in a different domain than the client.
// It also sets the Content-Type as "application/javascript".
//
// When the callback parameter is empty, it behaves equivalently to Context.JSON.
func (c *Context) JSONP(code int, obj any) {
callback := c.DefaultQuery("callback", "")
if callback == "" {
c.Render(code, render.JSON{Data: obj})
return
}
c.Render(code, render.JsonpJSON{Callback: callback, Data: obj})
c.Render(code, render.JsonpJSON{Callback: c.Query("callback"), Data: obj})
}
// JSON serializes the given struct as JSON into the response body.

View File

@ -115,17 +115,19 @@ func (r SecureJSON) WriteContentType(w http.ResponseWriter) {
// Render (JsonpJSON) marshals the given interface object and writes it and its callback with custom ContentType.
func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
r.WriteContentType(w)
ret, err := json.API.Marshal(r.Data)
if err != nil {
return err
}
if r.Callback == "" {
writeContentType(w, jsonContentType)
_, err = w.Write(ret)
return err
}
r.WriteContentType(w)
callback := template.JSEscapeString(r.Callback)
if _, err = w.Write(bytesconv.StringToBytes(callback)); err != nil {
return err

View File

@ -183,19 +183,28 @@ func TestRenderJsonpJSONError(t *testing.T) {
assert.Equal(t, `write "`+`);`+`" error`, err.Error())
}
func TestRenderJsonpJSONError2(t *testing.T) {
func TestRenderJsonpJSONWithEmptyCallback(t *testing.T) {
w := httptest.NewRecorder()
data := map[string]any{
"foo": "bar",
"num": 42,
"nested": map[string]any{
"key": "value",
},
}
(JsonpJSON{"", data}).WriteContentType(w)
assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
e := (JsonpJSON{"", data}).Render(w)
require.NoError(t, e)
err := (JsonpJSON{Callback: "", Data: data}).Render(w)
assert.JSONEq(t, "{\"foo\":\"bar\"}", w.Body.String())
assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
require.NoError(t, err)
// Verify Content-Type is set to jsonContentType when callback is empty
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
renderData, err := json.API.Marshal(data)
require.NoError(t, err)
// Verify body contains correct JSON data
assert.JSONEq(t, string(renderData), w.Body.String())
}
func TestRenderJsonpJSONFail(t *testing.T) {