cloudwego / hertz

Go HTTP framework with high-performance and strong-extensibility for building micro-services.
https://www.cloudwego.io
Apache License 2.0
5.04k stars 491 forks source link

[Question] Static method not work welll with relative path. #1121

Open TinyBeer opened 2 months ago

TinyBeer commented 2 months ago

Describe the bug I'm trying to change relative path of a Static method like h.Static("/static/", "./static"). When it comes to visit http://127.0.0.1:8888/static/hello.txt. It comes back with message [Cannot open requested path]. An error report comes out. ··· 2024/05/23 22:47:40.016435 transport.go:65: [Info] HERTZ: HTTP server listening on address=[::]:8888 2024/05/23 22:47:48.879962 fs.go:856: [Error] HERTZ: Cannot open file="./static/static/hello.txt", error=open ./static/static/hello.txt: The system cannot find the path specified. ···
It seems like Static join relative path and root path together. To Reproduce

  1. prepare file static/hello.txt
  2. change relative path of Static to /static/
  3. start server && visit except path http://127.0.0.1:8888/static/hello.txt
  4. error occure

Expected behavior get content of hello.txt Screenshots

image

Hertz version:

github.com/cloudwego/hertz v0.9.0

Environment:

set GO111MODULE=auto
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\TB\AppData\Local\go-build
set GOENV=C:\Users\TB\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=D:\goproject\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=D:\goproject
set GOPRIVATE=
set GOPROXY=https://goproxy.cn,direct
set GOROOT=D:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLCHAIN=auto
set GOTOOLDIR=D:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.22.0
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=D:\goproject\src\go_code\hz_app\go.mod
set GOWORK=
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\TB\AppData\Local\Temp\go-build3109564830=/tmp/go-build -gno-record-gcc-switches

Additional context

The entire family of Static family has this problem.

TinyBeer commented 2 months ago

files for test

D:.
│  go.mod
│  go.sum
│  main.go
│
└─static
        hello.txt

It works well when i test http://127.0.0.1:8888/hello.txt while use this code.

func main() {
    h := server.Default(server.WithExitWaitTime(time.Second))

    h.Static("/", "./static")

    h.Spin()
}

image

But i'm trying to change the url to http://127.0.0.1:8888/static/hello.txt.

func main() {
    h := server.Default(server.WithExitWaitTime(time.Second))

    h.Static("/static", "./static")

    h.Spin()
}

image image

error report

2024/05/28 23:07:28.923005 fs.go:856: [Error] HERTZ: Cannot open file="./static/static/hello.txt", error=open ./static/static/hello.txt: The system cannot find the path specified.
TinyBeer commented 2 months ago

Maybe the problem comes from here, where I think we should use ctx.Param("filepath") instead of ctx.Path()

https://github.com/cloudwego/hertz/blob/0fe11823b76a77cd68fa909993b400f0b0a2df35/pkg/app/fs.go#L801 https://github.com/cloudwego/hertz/blob/0fe11823b76a77cd68fa909993b400f0b0a2df35/pkg/app/fs.go#L838

func (h *fsHandler) handleRequest(c context.Context, ctx *RequestContext) {
    var path []byte
    if h.pathRewrite != nil {
        path = h.pathRewrite(ctx)
    } else {
        path = ctx.Path()  //  <----
    }
    path = stripTrailingSlashes(path)
       ...

    if !ok {
        pathStr := string(path)
        filePath := h.root + pathStr // <----
        var err error
        ff, err = h.openFSFile(filePath, mustCompress)
       ...

handler registered here

// StaticFS works just like `Static()` but a custom `FS` can be used instead.
func (group *RouterGroup) StaticFS(relativePath string, fs *app.FS) IRoutes {
    if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
        panic("URL parameters can not be used when serving a static folder")
    }
    handler := fs.NewRequestHandler()
    urlPattern := path.Join(relativePath, "/*filepath")

    // Register GET and HEAD handlers
    group.GET(urlPattern, handler)
    group.HEAD(urlPattern, handler)
    return group.returnObj()
}
welkeyever commented 2 months ago

Use PathRewrite to rewrite the URI, try this:

h.StaticFS("/assets", &app.FS{Root: "./", GenerateIndexPages: true, PathRewrite: app.NewPathSlashesStripper(1)})

More: https://github.com/cloudwego/hertz-examples/tree/main/file/staticFile

TinyBeer commented 2 months ago

Thanks, it actually works with PathRewrite. But it makes me more confused about the parameter relativepath of the method Static.

https://github.com/cloudwego/hertz-examples/blob/36af1b1f7ef584a674db94620b22e62edfb95a96/file/staticFile/main.go#L31 image

https://github.com/cloudwego/hertz/blob/0fe11823b76a77cd68fa909993b400f0b0a2df35/pkg/route/routergroup.go#L204 image