Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gateway how to add data head for response body? #3858

Open
eyjian opened this issue Jan 18, 2024 · 6 comments
Open

Gateway how to add data head for response body? #3858

eyjian opened this issue Jan 18, 2024 · 6 comments

Comments

@eyjian
Copy link

eyjian commented Jan 18, 2024

Add:

{"code":0,"data":{ ANY }

for success response body.

Add:

{"code":ERRCODE,"message":"error message"}

for fail response body.

httpx.SetErrorHandlerCtx supports fail response, but httpx.SetOkHandler does not work.

The following approach works with middleware, but is inelegant:

server.Use(wrapResponse)

type responseWriter struct {
	http.ResponseWriter
	statusCode int
	body       bytes.Buffer
}

func (rw *responseWriter) WriteHeader(statusCode int) {
	rw.statusCode = statusCode
	rw.ResponseWriter.WriteHeader(statusCode)
}

func (rw *responseWriter) Write(p []byte) (int, error) {
	return rw.body.Write(p)
}

func (rw *responseWriter) Body() []byte {
	return rw.body.Bytes()
}

// 对响应加上“"code":0,"data":{}”,
// 对于已经包含了“code”的不做任何处理(原因是 grpcErrorHandler 才能处理好)
func wrapResponse(next http.HandlerFunc) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 记录原始响应 writer
		rw := &responseWriter{
			ResponseWriter: w,
			statusCode:     http.StatusOK,
		}

		// 执行下一个中间件或处理函数
		next.ServeHTTP(rw, r)

		// 检查响应状态码
		if rw.statusCode != http.StatusOK {
			return
		}

		// 获取原始响应数据
		var resp map[string]interface{}
		err := json.Unmarshal(rw.Body(), &resp)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// 检查响应是否已经包含 code
		if _, ok := resp["code"]; ok {
			// 如果响应已经包含 code,则直接写回原始响应正文
			w.Header().Set("Content-Type", "application/json")
			w.Write(rw.Body())
			return
		}

		// 包装响应数据
		wrappedResp := map[string]interface{}{
			"code": 0,
			"data": resp,
		}

		// 将包装后的响应数据写回 response  body
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(wrappedResp)
	})
}

type MyResponse struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data,omitempty"`
}

@kevwan @gongluck @kesonan Thanks.

@gongluck
Copy link
Contributor

Reference test cases, maybe you can use

httpx.OkJson(w, wrappedResp)

replace

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(wrappedResp)

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


Reference test cases, maybe you can use

httpx.OkJson(w, wrappedResp)

replace

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(wrappedResp)

@eyjian
Copy link
Author

eyjian commented Jan 19, 2024

httpx.OkJson(w, wrappedResp)

Thanks. I hope to achieve the goal without using "server.Use(wrapResponse)", which is a non-elegant way to implement it.

@kevwan
Copy link
Contributor

kevwan commented Feb 3, 2024

@eyjian problem solved?

@eyjian
Copy link
Author

eyjian commented Feb 3, 2024

@eyjian problem solved?

Thank you, it's a temporary solution, but it's not elegant and not a satisfactory way. In addition, I hope that the gateway will not be unable to start because a certain service is not started. This is unreasonable. Just because a service cannot start, the gateway cannot start. This is a big problem.

The solution is as follows:
https://github.com/eyjian/mooon-gateway/blob/main/main.go

@eyjian eyjian closed this as completed Feb 3, 2024
@eyjian eyjian reopened this Feb 3, 2024
@denganliang
Copy link

same problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants