我编写了一个简单的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浏览器中显示的整个页面内容?
答案 0 :(得分:2)
这里的问题可能是您所引用的网站使用图像和样式表的相对路径,例如"/css/main.css"
。您使用Go服务向浏览器提供的本地网站具有另一个域(例如localhost
),因此浏览器无法解析相对路径(没有http://localhost/css/main.css
)。
因此,您需要做的是在您提供的文档中设置基本URL,或者,将每个相对路径重写为绝对路径(/css/main.css
到http://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)
您只提供根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)
}