Golang中CSS文件被作为text/html类型返回的问题

Golang中CSS文件被作为text/html类型返回的问题

package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
)

//allTemplates is of type pointer to a template
var allTemplates *template.Template

func contact(writer http.ResponseWriter, request *http.Request) {
	err := request.ParseForm()
	check(err)
	err = allTemplates.ExecuteTemplate(writer, "index.html", request.Form)
	check(err)
}

func init() {
	allTemplates = template.Must(template.ParseFiles("public/html/index.html"))

}

func main() {

	http.HandleFunc("/", contact)
	http.Handle("/css", http.FileServer(http.Dir("public")))
	http.Handle("/js/", http.FileServer(http.Dir("public")))
	http.Handle("/images/", http.FileServer(http.Dir("public")))
	http.Handle("/media-files/", http.FileServer(http.Dir("public")))
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

如果您能抽空审阅这段代码,我将不胜感激


更多关于Golang中CSS文件被作为text/html类型返回的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

我将

http.Handle("/css", http.FileServer(http.Dir("public")))

改为

http.Handle("/css", http.FileServer(http.Dir("./public")))

之后一切工作正常,但我想了解这种行为的原因,因为其他文件(如图片)在目录名前都没有添加"./"前缀,但一切都能正常工作。

另外,文件服务器会使用相应的Content-Type头部来提供文件,我在示例中使用了相同的方式,但对于不同的文件类型,其行为表现却有所不同。

更多关于Golang中CSS文件被作为text/html类型返回的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我不太确定回退到内容嗅探的具体工作原理,但第一阶段使用的 mime.TypeByExtension 在 Windows 上需要注册表支持,并且(或曾经)容易受到交叉编译损坏或目标计算机上缺少注册表项的影响。也就是说,至少在 Windows 系统上,这种自动检测功能的可靠性比我预期的要低。

不过我认为正如 lutzhorn 所说,这会导致返回 application/octet-stream。你确定得到的结果不是这样的吗?可能是浏览器在此基础上添加了它自己的默认设置。

如果我正确理解了您的问题,您是在询问为什么

	http.Handle("/css", http.FileServer(http.Dir("public")))

返回的CSS文件带有Content-Type头部为text/html

我无法复现这个问题。下面这个简单的程序

package main

import (
	"log"
	"net/http"
)

func main() {
	// 简单的静态网页服务器:
	log.Fatal(http.ListenAndServe(":8080", http.FileServer(http.Dir("/tmp/styles"))))
}

能够正确地从/tmp/styles目录提供CSS文件,并返回Content-Type: text/css

$ curl -i http://localhost:8080/foo.css
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 35
Content-Type: text/css; charset=utf-8
Last-Modified: Sun, 13 May 2018 14:52:05 GMT
Date: Sun, 13 May 2018 14:54:09 GMT

* {
    font-family: sans-serif;
}

我仍然无法复现这个问题。即使我将代码改为:

log.Fatal(http.ListenAndServe(":8080", http.FileServer(http.Dir("./styles"))))

并在包含styles/的目录中运行此程序,foo.cssContent-Type仍然设置为text/css

让我们看一下源代码

// If the response's Content-Type header is not set, ServeContent 
// first tries to deduce the type from name's file extension and,
// if that fails, falls back to reading the first block of the content
// and passing it to DetectContentType.

让我们看一下net/http.DetectContentType

DetectContentType 实现了 http://mimesniff.spec.whatwg.org/ 中描述的算法来确定给定数据的 Content-Type。它最多考虑数据的前512个字节。DetectContentType 总是返回一个有效的 MIME 类型:如果无法确定更具体的类型,它将返回 “application/octet-stream”。

  • 你的 CSS 文件叫什么名字?它们是否有.css扩展名?
  • 如果没有,它们的前512个字节包含什么内容?这些内容是否足以判断它们包含的是 CSS 而不是其他语言(如 C 或 JavaScript)?

问题在于你的静态文件路由配置不正确,导致CSS文件被错误地作为text/html类型返回。主要问题是路由路径和实际文件路径不匹配。

以下是修正后的代码:

package main

import (
    "fmt"
    "html/template"
    "log"
    "net/http"
    "path/filepath"
)

var allTemplates *template.Template

func contact(writer http.ResponseWriter, request *http.Request) {
    err := request.ParseForm()
    check(err)
    err = allTemplates.ExecuteTemplate(writer, "index.html", request.Form)
    check(err)
}

func init() {
    allTemplates = template.Must(template.ParseFiles("public/html/index.html"))
}

func main() {
    // 修正静态文件服务配置
    http.HandleFunc("/", contact)
    
    // 使用StripPrefix来正确处理文件路径
    http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("public/css"))))
    http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("public/js"))))
    http.Handle("/images/", http.StripPrefix("/images/", http.FileServer(http.Dir("public/images"))))
    http.Handle("/media-files/", http.StripPrefix("/media-files/", http.FileServer(http.Dir("public/media-files"))))
    
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func check(err error) {
    if err != nil {
        fmt.Println(err)
    }
}

关键修改点:

  1. 修正路由路径:所有静态文件路由都添加了尾部斜杠 /css/ 而不是 /css

  2. 使用StripPrefix:正确剥离URL前缀,将请求路径映射到正确的文件系统路径

  3. 指定具体目录:每个静态文件服务指向特定的子目录

如果你的目录结构是这样的:

public/
├── css/
│   └── style.css
├── js/
│   └── script.js
├── images/
│   └── logo.png
├── media-files/
│   └── video.mp4
└── html/
    └── index.html

现在CSS文件将通过正确的MIME类型返回:

  • /css/style.csstext/css
  • /js/script.jsapplication/javascript
  • /images/logo.pngimage/png

这样配置后,浏览器将正确识别和处理CSS文件,避免被当作HTML内容解析。

回到顶部