Closed ghost closed 2 years ago
for my local test
$ go run main.go
Response: ''
Response raw: '&{Status:200 OK StatusCode:200 Proto:HTTP/2.0 ProtoMajor:2 ProtoMinor:0 Header:map[Cache-Control:[max-age=0, private, must-revalidate] Cf-Cache-Status:[DYNAMIC] Cf-Ray:[6c1773661c097d0a-LAX] Content-Type:[application/json] Date:[Wed, 22 Dec 2021 06:56:31 GMT] Etag:[W/"0d495ac44aeb780f688f3eb8674fdbfc"] Expect-Ct:[max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"] Gitlab-Lb:[fe-17-lb-gprd] Gitlab-Sv:[localhost] Link:[<https://gitlab.com/api/v4/templates/gitignores?page=2&per_page=20>; rel="next", <https://gitlab.com/api/v4/templates/gitignores?page=1&per_page=20>; rel="first", <https://gitlab.com/api/v4/templates/gitignores?page=10&per_page=20>; rel="last"] Nel:[{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}] Ratelimit-Limit:[2000] Ratelimit-Observed:[1] Ratelimit-Remaining:[1999] Ratelimit-Reset:[1640156251] Ratelimit-Resettime:[Wed, 22 Dec 2021 06:57:31 GMT] Referrer-Policy:[strict-origin-when-cross-origin] Report-To:[{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=%2B%2Fsodq%2FpvR8ELbT%2FxjoW0XuETKakT2TUIYH2gQzVRH6VeKyE%2B%2FCOjN2N0K9SHqaL9Kt3dpB0djL%2FYaiDP7V8kDFol%2BTDSqjBuLkZf%2FPgeN417zgcMEtjVg0pe2Q%3D"}],"group":"cf-nel","max_age":604800}] Server:[cloudflare] Strict-Transport-Security:[max-age=31536000] Vary:[Origin] X-Content-Type-Options:[nosniff] X-Frame-Options:[SAMEORIGIN] X-Next-Page:[2] X-Page:[1] X-Per-Page:[20] X-Prev-Page:[] X-Request-Id:[01FQGETQ3KPJ9KE1TC0M5KX4J8] X-Runtime:[0.020044] X-Total:[191] X-Total-Pages:[10]] Body:0xc0002d29c0 ContentLength:-1 TransferEncoding:[] Close:false Uncompressed:true Trailer:map[] Request:0xc0000f4000 TLS:0xc00031e0b0}'
response status: 200 OK
body [{"key":"Actionscript","name":"Actionscript"},{"key":"Ada","name":"Ada"},{"key":"Agda","name":"Agda"},{"key":"Android","name":"Android"},{"key":"AppEngine","name":"AppEngine"},{"key":"AppceleratorTitanium","name":"AppceleratorTitanium"},{"key":"ArchLinuxPackages","name":"ArchLinuxPackages"},{"key":"Autotools","name":"Autotools"},{"key":"C","name":"C"},{"key":"C++","name":"C++"},{"key":"CFWheels","name":"CFWheels"},{"key":"CMake","name":"CMake"},{"key":"CUDA","name":"CUDA"},{"key":"CakePHP","name":"CakePHP"},{"key":"ChefCookbook","name":"ChefCookbook"},{"key":"Clojure","name":"Clojure"},{"key":"CodeIgniter","name":"CodeIgniter"},{"key":"CommonLisp","name":"CommonLisp"},{"key":"Composer","name":"Composer"},{"key":"Concrete5","name":"Concrete5"}]
Unlike many projects, the Go project does not use GitHub Issues for general discussion or asking questions. GitHub Issues are used for tracking bugs and proposals only.
For questions please refer to https://github.com/golang/go/wiki/Questions
How do you proof it not a bug. and i can 100% reproduce it.
发现问题比解决问题更难。为什么你一关了之?你知不知道为了构建最小可复现代码示例,我花了多少时间来研究? 我认为这是一个bug,原因如下:
既然知道不对,为什么不让指出来?
The real expected looks very similar with fmt.Sprintf("%#v", var)
but with json format
{Status:"422 Unprocessable Entity", StatusCode:422, Proto:"HTTP/2.0", ProtoMajor:2, ProtoMinor:0, Header:http.Header{"Access-Control-Allow-Origin":[]string{"*"}, "Access-Control-Expose-Headers":[]string{"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset"}, "Content-Length":[]string{"236"}, "Content-Security-Policy":[]string{"default-src 'none'"}, "Content-Type":[]string{"application/json; charset=utf-8"}, "Date":[]string{"Wed, 22 Dec 2021 09:01:35 GMT"}, "Referrer-Policy":[]string{"origin-when-cross-origin, strict-origin-when-cross-origin"}, "Server":[]string{"GitHub.com"}, "Strict-Transport-Security":[]string{"max-age=31536000; includeSubdomains; preload"}, "Vary":[]string{"Accept-Encoding, Accept, X-Requested-With"}, "X-Accepted-Oauth-Scopes":[]string{""}, "X-Content-Type-Options":[]string{"nosniff"}, "X-Frame-Options":[]string{"deny"}, "X-Github-Media-Type":[]string{"github.v3; format=json"}, "X-Github-Request-Id":[]string{"2270:3288:315B53:33D24D:61C2E96E"}, "X-Oauth-Scopes":[]string{"repo"}, "X-Ratelimit-Limit":[]string{"5000"}, "X-Ratelimit-Remaining":[]string{"4997"}, "X-Ratelimit-Reset":[]string{"1640167034"}, "X-Ratelimit-Resource":[]string{"core"}, "X-Ratelimit-Used":[]string{"3"}, "X-Xss-Protection":[]string{"0"}}, Body:http.http2transportResponseBody{cs:(*http.http2clientStream)(0xc000208300)}, ContentLength:236, TransferEncoding:[]string(nil), Close:false, Uncompressed:false, Trailer:http.Header(nil), Request:(*http.Request)(0xc0001ce000), TLS:(*tls.ConnectionState)(0xc0003aa0b0)}
@cnmade json.Marshal都报错了,还扯后面的。 panic: json: unsupported type: func() (io.ReadCloser, error)
goroutine 1 [running]: main.main() make/main.go:24 +0x3ef
// Click here and start typing.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
hc, err := http.NewRequest("GET", "https://gitlab.com/api/v4/templates/gitignores", bytes.NewBuffer([]byte{}))
if err != nil {
panic(err)
}
clt := http.Client{}
response, err := clt.Do(hc)
if err != nil {
panic(err)
}
jsonStr, err := json.Marshal(response)
if err != nil {
panic(err) // 这里都出错了
}
fmt.Printf("Response: '%+v' \n", string(jsonStr))
fmt.Printf("Response raw: '%+v'\n", response)
bodyAll, err := ioutil.ReadAll(response.Body)
fmt.Println("response status: " + response.Status)
fmt.Println("body " + string(bodyAll))
}
for any one who want to make json.Marshal really work, you may want to take: https://github.com/cnmade/goencode/blob/v1.17/json/encode.go
and the example work code like
package main
import (
"bytes"
"fmt"
"github.com/cnmade/goencode/json"
"io/ioutil"
"net/http"
)
func main() {
hc, err := http.NewRequest("GET", "https://gitlab.com/api/v4/templates/gitignores", bytes.NewBuffer([]byte{}))
if err != nil {
panic(err)
}
clt := http.Client{}
response, err := clt.Do(hc)
json.UnsupportedBehaviour = json.UnsupportedBehaviourWithNull
jsonStr, err := json.Marshal(response)
if err != nil {
fmt.Printf("error: %#v\n", err.Error())
panic(err)
}
fmt.Printf("Response: '%+v' \n", string(jsonStr))
fmt.Printf("Response raw: '%+v'\n", response)
bodyAll, err := ioutil.ReadAll(response.Body)
fmt.Println("response status: " + response.Status)
fmt.Println("body " + string(bodyAll))
}
After modify, json.Marshal will not throw Error, but encoding other valid Fields.
@orestonce 问题我知道,但go不处理,就离谱。 我提问题的意思是,这里有改进空间,可以让用户自己决定,是忽略解析不了的地方。 还是说直接报错,还是替代成其它固定的结构,或者是用fmt.Sprintf处理一下。 具体修改的代码见:
func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) {
if UnsupportedBehaviour != UnsupportedBehaviourWithError {
switch UnsupportedBehaviour {
case UnsupportedBehaviourWithSprintf:
e.WriteString(fmt.Sprintf("'%+v'", v))
case UnsupportedBehaviourWithNone:
e.WriteString(UnsupportedBehaviourWithNone)
case UnsupportedBehaviourWithNull:
e.WriteString(UnsupportedBehaviourWithNull)
default:
e.error(&UnsupportedTypeError{v.Type()})
}
return
}
e.error(&UnsupportedTypeError{v.Type()})
}
你要相信一点,敢提问题,那肯定是有哪里不对,你能想到的,我也想到了。
@cnmade 你的这种做法只是给json做了另一方面的改动,并无更好的优化效果。 我认为 json.Marshal报错就是json无法序列化对应的数据或者强行序列化后无法让另外的json解析器完全读出刚才传入的数据。所以不支持的类型直接报序列化错误我觉得是没毛病的。 至于fmt.Sprintf则没有地方需要反序列化,则可以填充处理即可。
对于无法序列化/反序列化的字段,明确在代码里使用 json:- 告知json代码忽略该字段,是有必要的。
@orestonce 问题我知道,但go不处理,就离谱。 我提问题的意思是,这里有改进空间,可以让用户自己决定,是忽略解析不了的地方。 还是说直接报错,还是替代成其它固定的结构,或者是用fmt.Sprintf处理一下。 具体修改的代码见:
func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) { if UnsupportedBehaviour != UnsupportedBehaviourWithError { switch UnsupportedBehaviour { case UnsupportedBehaviourWithSprintf: e.WriteString(fmt.Sprintf("'%+v'", v)) case UnsupportedBehaviourWithNone: e.WriteString(UnsupportedBehaviourWithNone) case UnsupportedBehaviourWithNull: e.WriteString(UnsupportedBehaviourWithNull) default: e.error(&UnsupportedTypeError{v.Type()}) } return } e.error(&UnsupportedTypeError{v.Type()}) }
你要相信一点,敢提问题,那肯定是有哪里不对,你能想到的,我也想到了。
你所说的不是标准库应该做的,标准库要做的就是要返回错误码,由用户来决定是要怎么处理error,你所做的是要你自己去处理或者借助第三方库去处理,正如java所做的
对于无法序列化/反序列化的字段,明确在代码里使用 json:- 告知json代码忽略该字段,是有必要的。
本就该如此.response
结构体内的Body
的类型为io.ReadCloser
本就不属于常规类型.譬如还有net.Conn
bufio.Reader
context.Context
甚至于func()
等,这些非常规类型的导出就该使用json:-
去屏蔽掉.我完全看不出楼主的槽点.=_=
@orestonce 问题我知道,但go不处理,就离谱。 我提问题的意思是,这里有改进空间,可以让用户自己决定,是忽略解析不了的地方。 还是说直接报错,还是替代成其它固定的结构,或者是用fmt.Sprintf处理一下。 具体修改的代码见:
func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) { if UnsupportedBehaviour != UnsupportedBehaviourWithError { switch UnsupportedBehaviour { case UnsupportedBehaviourWithSprintf: e.WriteString(fmt.Sprintf("'%+v'", v)) case UnsupportedBehaviourWithNone: e.WriteString(UnsupportedBehaviourWithNone) case UnsupportedBehaviourWithNull: e.WriteString(UnsupportedBehaviourWithNull) default: e.error(&UnsupportedTypeError{v.Type()}) } return } e.error(&UnsupportedTypeError{v.Type()}) }
你要相信一点,敢提问题,那肯定是有哪里不对,你能想到的,我也想到了。
你所说的不是标准库应该做的,标准库要做的就是要返回错误码,由用户来决定是要怎么处理error,你所做的是要你自己去处理或者借助第三方库去处理,正如java所做的
完全可以自己在封装一层,通过反射区分出基础类型,剔除掉非基础类型的字段再做导出.
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
What did you expect to see?
fmt.Printf("Response: '%+v' \n", string(jsonStr))
return the formatted JSON string.What did you see instead?
fmt.Printf("Response: '%+v' \n", string(jsonStr))
Empty string
For compare, With Java , we can easy to dump all response object into a JSON String