常见问题

如何修改监听地址?

通过 Run 方法启动的 Flame 实例可以通过环境变量 FLAMEGO_ADDR 来修改监听地址:

export FLAMEGO_ADDR=localhost:8888

或通过传递参数给 Run 方法:

f.Run("localhost")       // => localhost:2830
f.Run(8888)              // => 0.0.0.0:8888
f.Run("localhost", 8888) // => localhost:8888

或者直接使用 http.ListenAndServe在新窗口打开http.ListenAndServeTLS在新窗口打开 方法启动实例:

http.ListenAndServe("localhost:8888", f)
http.ListenAndServeTLS("localhost:8888", "certFile", "keyFile", f)

如何实现优雅停机?

github.com/ory/graceful在新窗口打开 可被用于实现 Flame 实例的优雅停机:

package main

import (
	"net/http"

	"github.com/flamego/flamego"
	"github.com/ory/graceful"
)

func main() {
	f := flamego.New()

	...

	server := graceful.WithDefaults(
		&http.Server{
			Addr:    "0.0.0.0:2830",
			Handler: f,
		},
	)
	if err := graceful.Graceful(server.ListenAndServe, server.Shutdown); err != nil {
		// 处理错误
	}
}

如何提供文件下载?

import (
	"net/http"
	"net/url"
	"path/filepath"

	"github.com/flamego/flamego"
	"golang.org/x/exp/utf8string"
)

func main() {
	f := flamego.Classic()
	f.Get("/download", func(w http.ResponseWriter, r *http.Request) {
		fpath := "文件路径"
		filename := filepath.Base(fpath)
		if utf8string.NewString(filename).IsASCII() {
			w.Header().Set("Content-Disposition", `attachment; filename="`+filename+`"`)
		} else {
			w.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename))
		}
		http.ServeFile(w, r, fpath)
	})
	f.Run()
}

如何集成到现有的 Web 应用?

因为 Flame 实例实现了 http.Handler在新窗口打开 接口,所以可以被集成到任何接受 http.Handler 作为参数的地方。

示例:与 net/http 集成

下面展示了如何集成到 net/http 的路由系统中,并响应路径为 "/user/info" 的请求:

package main

import (
	"log"
	"net/http"

	"github.com/flamego/flamego"
)

func main() {
	f := flamego.New()
	f.Get("/user/info", func() string {
		return "The user is Joe"
	})

	// 将所有以 "/user/" 开头的请求路径都交给 Flame 示例处理
	http.Handle("/user/", f)

	if err := http.ListenAndServe("0.0.0.0:2830", nil); err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}
$ curl -i http://localhost:2830/user/info
The user is Joe

示例:与 Macaron 集成

下面展示了如何集成到 Macaron 的路由系统中,并响应路径为 "/user/info" 的请求:

package main

import (
	"log"
	"net/http"

	"github.com/flamego/flamego"
	"gopkg.in/macaron.v1"
)

func main() {
	f := flamego.New()
	f.Get("/user/info", func() string {
		return "The user is Joe"
	})

	// 将所有以 "/user/" 开头的请求路径都交给 Flame 示例处理
	m := macaron.New()
	m.Any("/user/*", f.ServeHTTP)

	if err := http.ListenAndServe("0.0.0.0:2830", m); err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}
$ curl -i http://localhost:2830/user/info
The user is Joe

inject.Invokerinject.FastInvoker 有什么区别?

inject.Invoker在新窗口打开 是 Flame 实例通过反射调用函数的实现形式。

在 2016 年,@tupunco在新窗口打开 提出并贡献了在新窗口打开 inject.FastInvoker在新窗口打开 的最初实现,即通过实现接口的形式实现函数调用,提升了大约 30% 的调用性能,并且降低了运行时的内存消耗。

和 Macaron/Martini 的关系是什么?

Martini 是 Go 语言中依赖注入型 Web 框架的鼻祖,开创了一个全新的流派。但受限于原作者的实现细节,它的性能和内存消耗都非常不尽如人意。很多人将性能原因归咎于反射并嗤之以鼻,但我觉得这纯属无脑喷,标准库的 JSON 实现用的就是反射,这么多 Go 语言实现的应用还不是用的开开心心?

Macaron 秉承了相同的理念,通过更好的实现细节提升了可观的性能并大幅降低了内存占用。遗憾的是,当时只是作为 Gogs在新窗口打开 项目的衍生品,所以没有好好进行设计,或者干脆点说,当时根本就没什么设计思想。所有的功能当时都只是为了支持项目的快速开发。

缺乏整体架构和设计原则的思考导致了许多回头来看非常错误的决定,包括但不限于:

总而言之,我始终认为 Macaron 是一款非常牛逼的 Web 框架,只不过 Flamego 作为继任者而言会更加牛逼 🙂

为什么默认端口是 2830?

keyboard layout 2830