作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!
具体的思路是这样:通过 RequestCtx 的 Conn() 方法,获得 tcp 套接字。然后直接在 tcp 套接字上 Write 流式内容就行。
上代码:
package main
import (
"bufio"
"bytes"
"fmt"
"io"
syslog "log"
"net"
"os"
"strconv"
"time"
"github.com/valyala/bytebufferpool"
"github.com/valyala/fasthttp"
)
func FasthttpHandler(ctx *fasthttp.RequestCtx) {
ctx.HijackSetNoResponse(true) // 不使用 fasthttp 框架的输出
ctx.Hijack(func(c net.Conn) { // 这里会 go 出来一个协程执行 hijack 回调函数
log.Println("do nothing")
})
//
buf := bytebufferpool.Get()
defer bytebufferpool.Put(buf)
buf.Reset()
buf.B = append(buf.B, "HTTP/1.1 200 OK\r\n"+
"Server: fasthttp\r\n"+
"Date: Thu, 26 Oct 2023 01:09:23 GMT\r\n"+
"Content-Type: text/plain\r\n"+
"Cache-Control: no-cache, no-store, must-revalidate\r\n"+
"Transfer-Encoding: chunked\r\n"+
"\r\n"...)
conn := ctx.Conn()
_, _ = conn.Write(buf.B) // 写 http 头
//
for i := 0; i < 9; i++ {
_, _ = conn.Write([]byte(fmt.Sprintf("%x\r\n%d \r\n", 1, i)))
time.Sleep(1 * time.Second)
}
// 写入结束信息
_, _ = conn.Write([]byte("0\r\n\r\n")
}
func main() {
syslog.SetFlags(syslog.Lshortfile | syslog.LstdFlags)
server := &fasthttp.Server{
Handler: FasthttpHandler,
}
syslog.Fatalln(server.ListenAndServe(":8089"))
}
通过上述的方式虽然可以实现流式输出,但实际测试发现性能很差。
性能差的原因是每次请求都会 go 出来协程去执行 hijack 函数。
为此我改了一个版本,只要不设置 hijack 函数就不会产生协程去调用:
在 go.mod 中加上这样一句:
replace (
github.com/valyala/fasthttp => github.com/ahfuzhang/compress v1.49.2
)
然后注释掉设置 hijack 的那几行:
ctx.HijackSetNoResponse(true)
//ctx.Hijack(func(c net.Conn) {
// log.Println("do nothing")
//})
希望对大家有用,have fun ?
- Transfer-Encoding fasthttp Transfer Encoding chunkedtransfer-encoding fasthttp transfer encoding transfer-encoding transfer encoding chunked transfer-encoding transfer-encoding字段encoding transfer err_incomplete_chunked_encoding err_incomplete_chunked_encoding incomplete encoding encoding decoding transfer using fasthttp 片段fasthttp代码gzip fasthttp性能partial页面