1
0
mirror of https://github.com/kataras/iris.git synced 2026-05-11 08:33:47 +00:00

create the new FileServer and HandleDir, deprecate the rest APIBuilder/Party static methods and more

relative: https://github.com/kataras/iris/issues/1283 and removing pongo2 from vendor: https://github.com/kataras/iris/issues/1284

Former-commit-id: 3ec57b349f99faca2b8e36d9f7252db0b6ea080d
This commit is contained in:
Gerasimos (Makis) Maropoulos
2019-06-21 19:43:25 +03:00
parent 7f9e33cabb
commit d0104defa8
72 changed files with 1585 additions and 1826 deletions

View File

@@ -149,7 +149,7 @@ Navigate through examples for a better understanding.
- [Write your own custom parameter types](routing/macros/main.go)
- [Reverse routing](routing/reverse/main.go)
- [Custom Router (high-level)](routing/custom-high-level-router/main.go)
- [Custom Wrapper](routing/custom-wrapper/main.go)
- [Custom Wrapper](routing/custom-wrapper/main.go) **UPDATED**
- Custom Context
* [method overriding](routing/custom-context/method-overriding/main.go)
* [new implementation](routing/custom-context/new-implementation/main.go)
@@ -366,14 +366,14 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
### File Server
- [Favicon](file-server/favicon/main.go)
- [Basic](file-server/basic/main.go)
- [Embedding Files Into App Executable File](file-server/embedding-files-into-app/main.go)
- [Embedding Gziped Files Into App Executable File](file-server/embedding-gziped-files-into-app/main.go)
- [Basic](file-server/basic/main.go) **UPDATED**
- [Embedding Files Into App Executable File](file-server/embedding-files-into-app/main.go) **UPDATED**
- [Embedding Gziped Files Into App Executable File](file-server/embedding-gziped-files-into-app/main.go) **UPDATED**
- [Send/Force-Download Files](file-server/send-files/main.go)
- Single Page Applications
* [single Page Application](file-server/single-page-application/basic/main.go)
* [embedded Single Page Application](file-server/single-page-application/embedded-single-page-application/main.go)
* [embedded Single Page Application with other routes](file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go)
* [single Page Application](file-server/single-page-application/basic/main.go) **UPDATED**
* [embedded Single Page Application](file-server/single-page-application/embedded-single-page-application/main.go) **UPDATED**
* [embedded Single Page Application with other routes](file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go) **UPDATED**
### How to Read from `context.Request() *http.Request`

View File

@@ -10,7 +10,7 @@
### 概览
- [Hello world!](hello-world/main.go)
- [Hello WebAssemply!](webassembly/basic/main.go) **NEW**
- [Hello WebAssemply!](webassembly/basic/main.go)
- [基础](overview/main.go)
- [教程: 在线人数](tutorial/online-visitors/main.go)
- [教程: 一个“待完成”MVC Application基于Iris和Vue.js](https://hackernoon.com/a-todo-mvc-application-using-iris-and-vue-js-5019ff870064)
@@ -21,7 +21,7 @@
- [教程: DropzoneJS 上传](tutorial/dropzonejs)
- [教程: Caddy 服务器使用](tutorial/caddy)
- [教程: Iris + MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c)
- [教程: Apache Kafka的API](tutorial/api-for-apache-kafka) **NEW**
- [教程: Apache Kafka的API](tutorial/api-for-apache-kafka)
### 目录结构
@@ -105,10 +105,10 @@ app.Get("{root:path}", rootWildcardHandler)
- [自定义 HTTP 错误](routing/http-errors/main.go)
- [动态路径](routing/dynamic-path/main.go)
* [根级通配符路径](routing/dynamic-path/root-wildcard/main.go)
- [编写你自己的参数类型](routing/macros/main.go) **NEW**
- [编写你自己的参数类型](routing/macros/main.go)
- [反向路由](routing/reverse/main.go)
- [自定义路由(高层级)](routing/custom-high-level-router/main.go) **NEW**
- [自定义包装](routing/custom-wrapper/main.go)
- [自定义路由(高层级)](routing/custom-high-level-router/main.go)
- [自定义包装](routing/custom-wrapper/main.go) **更新**
- 自定义上下文
   * [方法重写](routing/custom-context/method-overriding/main.go)
   * [新实现方式](routing/custom-context/new-implementation/main.go)
@@ -121,8 +121,8 @@ app.Get("{root:path}", rootWildcardHandler)
- [基础](hero/basic/main.go)
- [概览](hero/overview)
- [Sessions](hero/sessions) **NEW**
- [另一种依赖注入的例子和通常的较好实践](hero/smart-contract/main.go) **NEW**
- [Sessions](hero/sessions)
- [另一种依赖注入的例子和通常的较好实践](hero/smart-contract/main.go) ****
### MVC 模式
@@ -255,14 +255,14 @@ func(c *ExampleController) Get() string |
参考下面的示例
- [Hello world](mvc/hello-world/main.go) **UPDATED**
- [Session Controller](mvc/session-controller/main.go) **UPDATED**
- [Overview - Plus Repository and Service layers](mvc/overview) **UPDATED**
- [Login showcase - Plus Repository and Service layers](mvc/login) **UPDATED**
- [Singleton](mvc/singleton) **NEW**
- [Websocket Controller](mvc/websocket) **NEW**
- [Register Middleware](mvc/middleware) **NEW**
- [Vue.js Todo MVC](tutorial/vuejs-todo-mvc) **NEW**
- [Hello world](mvc/hello-world/main.go) **更新**
- [Session Controller](mvc/session-controller/main.go) **更新**
- [Overview - Plus Repository and Service layers](mvc/overview) **更新**
- [Login showcase - Plus Repository and Service layers](mvc/login) **更新**
- [Singleton](mvc/singleton) ****
- [Websocket Controller](mvc/websocket) ****
- [Register Middleware](mvc/middleware) ****
- [Vue.js Todo MVC](tutorial/vuejs-todo-mvc) ****
### 子域名
@@ -316,14 +316,14 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
### 文件服务器
- [Favicon](file-server/favicon/main.go)
- [基础操作](file-server/basic/main.go)
- [把文件嵌入应用的可执行文件](file-server/embedding-files-into-app/main.go)
- [嵌入Gzip压缩的文件到可咨询文件](file-server/embedding-gziped-files-into-app/main.go) **NEW**
- [基础操作](file-server/basic/main.go) **更新**
- [把文件嵌入应用的可执行文件](file-server/embedding-files-into-app/main.go) **更新**
- [嵌入Gzip压缩的文件到可咨询文件](file-server/embedding-gziped-files-into-app/main.go) **更新**
- [上传/(强制)下载文件](file-server/send-files/main.go)
- 单页面应用(Single Page Applications)
* [单页面应用](file-server/single-page-application/basic/main.go)
* [嵌入式(embedded)单页面应用](file-server/single-page-application/embedded-single-page-application/main.go)
* [使用额外路由的嵌入式单页面应用](file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go)
* [单页面应用](file-server/single-page-application/basic/main.go) **更新**
* [嵌入式(embedded)单页面应用](file-server/single-page-application/embedded-single-page-application/main.go) **更新**
* [使用额外路由的嵌入式单页面应用](file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go) **更新**
### 如何读取`context.Request() *http.Request`
@@ -346,7 +346,7 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
- [写入Gzip压缩](http_responsewriter/write-gzip/main.go)
- [流输出Stream Writer](http_responsewriter/stream-writer/main.go)
- [数据传递Transactions](http_responsewriter/transactions/main.go)
- [SSE](http_responsewriter/sse/main.go) **NEW**
- [SSE](http_responsewriter/sse/main.go)
- [SSE (third-party package usage for server sent events第三方库SSE)](http_responsewriter/sse-third-party/main.go)
> The `context/context#ResponseWriter()` returns an enchament version of a http.ResponseWriter, these examples show some places where the Context uses this object. Besides that you can use it as you did before iris.
@@ -430,7 +430,7 @@ iris websocket库依赖于它自己的[包](https://github.com/kataras/iris/tree
设计这个包的目的是处理原始websockets虽然它的API和著名的[socket.io](https://socket.io)很像。我最近读了一片文章,并且对我
决定给iris设计一个**快速的**websocket**限定**包并且不是一个向后传递类socket.io的包。你可以阅读这个链接里的文章https://medium.com/@ivanderbyl/why-you-don-t-need-socket-io-6848f1c871cd。
- [Basic](websocket/basic) **NEW**
- [Basic](websocket/basic) ****
* [Server](websocket/basic/server.go)
* [Go Client](websocket/basic/go-client/client.go)
* [Browser Client](websocket/basic/browser/index.html)

View File

@@ -74,7 +74,7 @@ func writeMarkdown(ctx iris.Context) {
ctx.Markdown(markdownContents)
}
/* Note that `StaticWeb` does use the browser's disk caching by-default
therefore, register the cache handler AFTER any StaticWeb calls,
/* Note that `HandleDir` does use the browser's disk caching by-default
therefore, register the cache handler AFTER any HandleDir calls,
for a faster solution that server doesn't need to keep track of the response
navigate to https://github.com/kataras/iris/blob/master/_examples/cache/client-side/main.go */

View File

@@ -0,0 +1 @@
just a text.

View File

@@ -0,0 +1 @@
<h1>Hello App2App3 index</h1>

View File

@@ -0,0 +1 @@
<h1>Hello App2 index</h1>

View File

@@ -4,38 +4,48 @@ import (
"github.com/kataras/iris"
)
func main() {
func newApp() *iris.Application {
app := iris.New()
app.Favicon("./assets/favicon.ico")
// enable gzip, optionally:
// if used before the `StaticXXX` handlers then
// the content byte range feature is gone.
// recommend: turn off for large files especially
// when server has low memory,
// turn on for medium-sized files
// or for large-sized files if they are zipped already,
// i.e "zippedDir/file.gz"
//
// app.Use(iris.Gzip)
// first parameter is the request path
// second is the system directory
//
// app.StaticWeb("/css", "./assets/css")
// app.StaticWeb("/js", "./assets/js")
//
app.StaticWeb("/static", "./assets")
// app.HandleDir("/css", "./assets/css")
// app.HandleDir("/js", "./assets/js")
app.HandleDir("/static", "./assets", iris.DirOptions{
// Defaults to "/index.html", if request path is ending with **/*/$IndexName
// then it redirects to **/*(/) which another handler is handling it,
// that another handler, called index handler, is auto-registered by the framework
// if end developer does not managed to handle it by hand.
IndexName: "/index.html",
// When files should served under compression.
Gzip: false,
// List the files inside the current requested directory if `IndexName` not found.
ShowList: false,
// If `ShowList` is true then this function will be used instead of the default one to show the list of files of a current requested directory(dir).
// DirList: func(ctx context.Context, dirName string, dir http.File) error { ... }
//
// Optional validator that loops through each requested resource.
// AssetValidator: func(ctx iris.Context, name string) bool { ... }
})
// You can also register any index handler manually, order of registration does not matter:
// app.Get("/static", [...custom middleware...], func(ctx iris.Context) {
// [...custom code...]
// ctx.ServeFile("./assets/index.html", false)
// })
// http://localhost:8080/static
// http://localhost:8080/static/css/main.css
// http://localhost:8080/static/js/jquery-2.1.1.js
// http://localhost:8080/static/favicon.ico
app.Run(iris.Addr(":8080"))
// Note:
// Routing doesn't allows something .StaticWeb("/", "./assets")
//
// To see how you can wrap the router in order to achieve
// wildcard on root path, see "single-page-application".
return app
}
func main() {
app := newApp()
app.Run(iris.Addr(":8080"))
}

View File

@@ -0,0 +1,93 @@
package main
import (
"io/ioutil"
"path/filepath"
"strings"
"testing"
"github.com/kataras/iris/httptest"
)
type resource string
func (r resource) contentType() string {
switch filepath.Ext(r.String()) {
case ".js":
return "application/javascript"
case ".css":
return "text/css"
case ".ico":
return "image/x-icon"
case ".html", "":
return "text/html"
default:
return "text/plain"
}
}
func (r resource) String() string {
return string(r)
}
func (r resource) strip(strip string) string {
s := r.String()
return strings.TrimPrefix(s, strip)
}
func (r resource) loadFromBase(dir string) string {
filename := r.String()
filename = r.strip("/static")
if filepath.Ext(filename) == "" {
// root /.
filename = filename + "/index.html"
}
fullpath := filepath.Join(dir, filename)
b, err := ioutil.ReadFile(fullpath)
if err != nil {
panic(fullpath + " failed with error: " + err.Error())
}
result := string(b)
return result
}
func TestFileServerBasic(t *testing.T) {
var urls = []resource{
"/static/css/main.css",
"/static/js/jquery-2.1.1.js",
"/static/favicon.ico",
"/static/app2",
"/static/app2/app2app3",
"/static",
}
app := newApp()
// route := app.GetRouteReadOnly("GET/{file:path}")
// if route == nil {
// app.Logger().Fatalf("expected a route to serve files")
// }
// if expected, got := "./assets", route.StaticDir(); expected != got {
// app.Logger().Fatalf("expected route's static directory to be: '%s' but got: '%s'", expected, got)
// }
// if !route.StaticDirContainsIndex() {
// app.Logger().Fatalf("epxected ./assets to contain an %s file", "/index.html")
// }
e := httptest.New(t, app)
for _, u := range urls {
url := u.String()
contents := u.loadFromBase("./assets")
e.GET(url).Expect().
Status(httptest.StatusOK).
ContentType(u.contentType(), app.ConfigurationReadOnly().GetCharset()).
Body().Equal(contents)
}
}

View File

@@ -14,8 +14,14 @@ import (
// See `file-server/embedding-gziped-files-into-app` example as well.
func newApp() *iris.Application {
app := iris.New()
app.Logger().SetLevel("debug")
app.StaticEmbedded("/static", "./assets", Asset, AssetNames)
app.HandleDir("/static", "./assets", iris.DirOptions{
Asset: Asset,
AssetInfo: AssetInfo,
AssetNames: AssetNames,
ShowList: true,
})
return app
}

View File

@@ -66,12 +66,21 @@ var urls = []resource{
}
// if bindata's values matches with the assets/... contents
// and secondly if the StaticEmbedded had successfully registered
// and secondly if the HandleDir had successfully registered
// the routes and gave the correct response.
func TestEmbeddingFilesIntoApp(t *testing.T) {
app := newApp()
e := httptest.New(t, app)
route := app.GetRouteReadOnly("GET/static/{file:path}")
if route == nil {
t.Fatalf("expected a route to serve embedded files")
}
if len(route.StaticSites()) > 0 {
t.Fatalf("not expected a static site, the ./assets directory or its subdirectories do not contain any index.html")
}
if runtime.GOOS != "windows" {
// remove the embedded static favicon for !windows,
// it should be built for unix-specific in order to be work

View File

@@ -16,12 +16,13 @@ import (
func newApp() *iris.Application {
app := iris.New()
// Note the `GzipAsset` and `GzipAssetNames` are different from `go-bindata`'s `Asset` and `AssetNames,
// that means that you can use both `go-bindata` and `bindata` tools,
// the `go-bindata` can be used for the view engine's `Binary` method
// and the `bindata` with the `StaticEmbeddedGzip` (x8 times faster than the StaticEmbeded with `go-bindata`).
app.StaticEmbeddedGzip("/static", "./assets", GzipAsset, GzipAssetNames)
// Note the `GzipAsset` and `GzipAssetNames` are different from `go-bindata`'s `Asset`,
// do not set the `Gzip` option to true, it's already managed by the kataras/bindata.
app.HandleDir("/static", "./assets", iris.DirOptions{
Asset: GzipAsset,
AssetInfo: GzipAssetInfo,
AssetNames: GzipAssetNames,
})
return app
}

View File

@@ -67,7 +67,7 @@ var urls = []resource{
}
// if bindata's values matches with the assets/... contents
// and secondly if the StaticEmbedded had successfully registered
// and secondly if the HandleDir had successfully registered
// the routes and gave the correct response.
func TestEmbeddingGzipFilesIntoApp(t *testing.T) {
app := newApp()

View File

@@ -20,15 +20,7 @@ func newApp() *iris.Application {
ctx.View("index.html")
})
// or just serve index.html as it is:
// app.Get("/{f:path}", func(ctx iris.Context) {
// ctx.ServeFile("index.html", false)
// })
assetHandler := app.StaticHandler("./public", false, false)
// as an alternative of SPA you can take a look at the /routing/dynamic-path/root-wildcard
// example too
app.SPA(assetHandler)
app.HandleDir("/", "./public")
return app
}

View File

@@ -9,11 +9,21 @@ import "github.com/kataras/iris"
func newApp() *iris.Application {
app := iris.New()
app.OnErrorCode(404, func(ctx iris.Context) {
app.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) {
ctx.Writef("404 not found here")
})
app.StaticEmbedded("/", "./public", Asset, AssetNames)
app.HandleDir("/", "./public", iris.DirOptions{
Asset: Asset,
AssetInfo: AssetInfo,
AssetNames: AssetNames,
// IndexName: "index.html", // default.
// If you want to show a list of embedded files when inside a directory without an index file:
// ShowList: true,
// DirList: func(ctx iris.Context, dirName string, f http.File) error {
// // [Optional, custom code to show the html list].
// }
})
// Note:
// if you want a dynamic index page then see the file-server/embedded-single-page-application

View File

@@ -22,16 +22,11 @@ func newApp() *iris.Application {
ctx.View("index.html")
})
assetHandler := iris.StaticEmbeddedHandler("./public", Asset, AssetNames, false) // keep that false if you use the `go-bindata` tool.
// as an alternative of SPA you can take a look at the /routing/dynamic-path/root-wildcard
// example too
// or
// app.StaticEmbedded if you don't want to redirect on index.html and simple serve your SPA app (recommended).
// public/index.html is a dynamic view, it's handlded by root,
// and we don't want to be visible as a raw data, so we will
// the return value of `app.SPA` to modify the `IndexNames` by;
app.SPA(assetHandler).AddIndexName("index.html")
app.HandleDir("/", "./public", iris.DirOptions{
Asset: Asset,
AssetInfo: AssetInfo,
AssetNames: AssetNames,
})
return app
}
@@ -45,11 +40,3 @@ func main() {
// http://localhost:8080/css/main.css
app.Run(iris.Addr(":8080"))
}
// Note that app.Use/UseGlobal/Done will be executed
// only to the registered routes like our index (app.Get("/", ..)).
// The file server is clean, but you can still add middleware to that by wrapping its "assetHandler".
//
// With this method, unlike StaticWeb("/" , "./public") which is not working by-design anymore,
// all custom http errors and all routes are working fine with a file server that is registered
// to the root path of the server.

View File

@@ -2,19 +2,56 @@ package main
import (
"fmt"
"io"
"os"
"runtime"
"strings"
"time"
"github.com/kataras/iris"
"github.com/kataras/iris/middleware/logger"
"github.com/kataras/golog"
)
const deleteFileOnExit = false
func newRequestLogger(newWriter io.Writer) iris.Handler {
c := logger.Config{}
// we don't want to use the logger
// to log requests to assets and etc
c.AddSkipper(func(ctx iris.Context) bool {
path := ctx.Path()
for _, ext := range excludeExtensions {
if strings.HasSuffix(path, ext) {
return true
}
}
return false
})
c.LogFuncCtx = func(ctx iris.Context, latency time.Duration) {
datetime := time.Now().Format(ctx.Application().ConfigurationReadOnly().GetTimeFormat())
customHandlerMessage := ctx.Values().GetString("log_message")
file, line := ctx.HandlerFileLine()
source := fmt.Sprintf("%s:%d", file, line)
// this will just append a line without an array of javascript objects, readers of this file should read one line per log javascript object,
// however, you can improve it even more, this is just a simple example on how to use the `LogFuncCtx`.
jsonStr := fmt.Sprintf(`{"datetime":"%s","level":"%s","source":"%s","latency": "%s","status": %d,"method":"%s","path":"%s","message":"%s"}`,
datetime, "INFO", source, latency.String(), ctx.GetStatusCode(), ctx.Method(), ctx.Path(), customHandlerMessage)
fmt.Fprintln(newWriter, jsonStr)
}
return logger.New(c)
}
func h(ctx iris.Context) {
ctx.Values().Set("log_message", "something to give more info to the request logger")
ctx.Writef("Hello from %s", ctx.Path())
}
func main() {
app := iris.New()
@@ -26,56 +63,21 @@ func main() {
}
}()
// Handle the logs by yourself using the `app.Logger#Handle` method.
// Return true if that handled, otherwise will print to the screen.
// You can also use the `app.Logger#SetOutput/AddOutput` to change or add
// multi (io.Writer) outputs if you just want to print the message
// somewhere else than the terminal screen.
app.Logger().Handle(func(l *golog.Log) bool {
_, fn, line, _ := runtime.Caller(5)
var (
// formatted date string based on the `golog#TimeFormat`, which can be customized.
// Or use the golog.Log#Time field to get the exact time.Time instance.
datetime = l.FormatTime()
// the log's message level.
level = golog.GetTextForLevel(l.Level, false)
// the log's message.
message = l.Message
// the source code line of where it is called,
// this can differ on your app, see runtime.Caller(%d).
source = fmt.Sprintf("%s#%d", fn, line)
)
// You can always use a custom json structure and json.Marshal and logFile.Write(its result)
// but it is faster to just build your JSON string by yourself as we do below.
jsonStr := fmt.Sprintf(`{"datetime":"%s","level":"%s","message":"%s","source":"%s"}`, datetime, level, message, source)
fmt.Fprintln(logFile, jsonStr)
/* Example output:
{"datetime":"2018/10/31 13:13","level":"[INFO]","message":"My server started","source":"c:/mygopath/src/github.com/kataras/iris/_examples/http_request/request-logger/request-logger-file-json/main.go#71"}
*/
return true
})
r := newRequestLogger()
r := newRequestLogger(logFile)
app.Use(r)
app.OnAnyErrorCode(r, func(ctx iris.Context) {
ctx.HTML("<h1> Error: Please try <a href ='/'> this </a> instead.</h1>")
})
h := func(ctx iris.Context) {
ctx.Writef("Hello from %s", ctx.Path())
}
app.Get("/", h)
app.Get("/1", h)
app.Get("/2", h)
app.Logger().Info("My server started")
app.Get("/", h)
// http://localhost:8080
// http://localhost:8080/1
// http://localhost:8080/2
@@ -92,29 +94,6 @@ var excludeExtensions = [...]string{
".svg",
}
func newRequestLogger() iris.Handler {
c := logger.Config{
Status: true,
IP: true,
Method: true,
Path: true,
}
// we don't want to use the logger
// to log requests to assets and etc
c.AddSkipper(func(ctx iris.Context) bool {
path := ctx.Path()
for _, ext := range excludeExtensions {
if strings.HasSuffix(path, ext) {
return true
}
}
return false
})
return logger.New(c)
}
// get a filename based on the date, file logs works that way the most times
// but these are just a sugar.
func todayFilename() string {

View File

@@ -85,10 +85,10 @@ func newRequestLogger() (h iris.Handler, close func() error) {
return err
}
c.LogFunc = func(now time.Time, latency time.Duration, status, ip, method, path string, message interface{}, headerMessage interface{}) {
output := logger.Columnize(now.Format("2006/01/02 - 15:04:05"), latency, status, ip, method, path, message, headerMessage)
c.LogFunc = func(endTime time.Time, latency time.Duration, status, ip, method, path string, message interface{}, headerMessage interface{}) {
output := logger.Columnize(endTime.Format("2006/01/02 - 15:04:05"), latency, status, ip, method, path, message, headerMessage)
logFile.Write([]byte(output))
}
} // or make use of the `LogFuncCtx`, see the '../request-logger-file-json' example for more.
// we don't want to use the logger
// to log requests to assets and etc

View File

@@ -28,7 +28,7 @@ func main() {
Reload(true)
app.RegisterView(tmpl)
app.StaticWeb("/public", "./web/public")
app.HandleDir("/public", "./web/public")
app.OnAnyErrorCode(func(ctx iris.Context) {
ctx.ViewData("Message", ctx.Values().

View File

@@ -559,89 +559,72 @@ Example Code:
package main
import (
"net/http"
"strings"
"net/http"
"strings"
"github.com/kataras/iris"
"github.com/kataras/iris"
)
// In this example you'll just see one use case of .WrapRouter.
// You can use the .WrapRouter to add custom logic when or when not the router should
// be executed in order to execute the registered routes' handlers.
//
// To see how you can serve files on root "/" without a custom wrapper
// just navigate to the "file-server/single-page-application" example.
//
// This is just for the proof of concept, you can skip this tutorial if it's too much for you.
func newApp() *iris.Application {
app := iris.New()
app.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) {
ctx.HTML("<b>Resource Not found</b>")
})
app.Get("/profile/{username}", func(ctx iris.Context) {
ctx.Writef("Hello %s", ctx.Params().Get("username"))
})
app.HandleDir("/", "./public")
myOtherHandler := func(ctx iris.Context) {
ctx.Writef("inside a handler which is fired manually by our custom router wrapper")
}
// wrap the router with a native net/http handler.
// if url does not contain any "." (i.e: .css, .js...)
// (depends on the app , you may need to add more file-server exceptions),
// then the handler will execute the router that is responsible for the
// registered routes (look "/" and "/profile/{username}")
// if not then it will serve the files based on the root "/" path.
app.WrapRouter(func(w http.ResponseWriter, r *http.Request, router http.HandlerFunc) {
path := r.URL.Path
if strings.HasPrefix(path, "/other") {
// acquire and release a context in order to use it to execute
// our custom handler
// remember: we use net/http.Handler because here we are in the "low-level", before the router itself.
ctx := app.ContextPool.Acquire(w, r)
myOtherHandler(ctx)
app.ContextPool.Release(ctx)
return
}
router.ServeHTTP(w, r) // else continue serving routes as usual.
})
return app
}
func main() {
app := iris.New()
app := newApp()
app.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) {
ctx.HTML("<b>Resource Not found</b>")
})
// http://localhost:8080
// http://localhost:8080/index.html
// http://localhost:8080/app.js
// http://localhost:8080/css/main.css
// http://localhost:8080/profile/anyusername
// http://localhost:8080/other/random
app.Run(iris.Addr(":8080"))
app.Get("/", func(ctx iris.Context) {
ctx.ServeFile("./public/index.html", false)
})
app.Get("/profile/{username}", func(ctx iris.Context) {
ctx.Writef("Hello %s", ctx.Params().Get("username"))
})
// serve files from the root "/", if we used .StaticWeb it could override
// all the routes because of the underline need of wildcard.
// Here we will see how you can by-pass this behavior
// by creating a new file server handler and
// setting up a wrapper for the router(like a "low-level" middleware)
// in order to manually check if we want to process with the router as normally
// or execute the file server handler instead.
// use of the .StaticHandler
// which is the same as StaticWeb but it doesn't
// registers the route, it just returns the handler.
fileServer := app.StaticHandler("./public", false, false)
// wrap the router with a native net/http handler.
// if url does not contain any "." (i.e: .css, .js...)
// (depends on the app , you may need to add more file-server exceptions),
// then the handler will execute the router that is responsible for the
// registered routes (look "/" and "/profile/{username}")
// if not then it will serve the files based on the root "/" path.
app.WrapRouter(func(w http.ResponseWriter, r *http.Request, router http.HandlerFunc) {
path := r.URL.Path
// Note that if path has suffix of "index.html" it will auto-permant redirect to the "/",
// so our first handler will be executed instead.
if !strings.Contains(path, ".") {
// if it's not a resource then continue to the router as normally. <-- IMPORTANT
router(w, r)
return
}
// acquire and release a context in order to use it to execute
// our file server
// remember: we use net/http.Handler because here we are in the "low-level", before the router itself.
ctx := app.ContextPool.Acquire(w, r)
fileServer(ctx)
app.ContextPool.Release(ctx)
})
// http://localhost:8080
// http://localhost:8080/index.html
// http://localhost:8080/app.js
// http://localhost:8080/css/main.css
// http://localhost:8080/profile/anyusername
app.Run(iris.Addr(":8080"))
// Note: In this example we just saw one use case,
// you may want to .WrapRouter or .Downgrade in order to bypass the iris' default router, i.e:
// you can use that method to setup custom proxies too.
//
// If you just want to serve static files on other path than root
// you can just use the StaticWeb, i.e:
// .StaticWeb("/static", "./public")
// ________________________________requestPath, systemPath
// Note: In this example we just saw one use case,
// you may want to .WrapRouter or .Downgrade in order to bypass the iris' default router, i.e:
// you can use that method to setup custom proxies too.
}
```
@@ -1355,7 +1338,7 @@ type Context interface {
// You can define your own "Content-Type" with `context#ContentType`, before this function call.
//
// This function doesn't support resuming (by range),
// use ctx.SendFile or router's `StaticWeb` instead.
// use ctx.SendFile or router's `HandleDir` instead.
ServeContent(content io.ReadSeeker, filename string, modtime time.Time, gzipCompression bool) error
// ServeFile serves a file (to send a file, a zip for example to the client you should use the `SendFile` instead)
// receives two parameters
@@ -1365,7 +1348,7 @@ type Context interface {
// You can define your own "Content-Type" with `context#ContentType`, before this function call.
//
// This function doesn't support resuming (by range),
// use ctx.SendFile or router's `StaticWeb` instead.
// use ctx.SendFile or router's `HandleDir` instead.
//
// Use it when you want to serve dynamic files to the client.
ServeFile(filename string, gzipCompression bool) error

View File

@@ -10,11 +10,6 @@ import (
// In this example you'll just see one use case of .WrapRouter.
// You can use the .WrapRouter to add custom logic when or when not the router should
// be executed in order to execute the registered routes' handlers.
//
// To see how you can serve files on root "/" without a custom wrapper
// just navigate to the "file-server/single-page-application" example.
//
// This is just for the proof of concept, you can skip this tutorial if it's too much for you.
func newApp() *iris.Application {
app := iris.New()
@@ -23,26 +18,15 @@ func newApp() *iris.Application {
ctx.HTML("<b>Resource Not found</b>")
})
app.Get("/", func(ctx iris.Context) {
ctx.ServeFile("./public/index.html", false)
})
app.Get("/profile/{username}", func(ctx iris.Context) {
ctx.Writef("Hello %s", ctx.Params().Get("username"))
})
// serve files from the root "/", if we used .StaticWeb it could override
// all the routes because of the underline need of wildcard.
// Here we will see how you can by-pass this behavior
// by creating a new file server handler and
// setting up a wrapper for the router(like a "low-level" middleware)
// in order to manually check if we want to process with the router as normally
// or execute the file server handler instead.
app.HandleDir("/", "./public")
// use of the .StaticHandler
// which is the same as StaticWeb but it doesn't
// registers the route, it just returns the handler.
fileServer := app.StaticHandler("./public", false, false)
myOtherHandler := func(ctx iris.Context) {
ctx.Writef("inside a handler which is fired manually by our custom router wrapper")
}
// wrap the router with a native net/http handler.
// if url does not contain any "." (i.e: .css, .js...)
@@ -52,19 +36,18 @@ func newApp() *iris.Application {
// if not then it will serve the files based on the root "/" path.
app.WrapRouter(func(w http.ResponseWriter, r *http.Request, router http.HandlerFunc) {
path := r.URL.Path
// Note that if path has suffix of "index.html" it will auto-permant redirect to the "/",
// so our first handler will be executed instead.
if !strings.Contains(path, ".") { // if it's not a resource then continue to the router as normally.
router(w, r)
if strings.HasPrefix(path, "/other") {
// acquire and release a context in order to use it to execute
// our custom handler
// remember: we use net/http.Handler because here we are in the "low-level", before the router itself.
ctx := app.ContextPool.Acquire(w, r)
myOtherHandler(ctx)
app.ContextPool.Release(ctx)
return
}
// acquire and release a context in order to use it to execute
// our file server
// remember: we use net/http.Handler because here we are in the "low-level", before the router itself.
ctx := app.ContextPool.Acquire(w, r)
fileServer(ctx)
app.ContextPool.Release(ctx)
router.ServeHTTP(w, r) // else continue serving routes as usual.
})
return app
@@ -78,14 +61,10 @@ func main() {
// http://localhost:8080/app.js
// http://localhost:8080/css/main.css
// http://localhost:8080/profile/anyusername
// http://localhost:8080/other/random
app.Run(iris.Addr(":8080"))
// Note: In this example we just saw one use case,
// you may want to .WrapRouter or .Downgrade in order to bypass the iris' default router, i.e:
// you can use that method to setup custom proxies too.
//
// If you just want to serve static files on other path than root
// you can just use the StaticWeb, i.e:
// .StaticWeb("/static", "./public")
// ________________________________requestPath, systemPath
}

View File

@@ -56,4 +56,6 @@ func TestCustomWrapper(t *testing.T) {
Status(httptest.StatusOK).
Body().Equal(contents)
}
e.GET("/other/something").Expect().Status(httptest.StatusOK)
}

View File

@@ -1,7 +1,7 @@
<html>
<head>
<title>{{ .Page.Title }}</title>
<title>Index Page</title>
</head>
<body>

View File

@@ -35,17 +35,17 @@ func main() {
// maps to ./public/assets/css/bootstrap.min.css file at system location.
// GET: http://localhost:8080/assets/js/react.min.js
// maps to ./public/assets/js/react.min.js file at system location.
app.StaticWeb("/assets", "./public/assets")
app.HandleDir("/assets", "./public/assets")
/* OR
// GET: http://localhost:8080/js/react.min.js
// maps to ./public/assets/js/react.min.js file at system location.
app.StaticWeb("/js", "./public/assets/js")
app.HandleDir("/js", "./public/assets/js")
// GET: http://localhost:8080/css/bootstrap.min.css
// maps to ./public/assets/css/bootstrap.min.css file at system location.
app.StaticWeb("/css", "./public/assets/css")
app.HandleDir("/css", "./public/assets/css")
*/

View File

@@ -112,7 +112,7 @@ func (b *Bootstrapper) Bootstrap() *Bootstrapper {
// static files
b.Favicon(StaticAssets + Favicon)
b.StaticWeb(StaticAssets[1:len(StaticAssets)-1], StaticAssets)
b.HandleDir(StaticAssets[1:len(StaticAssets)-1], StaticAssets)
// middleware, after static files
b.Use(recover.New())

View File

@@ -18,7 +18,7 @@ func main() {
app.RegisterView(iris.HTML("./views", ".html").Layout("shared/layout.html"))
app.StaticWeb("/public", "./public")
app.HandleDir("/public", "./public")
mvc.Configure(app, configureMVC)

View File

@@ -11,8 +11,8 @@ func main() {
* Setup static files
*/
app.StaticWeb("/assets", "./public/assets")
app.StaticWeb("/upload_resources", "./public/upload_resources")
app.HandleDir("/assets", "./public/assets")
app.HandleDir("/upload_resources", "./public/upload_resources")
dashboard := app.Party("dashboard.")
{

View File

@@ -41,7 +41,7 @@ func TestSubdomainWWW(t *testing.T) {
}
host := "localhost:1111"
e := httptest.New(t, app, httptest.URL("http://"+host), httptest.Debug(false))
e := httptest.New(t, app, httptest.Debug(false))
for _, test := range tests {

View File

@@ -101,7 +101,7 @@ func main() {
app.RegisterView(iris.HTML("./views", ".html"))
// Make the /public route path to statically serve the ./public/... contents
app.StaticWeb("/public", "./public")
app.HandleDir("/public", "./public")
// Render the actual form
// GET: http://localhost:8080

View File

@@ -168,7 +168,7 @@ func main() {
app := iris.New()
app.RegisterView(iris.HTML("./views", ".html"))
app.StaticWeb("/public", "./public")
app.HandleDir("/public", "./public")
app.Get("/", func(ctx iris.Context) {
ctx.View("upload.html")

View File

@@ -124,7 +124,7 @@ func main() {
app := iris.New()
app.RegisterView(iris.HTML("./views", ".html"))
app.StaticWeb("/public", "./public")
app.HandleDir("/public", "./public")
app.Get("/", func(ctx iris.Context) {
ctx.View("upload.html")

View File

@@ -8,7 +8,7 @@ Article is coming soon, follow and stay tuned
Read [the fully functional example](main.go).
```sh
$ go get -u github.com/mongodb/mongo-go-driver
$ go get -u go.mongodb.org/mongo-driver/...
$ go get -u github.com/joho/godotenv
```

View File

@@ -1,6 +1,6 @@
package main
// go get -u github.com/mongodb/mongo-go-driver
// go get -u go.mongodb.org/mongo-driver
// go get -u github.com/joho/godotenv
import (
@@ -19,7 +19,7 @@ import (
"github.com/kataras/iris"
"github.com/mongodb/mongo-go-driver/mongo"
"go.mongodb.org/mongo-driver/mongo"
)
const version = "0.0.1"

View File

@@ -4,11 +4,11 @@ import (
"context"
"errors"
"github.com/mongodb/mongo-go-driver/bson"
"github.com/mongodb/mongo-go-driver/bson/primitive"
"github.com/mongodb/mongo-go-driver/mongo"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
// up to you:
// "github.com/mongodb/mongo-go-driver/mongo/options"
// "go.mongodb.org/mongo-driver/mongo/options"
)
type Movie struct {

View File

@@ -23,7 +23,7 @@ func main() {
app.Any("/iris-ws.js", websocket.ClientHandler())
// register static assets request path and system directory
app.StaticWeb("/js", "./static/assets/js")
app.HandleDir("/js", "./static/assets/js")
h := func(ctx iris.Context) {
ctx.ViewData("", page{PageID: "index page"})

View File

@@ -49,7 +49,7 @@ func newApp(db *DB) *iris.Application {
app.RegisterView(tmpl)
// Serve static files (css)
app.StaticWeb("/static", "./resources")
app.HandleDir("/static", "./resources")
indexHandler := func(ctx iris.Context) {
ctx.ViewData("URL_COUNT", db.Len())

View File

@@ -500,7 +500,7 @@ func main() {
// no need for any server-side template here,
// actually if you're going to just use vue without any
// back-end services, you can just stop afer this line and start the server.
app.StaticWeb("/", "./public")
app.HandleDir("/", "./public")
// configure the http sessions.
sess := sessions.New(sessions.Config{

View File

@@ -19,7 +19,7 @@ func main() {
// no need for any server-side template here,
// actually if you're going to just use vue without any
// back-end services, you can just stop afer this line and start the server.
app.StaticWeb("/", "./public")
app.HandleDir("/", "./public")
// configure the http sessions.
sess := sessions.New(sessions.Config{

View File

@@ -0,0 +1,44 @@
package main
import (
"time"
"github.com/kataras/iris"
// optionally, registers filters like `timesince`.
_ "github.com/flosch/pongo2-addons"
)
var startTime = time.Now()
func main() {
app := iris.New()
tmpl := iris.Django("./templates", ".html")
tmpl.Reload(true) // reload templates on each request (development mode)
tmpl.AddFunc("greet", func(s string) string { // {{greet(name)}}
return "Greetings " + s + "!"
})
// tmpl.RegisterFilter("myFilter", myFilter) // {{"simple input for filter"|myFilter}}
app.RegisterView(tmpl)
app.Get("/", hi)
// http://localhost:8080
app.Run(iris.Addr(":8080"), iris.WithCharset("UTF-8")) // defaults to that but you can change it.
}
func hi(ctx iris.Context) {
// ctx.ViewData("title", "Hi Page")
// ctx.ViewData("name", "iris")
// ctx.ViewData("serverStartTime", startTime)
// or if you set all view data in the same handler you can use the
// iris.Map/pongo2.Context/map[string]interface{}, look below:
ctx.View("hi.html", iris.Map{
"title": "Hi Page",
"name": "iris",
"serverStartTime": startTime,
})
}

View File

@@ -0,0 +1,12 @@
<html>
<head>
<title>{{title}}</title>
</head>
<body>
<h1>Hi {{name|capfirst}} </h1>
<h2>{{greet(name)}}</h2>
<h3>Server started about {{serverStartTime|timesince}}. Refresh the page to see different result</h3>
</body>
</html>

View File

@@ -14,7 +14,7 @@ func main() {
// we could serve your assets like this the shake of the example,
// never include the .go files there in production.
app.StaticWeb("/", "./client")
app.HandleDir("/", "./client")
app.Get("/", func(ctx iris.Context) {
ctx.ServeFile("./client/hello.html", false) // true for gzip.

View File

@@ -52,7 +52,7 @@ func main() {
})
// serves the npm browser websocket client usage example.
app.StaticWeb("/browserify", "./browserify")
app.HandleDir("/browserify", "./browserify")
app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

View File

@@ -35,7 +35,7 @@ func main() {
// see the inline javascript code i the websockets.html, this endpoint is used to connect to the server.
app.Get("/my_endpoint", ws.Handler())
app.StaticWeb("/js", "./static/js") // serve our custom javascript code
app.HandleDir("/js", "./static/js") // serve our custom javascript code
app.Get("/", func(ctx iris.Context) {
ctx.ViewData("", clientPage{"Client Page", "localhost:8080"})

View File

@@ -32,7 +32,7 @@ func main() {
ctx.Write(websocket.ClientSource)
})
app.StaticWeb("/js", "./static/js")
app.HandleDir("/js", "./static/js")
app.Get("/", func(ctx iris.Context) {
// send our custom javascript source file before client really asks for that
// using the go v1.8's HTTP/2 Push.

View File

@@ -38,7 +38,7 @@ func main() {
// serve the index.html and the javascript libraries at
// http://localhost:8080
app.StaticWeb("/", "./public")
app.HandleDir("/", "./public")
app.Run(iris.Addr("localhost:8080"), iris.WithoutPathCorrection)
}