美文网首页
使用Golang转发HTTP流数据

使用Golang转发HTTP流数据

作者: 土豆吞噬者 | 来源:发表于2019-08-13 00:32 被阅读0次
    package main
    
    import (
        "fmt"
        "net/http"
        "strings"
        "flag"
    )
    
    var(
        serverAddr string
    )
    
    
    
    func main() {
        flag.StringVar(&serverAddr,"addr",":80","server listen addr")
        flag.Parse()
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            _, _ = w.Write([]byte("radio relay server"))
        })
        http.HandleFunc("/play", handlePlay)
        _ = http.ListenAndServe(serverAddr, nil)
    }
    
    //提取http头中包含icy-的key-value对
    func extractIcyHeaders(headers map[string][]string) map[string]string{
        icyHeaders := make(map[string] string)
        for k, v := range headers{
            k=strings.ToLower(k)
            if strings.HasPrefix(k,"icy-"){
                if len(v)==0{
                    icyHeaders[k]=""
                }else{
                    icyHeaders[k]=v[0]
                }
            }
        }
        return icyHeaders
    }
    
    func sendRequest(url string, icyRequestHeaders map[string]string) *http.Response {
        if len(url)<5{
            fmt.Println("url length too short!")
            return nil
        }
        client := &http.Client{}
        request, err:= http.NewRequest("GET", url, nil)
        if err != nil {
            fmt.Println(err.Error())
            return nil
        }
        for k, v := range icyRequestHeaders {
            request.Header[k]=[]string{v}
        }
        response, err := client.Do(request)
        if err != nil {
            fmt.Println(err.Error())
            return nil
        }
        return response
    }
    
    
    
    func receiveBody(response *http.Response) (exitChan chan struct{},dataChan chan []byte){
        exitChan=make(chan struct{})
        dataChan=make(chan []byte, 10)
        go func() {
            defer close(dataChan)
            defer response.Body.Close()
            for {
                select {
                case <-exitChan:
                    fmt.Println("exit receive data!")
                    return
                default:{
                    buf := make([]byte, 4096)
                    n, err:= response.Body.Read(buf)
                    if err != nil || n == 0{
                        fmt.Println("receive data error!")
                        return
                    }else{
                        dataChan <-buf[:n]
                    }
                }
                }
            }
        }()
        return
    }
    
    
    func setResponseHeaders(w http.ResponseWriter,response *http.Response){
        w.Header().Set("Content-Type","audio/mpeg")
        w.Header().Set("transfer-encoding","identity")
        icyResponseHeaders:=extractIcyHeaders(response.Header)
        for k, v := range icyResponseHeaders {
            w.Header()[k]=[]string{v}
        }
    }
    
    func sendBody(w http.ResponseWriter, dataChan <-chan []byte) {
        for {
            data,ok := <-dataChan
            if (!ok){
                fmt.Println("receive data error!")
                break
            }
            n, err := w.Write(data)
            if err != nil || n == 0 {
                fmt.Println("send data error!")
                break
            }
        }
    }
    
    
    
    func handlePlay(w http.ResponseWriter, r *http.Request) {
        _ = r.ParseForm()
        url:=r.Form.Get("url")
        response:=sendRequest(url,extractIcyHeaders(r.Form));
        if (response!=nil){
            setResponseHeaders(w,response)
            exitChan,dataChan:=receiveBody(response);
            sendBody(w, dataChan)
            close(exitChan)
        }else{
            w.WriteHeader(500)
        }
    }
    

    相关文章

      网友评论

          本文标题:使用Golang转发HTTP流数据

          本文链接:https://www.haomeiwen.com/subject/vijmjctx.html