mirror of
https://github.com/kataras/iris.git
synced 2025-03-21 11:16:28 +01:00
This commit is contained in:
parent
333be428c4
commit
cf0338d342
|
@ -364,6 +364,8 @@ Response:
|
||||||
|
|
||||||
Other Improvements:
|
Other Improvements:
|
||||||
|
|
||||||
|
- Fix [#1621](https://github.com/kataras/iris/issues/1621) and add a new `cache.WithKey` to customize the cached entry key.
|
||||||
|
|
||||||
- Add a `Response() *http.Response` to the Response Recorder.
|
- Add a `Response() *http.Response` to the Response Recorder.
|
||||||
- Fix Response Recorder `Flush` when transfer-encoding is `chunked`.
|
- Fix Response Recorder `Flush` when transfer-encoding is `chunked`.
|
||||||
- Fix Response Recorder `Clone` concurrent access afterwards.
|
- Fix Response Recorder `Clone` concurrent access afterwards.
|
||||||
|
|
86
_examples/response-writer/cache/simple/main.go
vendored
86
_examples/response-writer/cache/simple/main.go
vendored
|
@ -4,16 +4,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12"
|
"github.com/kataras/iris/v12"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12/cache"
|
"github.com/kataras/iris/v12/cache"
|
||||||
|
"github.com/kataras/iris/v12/middleware/basicauth"
|
||||||
)
|
)
|
||||||
|
|
||||||
var markdownContents = []byte(`## Hello Markdown
|
var markdownContents = []byte(`## Hello Markdown
|
||||||
|
|
||||||
This is a sample of Markdown contents
|
This is a sample of Markdown contents
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Features
|
Features
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
@ -23,36 +21,7 @@ All features of Sundown are supported, including:
|
||||||
the --tidy option. Without --tidy, the differences are
|
the --tidy option. Without --tidy, the differences are
|
||||||
mostly in whitespace and entity escaping, where blackfriday is
|
mostly in whitespace and entity escaping, where blackfriday is
|
||||||
more consistent and cleaner.
|
more consistent and cleaner.
|
||||||
|
`)
|
||||||
* **Common extensions**, including table support, fenced code
|
|
||||||
blocks, autolinks, strikethroughs, non-strict emphasis, etc.
|
|
||||||
|
|
||||||
* **Safety**. Blackfriday is paranoid when parsing, making it safe
|
|
||||||
to feed untrusted user input without fear of bad things
|
|
||||||
happening. The test suite stress tests this and there are no
|
|
||||||
known inputs that make it crash. If you find one, please let me
|
|
||||||
know and send me the input that does it.
|
|
||||||
|
|
||||||
NOTE: "safety" in this context means *runtime safety only*. In order to
|
|
||||||
protect yourself against JavaScript injection in untrusted content, see
|
|
||||||
[this example](https://github.com/russross/blackfriday#sanitize-untrusted-content).
|
|
||||||
|
|
||||||
* **Fast processing**. It is fast enough to render on-demand in
|
|
||||||
most web applications without having to cache the output.
|
|
||||||
|
|
||||||
* **Routine safety**. You can run multiple parsers in different
|
|
||||||
goroutines without ill effect. There is no dependence on global
|
|
||||||
shared state.
|
|
||||||
|
|
||||||
* **Minimal dependencies**. Blackfriday only depends on standard
|
|
||||||
library packages in Go. The source code is pretty
|
|
||||||
self-contained, so it is easy to add to any project, including
|
|
||||||
Google App Engine projects.
|
|
||||||
|
|
||||||
* **Standards compliant**. Output successfully validates using the
|
|
||||||
W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional.
|
|
||||||
|
|
||||||
[this is a link](https://github.com/kataras/iris) `)
|
|
||||||
|
|
||||||
// Cache should not be used on handlers that contain dynamic data.
|
// Cache should not be used on handlers that contain dynamic data.
|
||||||
// Cache is a good and a must-feature on static content, i.e "about page" or for a whole blog site.
|
// Cache is a good and a must-feature on static content, i.e "about page" or for a whole blog site.
|
||||||
|
@ -63,6 +32,30 @@ func main() {
|
||||||
// saves its content on the first request and serves it instead of re-calculating the content.
|
// saves its content on the first request and serves it instead of re-calculating the content.
|
||||||
// After 10 seconds it will be cleared and reset.
|
// After 10 seconds it will be cleared and reset.
|
||||||
|
|
||||||
|
pages := app.Party("/pages")
|
||||||
|
pages.Use(cache.Handler(10 * time.Second)) // Per Party.
|
||||||
|
pages.Get("/", pagesIndex)
|
||||||
|
pages.Post("/", pagesIndexPost)
|
||||||
|
|
||||||
|
// Note: on authenticated requests
|
||||||
|
// the cache middleare does not run at all (see iris/cache/ruleset).
|
||||||
|
auth := basicauth.Default(map[string]string{
|
||||||
|
"admin": "admin",
|
||||||
|
})
|
||||||
|
app.Get("/protected", auth, cache.Handler(5*time.Second), protected)
|
||||||
|
|
||||||
|
// Set custom cache key/identifier,
|
||||||
|
// for the sake of the example
|
||||||
|
// we will SHARE the keys on both GET and POST routes
|
||||||
|
// so the first one is executed that's the body
|
||||||
|
// for both of the routes. Please don't do that
|
||||||
|
// on production, this is just an example.
|
||||||
|
custom := app.Party("/custom")
|
||||||
|
custom.Use(cache.WithKey("shared"))
|
||||||
|
custom.Use(cache.Handler(10 * time.Second))
|
||||||
|
custom.Get("/", customIndex)
|
||||||
|
custom.Post("/", customIndexPost)
|
||||||
|
|
||||||
app.Listen(":8080")
|
app.Listen(":8080")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +67,32 @@ func writeMarkdown(ctx iris.Context) {
|
||||||
ctx.Markdown(markdownContents)
|
ctx.Markdown(markdownContents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pagesIndex(ctx iris.Context) {
|
||||||
|
println("Handler executed. Content refreshed.")
|
||||||
|
ctx.WriteString("GET: hello")
|
||||||
|
}
|
||||||
|
|
||||||
|
func pagesIndexPost(ctx iris.Context) {
|
||||||
|
println("Handler executed. Content refreshed.")
|
||||||
|
ctx.WriteString("POST: hello")
|
||||||
|
}
|
||||||
|
|
||||||
|
func protected(ctx iris.Context) {
|
||||||
|
username, _, _ := ctx.Request().BasicAuth()
|
||||||
|
ctx.Writef("Hello, %s!", username)
|
||||||
|
}
|
||||||
|
|
||||||
|
func customIndex(ctx iris.Context) {
|
||||||
|
ctx.WriteString("Contents from GET custom index")
|
||||||
|
}
|
||||||
|
|
||||||
|
func customIndexPost(ctx iris.Context) {
|
||||||
|
ctx.WriteString("Contents from POST custom index")
|
||||||
|
}
|
||||||
|
|
||||||
/* Note that `HandleDir` does use the browser's disk caching by-default
|
/* Note that `HandleDir` does use the browser's disk caching by-default
|
||||||
therefore, register the cache handler AFTER any HandleDir calls,
|
therefore, register the cache handler AFTER any HandleDir calls,
|
||||||
for a faster solution that server doesn't need to keep track of the response
|
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 */
|
navigate to https://github.com/kataras/iris/blob/master/_examples/cache/client-side/main.go.
|
||||||
|
|
||||||
|
The `HandleDir` has its own cache mechanism, read the 'file-server' examples. */
|
||||||
|
|
12
cache/cache.go
vendored
12
cache/cache.go
vendored
|
@ -34,6 +34,18 @@ import (
|
||||||
"github.com/kataras/iris/v12/context"
|
"github.com/kataras/iris/v12/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// WithKey sets a custom entry key for cached pages.
|
||||||
|
// Should be prepended to the cache handler.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// app.Get("/", cache.WithKey("custom-key"), cache.Handler(time.Minute), mainHandler)
|
||||||
|
func WithKey(key string) context.Handler {
|
||||||
|
return func(ctx *context.Context) {
|
||||||
|
client.SetKey(ctx, key)
|
||||||
|
ctx.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cache accepts the cache expiration duration.
|
// Cache accepts the cache expiration duration.
|
||||||
// If the "expiration" input argument is invalid, <=2 seconds,
|
// If the "expiration" input argument is invalid, <=2 seconds,
|
||||||
// then expiration is taken by the "cache-control's maxage" header.
|
// then expiration is taken by the "cache-control's maxage" header.
|
||||||
|
|
50
cache/client/handler.go
vendored
50
cache/client/handler.go
vendored
|
@ -1,6 +1,7 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -73,6 +74,48 @@ func parseLifeChanger(ctx *context.Context) entry.LifeChanger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const entryKeyContextKey = "iris.cache.server.entry.key"
|
||||||
|
|
||||||
|
// SetKey sets a custom entry key for cached pages.
|
||||||
|
// See root package-level `WithKey` instead.
|
||||||
|
func SetKey(ctx *context.Context, key string) {
|
||||||
|
ctx.Values().Set(entryKeyContextKey, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKey returns the entry key for the current page.
|
||||||
|
func GetKey(ctx *context.Context) string {
|
||||||
|
return ctx.Values().GetString(entryKeyContextKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOrSetKey(ctx *context.Context) string {
|
||||||
|
if key := GetKey(ctx); key != "" {
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: by-default the rules(ruleset pkg)
|
||||||
|
// explictly ignores the cache handler
|
||||||
|
// execution on authenticated requests
|
||||||
|
// and immediately runs the next handler:
|
||||||
|
// if !h.rule.Claim(ctx) ...see `Handler` method.
|
||||||
|
// So the below two lines are useless,
|
||||||
|
// however we add it for cases
|
||||||
|
// that the end-developer messedup with the rules
|
||||||
|
// and by accident allow authenticated cached results.
|
||||||
|
username, password, _ := ctx.Request().BasicAuth()
|
||||||
|
authPart := username + strings.Repeat("*", len(password))
|
||||||
|
|
||||||
|
key := ctx.Method() + authPart
|
||||||
|
|
||||||
|
u := ctx.Request().URL
|
||||||
|
if !u.IsAbs() {
|
||||||
|
key += ctx.Scheme() + ctx.Host()
|
||||||
|
}
|
||||||
|
key += u.String()
|
||||||
|
|
||||||
|
SetKey(ctx, key)
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) ServeHTTP(ctx *context.Context) {
|
func (h *Handler) ServeHTTP(ctx *context.Context) {
|
||||||
// check for pre-cache validators, if at least one of them return false
|
// check for pre-cache validators, if at least one of them return false
|
||||||
// for this specific request, then skip the whole cache
|
// for this specific request, then skip the whole cache
|
||||||
|
@ -90,16 +133,11 @@ func (h *Handler) ServeHTTP(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
scheme := "http"
|
|
||||||
if ctx.Request().TLS != nil {
|
|
||||||
scheme = "https"
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
response *entry.Response
|
response *entry.Response
|
||||||
valid = false
|
valid = false
|
||||||
// unique per subdomains and paths with different url query.
|
// unique per subdomains and paths with different url query.
|
||||||
key = scheme + ctx.Host() + ctx.Request().URL.RequestURI()
|
key = getOrSetKey(ctx)
|
||||||
)
|
)
|
||||||
|
|
||||||
h.mu.RLock()
|
h.mu.RLock()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user