英文:
Go http cannot handle HTTP requests with no PATH
问题
我正在编写一个小型的HTTP服务器,用于接收来自一些嵌入式设备的HTTP POST请求。不幸的是,这些设备发送的POST请求是格式错误的,不包含PATH组件:
POST HTTP/1.1
Host: 192.168.13.130:8080
Content-Length: 572
Connection: Keep-Alive
<?xml version="1.0"?>
....XML正文的其余部分
由于这个原因,Go的http包从不将请求传递给我的任何处理程序,并始终以400 Bad Request的响应进行回复。
由于这些是嵌入式设备,无法更改它们发送请求的方式,所以我想也许我可以拦截HTTP请求,如果没有PATH,则在传递给ServeMux之前添加一个路径(例如/)。
我尝试通过创建自己的CameraMux来实现这一点,但是Go始终在调用我自定义ServeMux的ServeHTTP()方法之前就以400 Bad Request的响应进行回复(请参见下面的代码)。
是否有一种方法可以在Go http回复Bad Request之前的某个时刻修改Request对象,或者有一种方法可以使Go接受没有PATH的请求?
package main
import (
"net/http"
"log"
"os"
)
type CameraMux struct {
mux *http.ServeMux
}
func (handler *CameraMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 在这里尝试修复URL.Path,但服务器永远不会到达这个方法。
log.Printf("URL %v\n", r.URL.Path)
handler.mux.ServeHTTP(w, r)
}
func process(path string) error {
log.Printf("Processing %v\n", path)
// 根据路径和正文进行处理
return nil
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path[1:]
log.Printf("Processing path %v\n", path)
err := process(path)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
} else {
w.WriteHeader(http.StatusOK)
}
})
err := http.ListenAndServe(":8080", &CameraMux{http.DefaultServeMux})
if err != nil {
log.Println(err)
os.Exit(1)
}
os.Exit(0)
}
英文:
I am writing a small HTTP server that receives HTTP POSTs from some embedded devices. Unfortunately these devices send malformed POST request that contain no PATH component:
POST HTTP/1.1
Host: 192.168.13.130:8080
Content-Length: 572
Connection: Keep-Alive
<?xml version="1.0"?>
....REST OF XML BODY
Due to this the Go http never passes the request to any of my handlers and always responds with 400 Bad Request.
Since these are embedded devices and changing the way they send the request is not an option I though maybe I could intercept the HTTP requests and if no PATH is present add one (e.g. /) to it before it passes to the SeverMux.
I tried this by creating my own CameraMux but Go always responds with 400 Bad Request even before calling the ServeHTTP() method from my custom ServeMux (see code below).
Is there a way to modify the Request object at some point before Go http responds Bad Request or there is a way to make Go accept the request even if it has no PATH?
package main
import (
"net/http"
"log"
"os"
)
type CameraMux struct {
mux *http.ServeMux
}
func (handler *CameraMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Try to fix URL.Path here but the server never reaches this method.
log.Printf("URL %v\n", r.URL.Path)
handler.mux.ServeHTTP(w, r)
}
func process(path string) error {
log.Printf("Processing %v\n", path)
// Do processing based on path and body
return nil
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path[1:]
log.Printf("Processing path %v\n", path)
err := process(path)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
} else {
w.WriteHeader(http.StatusOK)
}
})
err := http.ListenAndServe(":8080", &CameraMux{http.DefaultServeMux})
if err != nil {
log.Println(err)
os.Exit(1)
}
os.Exit(0)
}
答案1
得分: 0
我不确定Go的HTTP解析器是否允许没有URI路径元素的请求。如果不允许,那么你就没办法了。但如果允许的话,你可以像这样重写请求的路径:
type FixPath struct {}
func (f *FixPath) ServeHTTP(w http.ResponseWriter, r *http.Request) {
r.RequestURI = "/dummy/path" // 修复URI路径
http.DefaultServeMux.ServeHTTP(w, r) // 将修复后的请求转发给http.DefaultServeMux
}
func main() {
// 通过http.Handle或http.HandleFunc向http.DefaultServeMux注册处理程序,然后...
http.ListenAndServe(":8080", &FixPath{})
}
这段代码创建了一个名为FixPath
的类型,实现了ServeHTTP
方法,用于修复请求的路径。然后,在main
函数中,通过http.ListenAndServe
函数监听端口8080,并将FixPath
实例作为处理器传递进去。这样,所有经过该服务器的请求都会被重写为/dummy/path
路径,并转发给http.DefaultServeMux
进行处理。
英文:
I'm unsure if Go's HTTP parser will allow requests with no URI path element. If it doesn't then you're out of luck. If it does however; you could overwrite the request's path like this:
type FixPath struct {}
func (f *FixPath) ServeHTTP(w http.ResponseWriter, r *http.Request) {
r.RequestURI = "/dummy/path" // fix URI path
http.DefaultServeMux.ServeHTTP(w, r) // forward the fixed request to http.DefaultServeMux
}
func main() {
// register handlers with http.DefaultServeMux through http.Handle or http.HandleFunc, and then...
http.ListenAndServe(":8080", &FixPath{})
}
答案2
得分: 0
你所看到的错误发生在请求解析逻辑中,在调用ServeHTTP
之前发生。
HTTP请求通过net/http
包中的ReadRequest
函数从套接字中读取。它将使用空的URL部分对请求的第一行进行标记化,然后继续解析URL:
if req.URL, err = url.ParseRequestURI(rawurl); err != nil {
return nil, err
}
不幸的是,这个函数将对于空的URL字符串返回错误,这将中止请求读取过程。
所以看起来没有简单的方法来实现你想要的功能,除非修改标准库的代码。
英文:
The error you are seeing occurs within the request parsing logic, which happens before ServeHTTP
is called.
The HTTP request is read from the socket by the ReadRequest
function from the net/http
package. It will tokenize the first line of the request with an empty URL portion, but then goes on to parse the URL:
if req.URL, err = url.ParseRequestURI(rawurl); err != nil {
return nil, err
}
Unfortunately this function will return an error for an empty URL string, which will in turn aborts the request reading process.
So it doesn't look like there is an easy way to achieve what you're after without modifying the standard library code.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论