douhuxi4145 2017-04-09 10:11
浏览 88
已采纳

返回给定URL内容的Web服务器

I wrote a simple web sever that gets the content of a given URL and writes it out using a http.ResponseWriter. But the problem is that it does not display any images and CSS on the page. The code is given bellow:

func factHandler(w http.ResponseWriter, r *http.Request) {
    res, err := http.Get("http://www.meaningfultype.com/")
    if err != nil {
        log.Fatal(err)
    }
    robots, err := ioutil.ReadAll(res.Body)

    res.Body.Close()
    if err != nil {
        log.Fatal(err)
    }   
    w.Write(robots)
}

What do I need to change so that the the whole page content as seen in the web browser is returned?

  • 写回答

2条回答 默认 最新

  • donglian1953 2017-04-09 11:41
    关注

    TL;DR

    • You are only serving the root HTML page, you need to respond to requests to other resources too (you can see what resource is being requested with the URL variable of the *http.Request variable)

    • When serving the resources, you need to write the Header's Content-Type to let the browser know what's the type of the resource (like image/png)

    Full Answer

    What you are doing in your request handler is getting http://www.meaningfultype.com/, the HTML page, then the browser finds an image like /images/header-logo.png and makes the request to get it but your server in localhost doesn't know how to respond to http://localhost/images/header-logo.png.

    Assuming your handler function is handling requests at the root of the server ("/"), you could get the requested URL r.URL and use it to get the required resource:

    url := "http://www.meaningfultype.com/"
    if r.URL.Host == "" {
        url += r.URL.String()
    } else {
        url = r.URL.String()
    }
    res, err := http.Get(url)
    

    The problem is that, even after doing this, all the resources are sent as plain/text because you are not setting the Header's Content-Type. That's why you need to specify the type of the resource before writing. In order to know what the type of the resource is, just get it from the Content-Type you just received in the Header of the response of http.Get:

    contentType := res.Header.Get("Content-Type")
    w.Header().Set("Content-Type", contentType)
    w.Write(robots)
    

    The final result:

    package main
    
    import (
        "io/ioutil"
        "log"
        "net/http"
    )
    
    func main() {
        http.HandleFunc("/", factHandler)
        http.ListenAndServe(":8080", nil)
    }
    
    func factHandler(w http.ResponseWriter, r *http.Request) {
        url := "http://www.meaningfultype.com/"
        if r.URL.Host == "" {
            url += r.URL.String()
        } else {
            url = r.URL.String()
        }
        res, err := http.Get(url)
        if err != nil {
            log.Fatal(err)
        }
        robots, err := ioutil.ReadAll(res.Body)
    
        res.Body.Close()
        if err != nil {
            log.Fatal(err)
        }
        contentType := res.Header.Get("Content-Type")
        w.Header().Set("Content-Type", contentType)
        w.Write(robots)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?