我想构建一个http反向代理,它检查http主体,然后向其上游服务器发送http请求。你怎么能在围棋中做到这一点?
初始尝试(随后)失败,因为ReverseProxy复制传入请求,修改并发送请求,但正文已被读取。
func main() {
backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("ioutil.ReadAll: %s", err), 500)
return
}
// expecting to see hoge=fuga
fmt.Fprintf(w, "this call was relayed by the reverse proxy, body: %s", string(b))
}))
defer backendServer.Close()
rpURL, err := url.Parse(backendServer.URL)
if err != nil {
log.Fatal(err)
}
proxy := func(u *url.URL) http.Handler {
p := httputil.NewSingleHostReverseProxy(u)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, fmt.Sprintf("ParseForm: %s", err), 500)
return
}
p.ServeHTTP(w, r)
})
}(rpURL)
frontendProxy := httptest.NewServer(proxy)
defer frontendProxy.Close()
resp, err := http.Post(frontendProxy.URL, "application/x-www-form-urlencoded", bytes.NewBufferString("hoge=fuga"))
if err != nil {
log.Fatalf("http.Post: %s", err)
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalf("ioutil.ReadAll: %s", err)
}
fmt.Printf("%s", b)
}
// shows: "http: proxy error: http: ContentLength=9 with Body length 0"
然后,我的下一个尝试是将整个正文读入字节。读卡器,并使用它检查正文内容,在发送到上游服务器之前查找开头部分。但是接下来我必须重新实现我想要避免的ReverseProxy。还有其他优雅的方式吗?
编辑:
如上所述,在这种情况下,解析的表单将为空。您需要从主体中手动解析表单。
请求。Body
是一个io。ReaderCloser
,因为它描述了tcp连接的rx
部分。但是在您的用例中,您需要阅读所有内容,因为您正在将主体解析为表单。这里的技巧是使用io重新分配
从已读数据派生的对象。下面是我要做的:r.Body
。ReaderCloser
// before calling r.ParseForm(), get the body
// as a byte slice
body, err := ioutil.ReadAll(r.Body)
// after calling r.ParseForm(), reassign body
r.Body = ioutil.NopCloser(bytes.NewBuffer(body))
字节。NewBuffer(body)
将主体字节片转换为io。Reader
和ioutil。NopCler
转换一个io。读取
到io。带有nop方法的ReaderCloser方法。
package main
import "net/http"
import "net/http/httputil"
import "net/url"
import "net/http/httptest"
import "fmt"
import "log"
import "bytes"
import "io/ioutil"
func main() {
backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("ioutil.ReadAll: %s", err), 500)
return
}
// expecting to see hoge=fuga
fmt.Fprintf(w, "this call was relayed by the reverse proxy, body: %s", string(b))
}))
defer backendServer.Close()
rpURL, err := url.Parse(backendServer.URL)
if err != nil {
log.Fatal(err)
}
proxy := func(u *url.URL) http.Handler {
p := httputil.NewSingleHostReverseProxy(u)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// read out body into a slice
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("Error reading body: %s", err), 500)
return
}
// inspect current body here
if err := r.ParseForm(); err != nil {
http.Error(w, fmt.Sprintf("ParseForm: %s", err), 500)
return
}
// assign a new body with previous byte slice
r.Body = ioutil.NopCloser(bytes.NewBuffer(body))
p.ServeHTTP(w, r)
})
}(rpURL)
frontendProxy := httptest.NewServer(proxy)
defer frontendProxy.Close()
resp, err := http.Post(
frontendProxy.URL,
"application/x-www-form-urlencoded",
bytes.NewBufferString("hoge=fuga"))
if err != nil {
log.Fatalf("http.Post: %s", err)
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalf("ioutil.ReadAll: %s", err)
}
fmt.Printf("%s", b)
}
您可以将导演
处理程序设置为http putil。ReverseProxy
文档:https://golang.org/pkg/net/http/httputil/#ReverseProxy
下面是一个示例代码,它从请求中读取内容正文,并从localhost:8080
到localhost:3333
package main
import (
"bytes"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
)
func main() {
director := func(req *http.Request) {
if req.Body != nil {
// read all bytes from content body and create new stream using it.
bodyBytes, _ := ioutil.ReadAll(req.Body)
req.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
// create new request for parsing the body
req2, _ := http.NewRequest(req.Method, req.URL.String(), bytes.NewReader(bodyBytes))
req2.Header = req.Header
req2.ParseForm()
log.Println(req2.Form)
}
req.URL.Host = "localhost:3333"
req.URL.Scheme = "http"
}
proxy := &httputil.ReverseProxy{Director: director}
log.Fatalln(http.ListenAndServe(":8080", proxy))
}
问题内容: 我正在将算法从C移植到Go。我有些困惑。这是C函数: 在for循环中,将值s分配给元素cd数组x。这怎么可能?据我所知,长双精度数是float64(在Go上下文中)。因此,我不应该编译C代码,因为我正在向只包含uint64元素的数组分配一个long double。但是C代码可以正常工作。 那么有人可以解释为什么这行得通吗? 非常感谢你。 更新: 该函数的原始C代码可以在以下位置找到:h
有什么方法可以重写panic功能来使用我们的记录器吗?
用围棋的语言, 是一个字符串数组 我们还使用作为参数。 有什么区别? 功能定义: 我可以像下面那样调用这个函数吗?
问题内容: Go语言规范的“地图类型”部分描述了地图类型的界面和常规用法,The Go Blog上 的“ Go maps in action”一文中 偶然提到了哈希表和“快速查找,添加和删除”。 的电流源代码描述了其作为散列表实施方案(其通常摊销); 但是,在语言规范或其他材料中我看不到任何性能特征(例如Big O性能)的保证。 go语言是否为地图类型或仅 接口 保证了任何 性能 保证(例如,恒定
问题内容: 我正在使用Java 7和。我想读取一个请求(例如),但如果它大于我正在使用的大小,则我正在努力想出一个很好的解决方案来读取完整的请求。例如,如果是4048字节,并且HTTP POST包含大于4kB的图像。 有没有很好的递归解决方案或循环呢? 这是我的阅读请求代码: 在我写过的地方: 它看起来像是代码重用的好地方,但是我无法提出一个好的解决方案。有什么办法可以在这里重用Completio