labstack / echo

High performance, minimalist Go web framework

Home Page:https://echo.labstack.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Using static middleware, does not raise handler at '/*' path

mehranzand opened this issue · comments

Issue Description

When I use the middleware static to embed react project the home handler for example GET or Any does not raise the event but the other paths does.

func New() *echo.Echo {
	e := echo.New()

	e.GET("*", IndexHandler, middleware.StaticWithConfig(middleware.StaticConfig{
		HTML5:      true,
		Filesystem: http.FS(web.DistDirFS),
	}))

}

Checklist

  • Dependencies installed
  • No typos
  • Searched existing issues and docs

Expected behaviour

IndexHandler will be called at path '/'

Actual behaviour

Nothing

Paths * and /* are the same. When registering routes with same path the last one used when routing is done.

and you probably need to set Root folder for your DistDirFS

	e.GET("*", IndexHandler, middleware.StaticWithConfig(middleware.StaticConfig{
		Root:       "path-in-web.DistDirFS",
		HTML5:      true,
		Filesystem: http.FS(web.DistDirFS),
	}))

thanks for your quick reply.
IndexHandler does not called when fetching home landing for example localhost:7070 but the other paths (localhost:7070/containers) it will called properly. I was set Root path in static middleware but it not managed to solve my issue.

Try adding static MW with Use

	e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
		Root:       "path-in-web.DistDirFS",
		HTML5:      true,
		Filesystem: http.FS(web.DistDirFS),
	}))

I tried this method first but not resolve my issue.

Is that IndexHandler returning something dynamic or static content?

It just reading index.html and execute some template on that then using Context.Response.Writer to apply result.

func IndexHandler(c echo.Context) error {
	data := map[string]interface{}{
		"Config": "config json",
	}

	file, err := web.DistDirFS.Open("index.html")
	if err != nil {
		log.Panic(err)
	}
	bytes, err := io.ReadAll(file)
	if err != nil {
		log.Panic(err)
	}

	tmpl, err := template.New("index").Parse(string(bytes))
	if err != nil {
		log.Panic(err)
	}

	err = tmpl.Execute(c.Response().Writer, data)
	if err != nil {
		log.Panic(err)
		http.Error(c.Response().Writer, err.Error(), http.StatusInternalServerError)
	}

	return nil
}

Lets start with this small example

package main

import (
	"embed"
	"errors"
	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"log"
	"net/http"
)

//go:embed website
var assets embed.FS

func main() {
	e := echo.New()

	e.Use(middleware.Recover())
	e.Use(middleware.Logger())
	
	indexHandler := func(c echo.Context) error {
		return c.String(http.StatusOK, "HI") // replace with your rendering handler
	}

	e.GET("/", indexHandler)
	e.GET("/*", indexHandler, middleware.StaticWithConfig(middleware.StaticConfig{
		Root:       "website",
		HTML5:      true,
		Filesystem: http.FS(assets),
	}))

	g := e.Group("/api")
	g.GET("/test", func(c echo.Context) error {
		return c.String(http.StatusOK, "OK")
	})

	if err := e.Start(":8080"); err != nil && !errors.Is(err, http.ErrServerClosed) {
		log.Fatal(err)
	}
}

website is folder containing you html/css etc files. For example lets say that folder contains test.html then curl http://localhost:8080/test.html would serve that file. curl http://localhost:8080/xxx.html would serve indexHandler

it's works! there was some problem in embed FS reference. it was solved thank you.

very good.

NB: you should not leave that file read and template executing part in that function or at least wrap it into sync.Once. At the moment you are reading that file and parsing the template for every request and this is a lot of unnecessary work that could be done once.

I think every time the static page served by echo should render the index.html to inject the config json into react app.So it will be good. Isn't?

for effiency I suggest moving these parts out of handler so these will not be executed for every request.

	file, err := web.DistDirFS.Open("index.html")
	if err != nil {
		log.Panic(err)
	}
	bytes, err := io.ReadAll(file)
	if err != nil {
		log.Panic(err)
	}

	tmpl, err := template.New("index").Parse(string(bytes))
	if err != nil {
		log.Panic(err)
	}

It seems to me that only thing that needs to be executed for every request is err = tmpl.Execute(c.Response().Writer, data)

Thank you, I'll definitely take it into consideration.