2016-07-26 81 views
0

我需要擴展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請求中沒有時間戳或其他... –

回答

2

可以使用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