Golang - символ отображения, а не ascii. Подобно '&', а не '\ 0026'

Это мой тестовый код. Просто создайте простой http-сервер. Затем, генерируя данные json, это значение равно "&". Но результат - это то, чего я не хочу. Результат ниже кода.

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
)

func testFunc(w http.ResponseWriter, r *http.Request) {
    data := make(map[string]string)
    data["key"] = "&"
    bytes, err := json.Marshal(data)
    if err != nil {
        fmt.Fprintln(w, "generator json error")
    } else {
        //print console
        fmt.Println(string(bytes))
        fmt.Println("&")
        //print broswer
        fmt.Fprintln(w, string(bytes))
        fmt.Fprintln(w, "&")
    }
}

func main() {
    http.HandleFunc("/", testFunc)
    err := http.ListenAndServe(":9090", nil)
    if err != nil {
        log.Fatal("ListenAndServe", err)
    }

}

Результат: Браузер Chrome:

{ "ключ": "\ u0026" }

&

Консоль также показывает:

{ "ключ": "\ u0026" }

&

Когда " &" не находится в json, браузер и консоль будут печатать " &".

Ответ 1

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
)

type Search struct {
    Query string `json:"query"`
}

func main() {
    data := &Search{Query: "http://google.com/?q=stackoverflow&ie=UTF-8"}
    responseJSON, _ := JSONMarshal(data, true)
    fmt.Println(string(responseJSON))

}

func JSONMarshal(v interface{}, safeEncoding bool) ([]byte, error) {
    b, err := json.Marshal(v)

    if safeEncoding {
        b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1)
        b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1)
        b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1)
    }
    return b, err
}

Результаты:

JSONMarshal(data, true)
{"query":"http://google.com/?q=stackoverflow&ie=UTF-8"}

JSONMarshal(data, false)
{"query":"http://google.com/?q=stackoverflow\u0026ie=UTF-8"}

Кредиты: https://github.com/clbanning/mxj/blob/master/json.go#L20

Playbook: http://play.golang.org/p/c7M32gICl8

Ответ 2

В Go1.7 добавили новый параметр, чтобы исправить это:

кодирования/JSON: add Encoder.DisableHTMLEscaping Это дает возможность отключить экранирование строк <, > и и в JSON.

Соответствующая функция

func (*Encoder) SetEscapeHTML

Это должно быть применено к Encoder.

enc := json.NewEncoder(os.Stdout)
enc.SetEscapeHTML(false)

Пример модификации stupidbodo: https://play.golang.org/p/HnWGJAjqPA

Ответ 3

Из docs (выделение мной):

Строковые значения кодируются как строки JSON. InvalidUTF8Error будет возвращен, если встречается некорректная последовательность UTF-8. Угловые скобки "<" и " > " экранируются до "\ u003c" и "\ u003e", чтобы некоторые браузеры неправильно интерпретировали вывод JSON как HTML. Амперсанд "&" по той же причине также экранируется "\ u0026".

Видимо, если вы хотите отправить '&' как и вам, вам нужно создать пользовательский маршалер или использовать тип RawMessage следующим образом: http://play.golang.org/p/HKP0eLogQX.