英文:
Golang ServeHTTP make proxy error EOF on POST request
问题
我正在使用gin和ServeHTTP开发代理服务器。实际上,GET和OPTIONS请求都能正常工作。但是当我尝试发送多个POST请求时,每两个请求中就会出现EOF错误。
我已经测试过在没有代理服务的情况下重复发送请求,结果是正常工作的,所以问题应该出在我的代码中。
编辑:
- 我已经使用https://ptsv2.com/测试了POST代理,并且所有请求的响应都返回200状态码。
// main.go
package main
import (
"fmt"
"../pkg/api"
)
func main() {
fmt.Println("Starting server")
api.InitServer()
}
// routes.go
package api
import (
"github.com/gin-gonic/gin"
)
const serviceUrl = "http://localhost:8732"
func InitServer() {
router := gin.Default()
defineRoutes(router)
router.Run()
}
func defineRoutes(router *gin.Engine) {
router.GET("/ping", Ping)
router.POST("/*any", Proxy(serviceUrl))
}
// controller.go
package api
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
"github.com/gin-gonic/gin"
)
type transport struct {
http.RoundTripper
}
func (t *transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
resp, err = t.RoundTripper.RoundTrip(req)
if err != nil {
// 在这里出现EOF错误
return nil, err
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
err = resp.Body.Close()
if err != nil {
return nil, err
}
b = bytes.Replace(b, []byte("server"), []byte("schmerver"), -1)
body := ioutil.NopCloser(bytes.NewReader(b))
response := resp
response.Body = body
response.ContentLength = int64(len(b))
response.Header.Set("Content-Length", strconv.Itoa(len(b)))
response.Header.Set("Access-Control-Allow-Origin", "*")
return response, nil
}
func Proxy(targetUrl string) gin.HandlerFunc {
fn := func(c *gin.Context) {
remote, err := url.Parse(targetUrl)
if err != nil {
panic(err)
}
proxy := httputil.NewSingleHostReverseProxy(remote)
proxy.Director = func(req *http.Request) {
req.Header = c.Request.Header
req.Host = remote.Host
req.URL.Scheme = remote.Scheme
req.URL.Host = remote.Host
req.Close = true // True / False same result
}
proxy.Transport = &transport{http.DefaultTransport}
proxy.ServeHTTP(c.Writer, c.Request)
}
return fn
}
```
<details>
<summary>英文:</summary>
I’m working on proxy server with gin and ServeHTTP.
Actually GET and OPTIONS request works well. But when I trying multiples POST request I get EOF error one in two request.
I’ve test to make **repeat request without proxy service and its work** well, so there is something not working in my code.
Edit :
1. I have test POST proxy with https://ptsv2.com/ and all request response return 200 status code.
// main.go
package main
import (
"fmt"
"../pkg/api"
)
func main() {
fmt.Println("Starting server")
api.InitServer()
}
// routes.go
package api
import (
"github.com/gin-gonic/gin"
)
const serviceUrl = "http://localhost:8732"
func InitServer() {
router := gin.Default()
defineRoutes(router)
router.Run()
}
func defineRoutes(router *gin.Engine) {
router.GET("/ping", Ping)
router.POST("/*any", Proxy(serviceUrl))
}
// controller.go
package api
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
"github.com/gin-gonic/gin"
)
type transport struct {
http.RoundTripper
}
func (t *transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
resp, err = t.RoundTripper.RoundTrip(req)
if err != nil {
// EOF ERROR HERE
return nil, err
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
err = resp.Body.Close()
if err != nil {
return nil, err
}
b = bytes.Replace(b, []byte("server"), []byte("schmerver"), -1)
body := ioutil.NopCloser(bytes.NewReader(b))
response := resp
response.Body = body
response.ContentLength = int64(len(b))
response.Header.Set("Content-Length", strconv.Itoa(len(b)))
response.Header.Set("Access-Control-Allow-Origin", "*")
return response, nil
}
func Proxy(targetUrl string) gin.HandlerFunc {
fn := func(c *gin.Context) {
remote, err := url.Parse(targetUrl)
if err != nil {
panic(err)
}
proxy := httputil.NewSingleHostReverseProxy(remote)
proxy.Director = func(req *http.Request) {
req.Header = c.Request.Header
req.Host = remote.Host
req.URL.Scheme = remote.Scheme
req.URL.Host = remote.Host
req.Close = true // True / False same result
}
proxy.Transport = &transport{http.DefaultTransport}
proxy.ServeHTTP(c.Writer, c.Request)
}
return fn
}
</details>
# 答案1
**得分**: 1
## 结论
你的代码没有 bug,它是有效的。可能是你的网络设置有问题。
## 解释
我下载了你的代码,并在本地后端服务器上进行了测试。它可以正常工作。
[![enter image description here][1]][1]
[![enter image description here][2]][2]
## 附录
后端服务器代码
```go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
fmt.Println("Starting server")
router := gin.Default()
router.POST("/*any", func(c *gin.Context) {
c.JSON(200, gin.H{
"mes": "hello",
})
})
router.Run(":8888")
}
```
[1]: https://i.stack.imgur.com/kzP50.png
[2]: https://i.stack.imgur.com/Vp18s.png
<details>
<summary>英文:</summary>
## conclusion
your code have no bug. it works. maybe your network setting is wrong.
## explain
I download your code and test it with a local backend server. It works.
[![enter image description here][1]][1]
[![enter image description here][2]][2]
## appendix
backend server code
```
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
fmt.Println("Starting server")
router := gin.Default()
router.POST("/*any", func(c *gin.Context) {
c.JSON(200, gin.H{
"mes": "hello",
})
})
router.Run(":8888")
}
```
[1]: https://i.stack.imgur.com/kzP50.png
[2]: https://i.stack.imgur.com/Vp18s.png
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论