扩展golang的http包

扩展golang的http包

问题描述:

我需要扩展http包来实现包含状态错误描述的非标准响应,例如: 400缺少必需参数 而不是400作为标准状态描述的错误请求。扩展golang的http包

这是我的实际执行情况:

package main 

import (
    "fmt" 
    "io" 
    "io/ioutil" 
    "net/http" 
    "net/url" 
) 

type GatewayHandler int 

func main() { 
    var gh GatewayHandler 

    http.ListenAndServe(":9000", gh) 
} 

func (gh GatewayHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) { 

    legacyApiUrl := "http://some-url.com" + req.URL.RequestURI() 

    client := &http.Client{} 
    request, _ := http.NewRequest(req.Method, legacyApiUrl, nil) 
    response, _ := client.Do(request) 
    res.Header().Set("Status", response.Status) 
    for k, v := range response.Header { 
     fmt.Println(k, ": ", v) 
     i := "" 
     for _, j := range v { 
      i += j 
     } 
     res.Header().Set(k, i) 
    } 

    res.WriteHeader(response.StatusCode) 

    if response.Status != "200 OK" { 
     fmt.Println(response.Status) 
    } 

    result, _ := ioutil.ReadAll(response.Body) 
    output := string(result) 
    fmt.Println(output) 

    io.WriteString(res, output) 
} 

总的来说,我需要转发来自其他网址使用它的那个状态,我需要保持兼容。

非常感谢您提前。

约瑟夫

+1

你确切的问题是什么?在您当前的实施中,哪些不适合您?你想为一些遗留API编写代理吗? – Nebril

+0

是的,有点......问题是标题需要像状态消息应该包含一个错误描述,但不是像400错误请求那样的标准错误描述,但是400缺少必需的参数,或者400请求中没有时间戳或其他... –

可以使用http.Hijacker接口https://golang.org/pkg/net/http/#Hijacker“劫持”(接管)服务器的TCP连接到客户端和写入它的自定义响应。下面是示例https://golang.org/pkg/net/http/#example_Hijacker的变形返回“400缺少所需的参数”,而不是标准的“400错误请求”响应到客户端:

package main 

import "net/http" 

func main() { 
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 
     hj, ok := w.(http.Hijacker) 
     if !ok { 
      http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError) 
      return 
     } 
     conn, bufrw, err := hj.Hijack() 
     if err != nil { 
      http.Error(w, err.Error(), http.StatusInternalServerError) 
      return 
     } 
     // Don't forget to close the connection: 
     defer conn.Close() 
     // non-standard HTTP status text and an HTTP header are written; 
     // end of the Headers part of the messages is marked by extra \r\n 
     bufrw.WriteString("HTTP/1.1 400 Required parameter is missing\r\nContent-Type: text/html; charset=utf-8\r\n\r\n") 
     // write the body of the HTTP response message 
     bufrw.WriteString("400 Required parameter is missing\n") 
     bufrw.Flush() 
    }) 
    http.ListenAndServe(":9000", nil) 
} 

运行此程序和发送卷曲请求产生所需的响应:

 
$ curl -i http://localhost:9000/ 
HTTP/1.1 400 Required parameter is missing 
Content-Type: text/html; charset=utf-8 

400 Required parameter is missing 

它应该是简单的把它扩大到传播从旧API服务器等的响应。

编辑
使用\r\n\r\n在示例程序终止按照HTTP消息标准(https://tools.ietf.org/html/rfc7230#section-3)HTTP响应的报头部分;为了清楚起见,将分开的WriteString呼叫标头和HTTP响应的主体。

+0

TIL!感谢那。 – Nebril

+0

哇,这很漂亮,但如何编写标题和内容到被劫持的连接?无论如何,这是我正在寻找的。在此先感谢:) –

+0

我修改了上面的程序,使用单独的bufrw.WriteString调用标题和正文,用额外的'\ r \ n'空行分隔。当然,你可以添加更多的头文件或者从代理连接复制它们。只要记住,在劫持的情况下,您可以完全控制正在编写和正在模仿HTTP服务器的内容 - 例如,如果发送Content-Length报头非常重要,则应计算响应长度并“手动”发送报头,如示例中的Content-Type所做的那样。 – dmitris