You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何使用fmt.Fprintf结合http.ResponseWriter无法正确输出CSS文件?

为什么用fmt.Fprintf返回CSS会触发curl报错,换成writer.Write就正常?

问题重现

这段Go代码试图对外提供CSS文件服务:

package main

import (
  "fmt"
  "io/ioutil"
  "log"
  "net/http"
)

func main() {

  b, _ := ioutil.ReadFile("style1.css") // 文件大小7626字节
  bigString := string(b)

  http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
    writer.Header().Set("Content-Type", "text/css")
    writer.Header().Set("Connection", "keep-alive")
    writer.Header().Set("Content-Length", fmt.Sprintf("%d", len(bigString)))
    fmt.Fprintf(writer, bigString)
  })

  log.Fatal(http.ListenAndServe(":3000", nil))
}

执行curl http://localhost:3000/时会报错:curl: (18) transfer closed with 7626 bytes remaining to read,但把fmt.Fprintf(writer, bigString)替换成writer.Write([]byte(bigString))后,一切正常。

问题根源

fmt.Fprintf是格式化输出函数,它会把传入的字符串当成格式化模板解析——如果你的CSS文件里包含%字符(比如CSS的百分比值、特殊选择器或属性里的符号),fmt.Fprintf会将其视为格式化占位符,但你没有传递对应的参数,导致实际输出的内容被截断或篡改,最终输出的字节数远小于你在Content-Length头部声明的7626字节。

curl发现实际收到的字节数和头部承诺的不一致,就会抛出“传输关闭时还有字节未读取”的错误。

而writer.Write是直接将字节切片原封不动写入响应流,不会做任何解析或格式化,输出的字节数和Content-Length完全匹配,所以客户端能正常接收。

解决方案

有两种简单的修复方式:

  1. 直接使用原始字节切片写入(推荐,更高效)
    跳过字符串转换步骤,直接用读取到的b写入响应,同时Content-Length直接用len(b)计算:

    // 读取文件后直接保留字节切片
    b, err := os.ReadFile("style1.css") // 替代已废弃的ioutil.ReadFile
    if err != nil {
      log.Fatal(err)
    }
    
    http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
      writer.Header().Set("Content-Type", "text/css")
      writer.Header().Set("Connection", "keep-alive")
      writer.Header().Set("Content-Length", fmt.Sprintf("%d", len(b)))
      _, err := writer.Write(b)
      if err != nil {
        log.Printf("写入响应失败: %v", err)
      }
    })
    
  2. 用fmt.Fprint替代fmt.Fprintf
    如果一定要用fmt系列函数,用fmt.Fprint(writer, bigString)——它不会解析格式化占位符,只是单纯输出字符串内容,输出字节数和原字符串长度一致。

内容的提问来源于stack exchange,提问作者Andrew Arrow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 02:57:33