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

时间:2017-04-09 10:11:42

标签: go webserver

我编写了一个简单的Web服务器,它获取给定URL的内容并使用http.ResponseWriter将其写出来。但问题是它不会在页面上显示任何图像和CSS。代码如下:

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)
}

我需要更改哪些内容才能返回Web浏览器中显示的整个页面内容?

2 个答案:

答案 0 :(得分:2)

这里的问题可能是您所引用的网站使用图像和样式表的相对路径,例如"/css/main.css"。您使用Go服务向浏览器提供的本地网站具有另一个域(例如localhost),因此浏览器无法解析相对路径(没有http://localhost/css/main.css)。

因此,您需要做的是在您提供的文档中设置基本URL,或者,将每个相对路径重写为绝对路径(/css/main.csshttp://originalwebsite.com/css/main.css)。

为了添加基本标记或重写文档中的URL,我建议使用类似goquery的东西,它可以让你操纵类似于jQuery的HTML结构。

添加<base>代码的示例:

import (
    "github.com/PuerkitoBio/goquery"
    "fmt"
)

func main() {
    doc,err := goquery.NewDocument("http://www.meaningfultype.com/")

    if err != nil {
        panic(err)
    }

    m := doc.Find("head")

    m.Children().First().BeforeHtml(`<base url="http://localhost/">`)

    fmt.Println(doc.Html())
}

答案 1 :(得分:0)

TL; DR

  • 您只提供根HTML页面,您还需要响应对其他资源的请求(您可以看到使用* http.Request变量的URL变量请求的资源)

  • 在提供资源时,您需要编写标题Content-Type以让浏览器知道资源的类型(例如image/png

完整答案

您在请求处理程序中执行的操作是获取http://www.meaningfultype.com/ HTML页面,然后浏览器找到像/images/header-logo.png这样的图像并发出请求以获取它但是您在localhost中的服务器没有知道如何回复http://localhost/images/header-logo.png

假设您的处理程序函数正在处理服务器根目录("/")的请求,您可以获取请求的URL r.URL并使用它来获取所需的资源:

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

问题在于,即使执行此操作,所有资源都会以plain/text的形式发送,因为您没有设置标头Content-Type。这就是为什么你需要在写入之前指定资源的类型。为了知道资源的类型,只需从Content-Type的响应标题中收到的http.Get中获取它:

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

最终结果:

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)
}