mirror of
https://github.com/kataras/iris.git
synced 2025-12-23 21:07:03 +00:00
(#1554) Add support for all common compressions (write and read)
- Remove the context.Context interface and export the *context, the iris.Context now points to the pointer\nSupport compression and rate limiting in the FileServer\nBit of code organisation Former-commit-id: ad1c61bf968059510c6be9e7f2cceec7da70ba17
This commit is contained in:
@@ -54,9 +54,6 @@
|
||||
* [Reverse Routing](routing/reverse/main.go)
|
||||
* [Router Wrapper](routing/custom-wrapper/main.go)
|
||||
* [Custom Router](routing/custom-router/main.go)
|
||||
* Custom Context
|
||||
* [Method Overriding](routing/custom-context/method-overriding/main.go)
|
||||
* [New Implementation](routing/custom-context/new-implementation/main.go)
|
||||
* Subdomains
|
||||
* [Single](routing/subdomains/single/main.go)
|
||||
* [Multi](routing/subdomains/multi/main.go)
|
||||
@@ -129,12 +126,10 @@
|
||||
* [Bind Custom per type](request-body/read-custom-per-type/main.go)
|
||||
* [Bind Custom via Unmarshaler](request-body/read-custom-via-unmarshaler/main.go)
|
||||
* [Bind Many times](request-body/read-many/main.go)
|
||||
* [Read/Bind Gzip compressed data](request-body/read-gzip/main.go)
|
||||
* Response Writer
|
||||
* [Content Negotiation](response-writer/content-negotiation)
|
||||
* [Text, Markdown, YAML, HTML, JSON, JSONP, Msgpack, XML and Binary](response-writer/write-rest/main.go)
|
||||
* [Protocol Buffers](response-writer/protobuf/main.go)
|
||||
* [Write Gzip](response-writer/write-gzip/main.go)
|
||||
* [HTTP/2 Server Push](response-writer/http2push/main.go)
|
||||
* [Stream Writer](response-writer/stream-writer/main.go)
|
||||
* [Transactions](response-writer/transactions/main.go)
|
||||
@@ -143,6 +138,10 @@
|
||||
* Cache
|
||||
* [Simple](response-writer/cache/simple/main.go)
|
||||
* [Client-Side (304)](response-writer/cache/client-side/main.go)
|
||||
* Compression
|
||||
* [Server-Side](compression/main.go)
|
||||
* [Client-Side](compression/client/main.go)
|
||||
* [Client-Side (using Iris)](compress/client-using-iris/main.go)
|
||||
* Localization and Internationalization
|
||||
* [i18n](i18n/main.go)
|
||||
* Authentication, Authorization & Bot Detection
|
||||
|
||||
112
_examples/compression/client-using-iris/main.go
Normal file
112
_examples/compression/client-using-iris/main.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
)
|
||||
|
||||
const baseURL = "http://localhost:8080"
|
||||
|
||||
// Available options:
|
||||
// - "gzip",
|
||||
// - "deflate",
|
||||
// - "br" (for brotli),
|
||||
// - "snappy" and
|
||||
// - "s2"
|
||||
const encoding = context.BROTLI
|
||||
|
||||
var client = http.DefaultClient
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Running client example on: %s\n", baseURL)
|
||||
|
||||
getExample()
|
||||
postExample()
|
||||
}
|
||||
|
||||
func getExample() {
|
||||
endpoint := baseURL + "/"
|
||||
req, err := http.NewRequest(http.MethodGet, endpoint, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Required to receive server's compressed data.
|
||||
req.Header.Set("Accept-Encoding", encoding)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// decompress server's compressed reply.
|
||||
cr, err := context.NewCompressReader(resp.Body, encoding)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer cr.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(cr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Received from server: %s", string(body))
|
||||
}
|
||||
|
||||
type payload struct {
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
func postExample() {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
// Compress client's data.
|
||||
cw, err := context.NewCompressWriter(buf, encoding, -1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
json.NewEncoder(cw).Encode(payload{Username: "Edward"})
|
||||
|
||||
// `Close` or `Flush` required before `NewRequest` call.
|
||||
cw.Close()
|
||||
|
||||
endpoint := baseURL + "/"
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, endpoint, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Required to send gzip compressed data to the server.
|
||||
req.Header.Set("Content-Encoding", encoding)
|
||||
// Required to receive server's compressed data.
|
||||
req.Header.Set("Accept-Encoding", encoding)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Decompress server's compressed reply.
|
||||
cr, err := context.NewCompressReader(resp.Body, encoding)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer cr.Close() // Closes the request body too.
|
||||
|
||||
body, err := ioutil.ReadAll(cr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Server replied with: %s", string(body))
|
||||
}
|
||||
102
_examples/compression/client/main.go
Normal file
102
_examples/compression/client/main.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var client = http.DefaultClient
|
||||
|
||||
const baseURL = "http://localhost:8080"
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Running client example on: %s\n", baseURL)
|
||||
|
||||
getExample()
|
||||
postExample()
|
||||
}
|
||||
|
||||
func getExample() {
|
||||
endpoint := baseURL + "/"
|
||||
req, err := http.NewRequest(http.MethodGet, endpoint, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Required to receive server's compressed data.
|
||||
req.Header.Set("Accept-Encoding", "gzip")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// decompress server's compressed reply.
|
||||
r, err := gzip.NewReader(resp.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Received from server: %s", string(body))
|
||||
}
|
||||
|
||||
type payload struct {
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
func postExample() {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
// Compress client's data.
|
||||
w := gzip.NewWriter(buf)
|
||||
|
||||
b, err := json.Marshal(payload{Username: "Edward"})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
w.Write(b)
|
||||
w.Close()
|
||||
|
||||
endpoint := baseURL + "/"
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, endpoint, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Required to send gzip compressed data to the server.
|
||||
req.Header.Set("Content-Encoding", "gzip")
|
||||
// Required to receive server's compressed data.
|
||||
req.Header.Set("Accept-Encoding", "gzip")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Decompress server's compressed reply.
|
||||
r, err := gzip.NewReader(resp.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Server replied with: %s", string(body))
|
||||
}
|
||||
64
_examples/compression/main.go
Normal file
64
_examples/compression/main.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package main
|
||||
|
||||
import "github.com/kataras/iris/v12"
|
||||
|
||||
func main() {
|
||||
app := newApp()
|
||||
app.Logger().SetLevel("debug")
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
// HERE and you are ready to GO:
|
||||
app.Use(iris.Compress, iris.CompressReader)
|
||||
|
||||
app.Get("/", send)
|
||||
app.Post("/", receive)
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
type payload struct {
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
func send(ctx iris.Context) {
|
||||
ctx.JSON(payload{
|
||||
Username: "Makis",
|
||||
})
|
||||
}
|
||||
|
||||
func receive(ctx iris.Context) {
|
||||
var p payload
|
||||
if err := ctx.ReadJSON(&p); err != nil {
|
||||
ctx.Application().Logger().Debugf("ReadJSON: %v", err)
|
||||
}
|
||||
|
||||
ctx.WriteString(p.Username)
|
||||
}
|
||||
|
||||
/* Manually:
|
||||
func enableCompression(ctx iris.Context) {
|
||||
// Enable writing using compression (deflate, gzip, brotli, snappy, s2):
|
||||
err := ctx.Compress(true)
|
||||
if err != nil {
|
||||
ctx.Application().Logger().Debugf("writer: %v", err)
|
||||
// if you REQUIRE server to SEND compressed data then `return` here.
|
||||
// return
|
||||
}
|
||||
|
||||
// Enable reading and binding request's compressed data:
|
||||
err = ctx.CompressReader(true)
|
||||
if err != nil &&
|
||||
// on GET we don't expect writing with gzip from client
|
||||
ctx.Method() != iris.MethodGet {
|
||||
ctx.Application().Logger().Debugf("reader: %v", err)
|
||||
// if you REQUIRE server to RECEIVE only
|
||||
// compressed data then `return` here.
|
||||
// return
|
||||
}
|
||||
|
||||
ctx.Next()
|
||||
}
|
||||
*/
|
||||
41
_examples/compression/main_test.go
Normal file
41
_examples/compression/main_test.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
func TestCompression(t *testing.T) {
|
||||
app := newApp()
|
||||
e := httptest.New(t, app)
|
||||
|
||||
var expectedReply = payload{Username: "Makis"}
|
||||
body := e.GET("/").WithHeader(context.AcceptEncodingHeaderKey, context.GZIP).Expect().
|
||||
Status(httptest.StatusOK).
|
||||
ContentEncoding(context.GZIP).
|
||||
ContentType(context.ContentJSONHeaderValue).Body().Raw()
|
||||
|
||||
// Note that .Expect() consumes the response body
|
||||
// and stores it to unexported "contents" field
|
||||
// therefore, we retrieve it as string and put it to a new buffer.
|
||||
r := strings.NewReader(body)
|
||||
cr, err := context.NewCompressReader(r, context.GZIP)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cr.Close()
|
||||
|
||||
var got payload
|
||||
if err = json.NewDecoder(cr).Decode(&got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expectedReply, got) {
|
||||
t.Fatalf("expected %#+v but got %#+v", expectedReply, got)
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,3 @@ func negronilikeTestMiddleware(w http.ResponseWriter, r *http.Request, next http
|
||||
w.WriteHeader(iris.StatusBadRequest)
|
||||
w.Write([]byte("Bad request"))
|
||||
}
|
||||
|
||||
// Look "routing/custom-context" if you want to convert a custom handler with a custom Context
|
||||
// to a context.Handler.
|
||||
|
||||
@@ -29,6 +29,3 @@ func main() {
|
||||
func nativeTestMiddleware(w http.ResponseWriter, r *http.Request) {
|
||||
println("Request path: " + r.URL.Path)
|
||||
}
|
||||
|
||||
// Look "routing/custom-context" if you want to convert a custom handler with a custom Context
|
||||
// to a context.Handler.
|
||||
|
||||
@@ -23,7 +23,7 @@ func newApp() *iris.Application {
|
||||
// if end developer does not managed to handle it by hand.
|
||||
IndexName: "/index.html",
|
||||
// When files should served under compression.
|
||||
Gzip: false,
|
||||
Compress: 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).
|
||||
|
||||
@@ -54,7 +54,7 @@ func main() {
|
||||
filesRouter := app.Party("/files")
|
||||
{
|
||||
filesRouter.HandleDir("/", uploadDir, iris.DirOptions{
|
||||
Gzip: false,
|
||||
Compress: true,
|
||||
ShowList: true,
|
||||
|
||||
// Optionally, force-send files to the client inside of showing to the browser.
|
||||
|
||||
@@ -83,7 +83,11 @@
|
||||
{{ range $idx, $file := .Files }}
|
||||
<tr>
|
||||
<td>{{ $idx }}</td>
|
||||
{{ if $file.Download }}
|
||||
<td><a href="{{ $file.Path }}" title="{{ $file.ModTime }}" download>{{ $file.Name }}</a></td>
|
||||
{{ else }}
|
||||
<td><a href="{{ $file.Path }}" title="{{ $file.ModTime }}">{{ $file.Name }}</a></td>
|
||||
{{ end }}
|
||||
{{ if $file.Info.IsDir }}
|
||||
<td>Dir</td>
|
||||
{{ else }}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := newApp()
|
||||
app.Logger().SetLevel("debug")
|
||||
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
type payload struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
|
||||
// GzipReader is a middleware which enables gzip decompression,
|
||||
// when client sends gzip compressed data.
|
||||
//
|
||||
// A shortcut of:
|
||||
// func(ctx iris.Context) {
|
||||
// ctx.GzipReader(true)
|
||||
// ctx.Next()
|
||||
// }
|
||||
app.Use(iris.GzipReader)
|
||||
|
||||
app.Post("/", func(ctx iris.Context) {
|
||||
// Bind incoming gzip compressed JSON to "p".
|
||||
var p payload
|
||||
if err := ctx.ReadJSON(&p); err != nil {
|
||||
ctx.StopWithError(iris.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Send back the message as plain text.
|
||||
ctx.WriteString(p.Message)
|
||||
})
|
||||
|
||||
return app
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
func TestGzipReader(t *testing.T) {
|
||||
app := newApp()
|
||||
|
||||
expected := payload{Message: "test"}
|
||||
b, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
w := gzip.NewWriter(buf)
|
||||
_, err = w.Write(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
e := httptest.New(t, app)
|
||||
// send gzip compressed.
|
||||
e.POST("/").WithHeader("Content-Encoding", "gzip").WithHeader("Content-Type", "application/json").
|
||||
WithBytes(buf.Bytes()).Expect().Status(httptest.StatusOK).Body().Equal(expected.Message)
|
||||
// raw.
|
||||
e.POST("/").WithJSON(expected).Expect().Status(httptest.StatusOK).Body().Equal(expected.Message)
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package main
|
||||
|
||||
import "github.com/kataras/iris/v12"
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
// app.Use(iris.Gzip)
|
||||
// func(ctx iris.Context) { ctx.Gzip(true/false)}
|
||||
// OR:
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.WriteGzip([]byte("Hello World!"))
|
||||
ctx.Header("X-Custom",
|
||||
"Headers can be set here after WriteGzip as well, because the data are kept before sent to the client when using the context's GzipResponseWriter and ResponseRecorder.")
|
||||
})
|
||||
|
||||
app.Get("/2", func(ctx iris.Context) {
|
||||
// same as the `WriteGzip`.
|
||||
// However GzipResponseWriter gives you more options, like
|
||||
// reset data, disable and more, look its methods.
|
||||
ctx.GzipResponseWriter().WriteString("Hello World!")
|
||||
})
|
||||
|
||||
app.Listen(":8080")
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package main
|
||||
|
||||
// In this package I'll show you how to override the existing Context's functions and methods.
|
||||
// You can easly navigate to the custom-context example to see how you can add new functions
|
||||
// to your own context (need a custom handler).
|
||||
//
|
||||
// This way is far easier to understand and it's faster when you want to override existing methods:
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/context"
|
||||
)
|
||||
|
||||
// Create your own custom Context, put any fields you wanna need.
|
||||
type MyContext struct {
|
||||
// Optional Part 1: embed (optional but required if you don't want to override all context's methods)
|
||||
iris.Context
|
||||
}
|
||||
|
||||
var _ iris.Context = &MyContext{} // optionally: validate on compile-time if MyContext implements context.Context.
|
||||
|
||||
// The only one important if you will override the Context
|
||||
// with an embedded context.Context inside it.
|
||||
// Required in order to run the handlers via this "*MyContext".
|
||||
func (ctx *MyContext) Do(handlers context.Handlers) {
|
||||
context.Do(ctx, handlers)
|
||||
}
|
||||
|
||||
// The second one important if you will override the Context
|
||||
// with an embedded context.Context inside it.
|
||||
// Required in order to run the chain of handlers via this "*MyContext".
|
||||
func (ctx *MyContext) Next() {
|
||||
context.Next(ctx)
|
||||
}
|
||||
|
||||
// Override any context's method you want...
|
||||
// [...]
|
||||
|
||||
func (ctx *MyContext) HTML(format string, args ...interface{}) (int, error) {
|
||||
ctx.Application().Logger().Infof("Executing .HTML function from MyContext")
|
||||
|
||||
ctx.ContentType("text/html")
|
||||
return ctx.Writef(format, args...)
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
// app.Logger().SetLevel("debug")
|
||||
|
||||
// The only one Required:
|
||||
// here is how you define how your own context will
|
||||
// be created and acquired from the iris' generic context pool.
|
||||
app.ContextPool.Attach(func() iris.Context {
|
||||
return &MyContext{
|
||||
// Optional Part 3:
|
||||
Context: context.NewContext(app),
|
||||
}
|
||||
})
|
||||
|
||||
// Register a view engine on .html files inside the ./view/** directory.
|
||||
app.RegisterView(iris.HTML("./view", ".html"))
|
||||
|
||||
// register your route, as you normally do
|
||||
app.Handle("GET", "/", recordWhichContextJustForProofOfConcept, func(ctx iris.Context) {
|
||||
// use the context's overridden HTML method.
|
||||
ctx.HTML("<h1> Hello from my custom context's HTML! </h1>")
|
||||
})
|
||||
|
||||
// this will be executed by the MyContext.Context
|
||||
// if MyContext is not directly define the View function by itself.
|
||||
app.Handle("GET", "/hi/{firstname:alphabetical}", recordWhichContextJustForProofOfConcept, func(ctx iris.Context) {
|
||||
firstname := ctx.Params().Get("firstname")
|
||||
|
||||
ctx.ViewData("firstname", firstname)
|
||||
ctx.Gzip(true)
|
||||
|
||||
ctx.View("hi.html")
|
||||
})
|
||||
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
// should always print "($PATH) Handler is executing from 'MyContext'"
|
||||
func recordWhichContextJustForProofOfConcept(ctx iris.Context) {
|
||||
ctx.Application().Logger().Infof("(%s) Handler is executing from: '%s'", ctx.Path(), reflect.TypeOf(ctx).Elem().Name())
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
// Look "new-implementation" to see how you can create an entirely new Context with new functions.
|
||||
@@ -1 +0,0 @@
|
||||
<h1> Hi {{.firstname}} </h1>
|
||||
@@ -1,103 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/sessions"
|
||||
)
|
||||
|
||||
// Owner is our application structure, it contains the methods or fields we need,
|
||||
// think it as the owner of our *Context.
|
||||
type Owner struct {
|
||||
// define here the fields that are global
|
||||
// and shared to all clients.
|
||||
sessionsManager *sessions.Sessions
|
||||
}
|
||||
|
||||
// this package-level variable "application" will be used inside context to communicate with our global Application.
|
||||
var owner = &Owner{
|
||||
sessionsManager: sessions.New(sessions.Config{Cookie: "mysessioncookie"}),
|
||||
}
|
||||
|
||||
// Context is our custom context.
|
||||
// Let's implement a context which will give us access
|
||||
// to the client's Session with a trivial `ctx.Session()` call.
|
||||
type Context struct {
|
||||
iris.Context
|
||||
session *sessions.Session
|
||||
}
|
||||
|
||||
// Session returns the current client's session.
|
||||
func (ctx *Context) Session() *sessions.Session {
|
||||
// this help us if we call `Session()` multiple times in the same handler
|
||||
if ctx.session == nil {
|
||||
// start a new session if not created before.
|
||||
ctx.session = owner.sessionsManager.Start(ctx.Context)
|
||||
}
|
||||
|
||||
return ctx.session
|
||||
}
|
||||
|
||||
// Bold will send a bold text to the client.
|
||||
func (ctx *Context) Bold(text string) {
|
||||
ctx.HTML("<b>" + text + "</b>")
|
||||
}
|
||||
|
||||
var contextPool = sync.Pool{New: func() interface{} {
|
||||
return &Context{}
|
||||
}}
|
||||
|
||||
func acquire(original iris.Context) *Context {
|
||||
ctx := contextPool.Get().(*Context)
|
||||
ctx.Context = original // set the context to the original one in order to have access to iris's implementation.
|
||||
ctx.session = nil // reset the session
|
||||
return ctx
|
||||
}
|
||||
|
||||
func release(ctx *Context) {
|
||||
contextPool.Put(ctx)
|
||||
}
|
||||
|
||||
// Handler will convert our handler of func(*Context) to an iris Handler,
|
||||
// in order to be compatible with the HTTP API.
|
||||
func Handler(h func(*Context)) iris.Handler {
|
||||
return func(original iris.Context) {
|
||||
ctx := acquire(original)
|
||||
h(ctx)
|
||||
release(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
|
||||
// Work as you did before, the only difference
|
||||
// is that the original context.Handler should be wrapped with our custom
|
||||
// `Handler` function.
|
||||
app.Get("/", Handler(func(ctx *Context) {
|
||||
ctx.Bold("Hello from our *Context")
|
||||
}))
|
||||
|
||||
app.Post("/set", Handler(func(ctx *Context) {
|
||||
nameFieldValue := ctx.FormValue("name")
|
||||
ctx.Session().Set("name", nameFieldValue)
|
||||
ctx.Writef("set session = " + nameFieldValue)
|
||||
}))
|
||||
|
||||
app.Get("/get", Handler(func(ctx *Context) {
|
||||
name := ctx.Session().GetString("name")
|
||||
ctx.Writef(name)
|
||||
}))
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := newApp()
|
||||
|
||||
// GET: http://localhost:8080
|
||||
// POST: http://localhost:8080/set
|
||||
// GET: http://localhost:8080/get
|
||||
app.Listen(":8080")
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
func TestCustomContextNewImpl(t *testing.T) {
|
||||
app := newApp()
|
||||
e := httptest.New(t, app, httptest.URL("http://localhost:8080"))
|
||||
|
||||
e.GET("/").Expect().
|
||||
Status(httptest.StatusOK).
|
||||
ContentType("text/html").
|
||||
Body().Equal("<b>Hello from our *Context</b>")
|
||||
|
||||
expectedName := "iris"
|
||||
e.POST("/set").WithFormField("name", expectedName).Expect().
|
||||
Status(httptest.StatusOK).
|
||||
Body().Equal("set session = " + expectedName)
|
||||
|
||||
e.GET("/get").Expect().
|
||||
Status(httptest.StatusOK).
|
||||
Body().Equal(expectedName)
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
Build(provider router.RoutesProvider) error
|
||||
- RouteExists reports whether a particular route exists.
|
||||
RouteExists(ctx iris.Context, method, path string) bool
|
||||
- FireErrorCode(ctx context.Context) should handle the given ctx.GetStatusCode().
|
||||
- FireErrorCode(ctx iris.Context) should handle the given ctx.GetStatusCode().
|
||||
|
||||
For a more detailed, complete and useful example
|
||||
you can take a look at the iris' router itself which is located at:
|
||||
|
||||
@@ -179,7 +179,7 @@ func main() {
|
||||
app.Get("/profile/{id:uint64 min(1)}/friends/{friendid:uint64 min(1) else 504}", func(ctx iris.Context) {
|
||||
id := ctx.Params().GetUint64Default("id", 0)
|
||||
friendid := ctx.Params().GetUint64Default("friendid", 0)
|
||||
ctx.Writef("Hello id: %d looking for friend id: ", id, friendid)
|
||||
ctx.Writef("Hello id: %d looking for friend id: %d", id, friendid)
|
||||
}) // this will throw e 504 error code instead of 404 if all route's macros not passed.
|
||||
|
||||
// :uint8 0 to 255.
|
||||
|
||||
@@ -17,7 +17,7 @@ func main() {
|
||||
app := iris.New()
|
||||
|
||||
app.Get("/users", func(ctx iris.Context) {
|
||||
ctx.Gzip(true)
|
||||
ctx.Compress(true)
|
||||
ctx.ContentType("text/html")
|
||||
|
||||
userList := []string{
|
||||
@@ -35,11 +35,9 @@ func main() {
|
||||
// template.UserList(userList, buffer)
|
||||
// ctx.Write(buffer.Bytes())
|
||||
|
||||
// using an io.Writer for automatic buffer management (i.e. hero built-in buffer pool),
|
||||
// iris context implements the io.Writer by its ResponseWriter
|
||||
// which is an enhanced version of the standard http.ResponseWriter
|
||||
// but still 100% compatible, GzipResponseWriter too:
|
||||
// _, err := template.UserListToWriter(userList, ctx.GzipResponseWriter())
|
||||
// iris context implements the io.Writer:
|
||||
// _, err := template.UserListToWriter(userList, ctx)
|
||||
// OR:
|
||||
buffer := new(bytes.Buffer)
|
||||
template.UserList(userList, buffer)
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ func main() {
|
||||
// - {{ current }}
|
||||
app.RegisterView(iris.HTML("./templates", ".html"))
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.ViewData("Name", "iris") // the .Name inside the ./templates/hi.html
|
||||
ctx.Gzip(true) // enable gzip for big files
|
||||
ctx.View("hi.html") // render the template with the file name relative to the './templates'
|
||||
ctx.Compress(true) // enable compression based on Accept-Encoding (e.g. "gzip").
|
||||
ctx.ViewData("Name", "iris") // the .Name inside the ./templates/hi.html.
|
||||
ctx.View("hi.html") // render the template with the file name relative to the './templates'.
|
||||
})
|
||||
|
||||
// http://localhost:8080/
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
// ExecuteTemplate renders a "tmpl" partial template to the `context#ResponseWriter`.
|
||||
// ExecuteTemplate renders a "tmpl" partial template to the `Context.ResponseWriter`.
|
||||
func ExecuteTemplate(ctx iris.Context, tmpl templates.Partial) {
|
||||
ctx.Gzip(true)
|
||||
ctx.Compress(true)
|
||||
ctx.ContentType("text/html")
|
||||
templates.WriteTemplate(ctx.ResponseWriter(), tmpl)
|
||||
templates.WriteTemplate(ctx, tmpl)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ func main() {
|
||||
// TIP: append .Reload(true) to reload the templates on each request.
|
||||
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.Gzip(true)
|
||||
ctx.Compress(true)
|
||||
ctx.ViewData("", mypage{"My Page title", "Hello world!"})
|
||||
ctx.View("mypage.html")
|
||||
// Note that: you can pass "layout" : "otherLayout.html" to bypass the config's Layout property
|
||||
|
||||
@@ -201,9 +201,9 @@ func AssetNames() []string {
|
||||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
"views/includes/_partial.jet": viewsIncludes_partialJet,
|
||||
"views/includes/blocks.jet": viewsIncludesBlocksJet,
|
||||
"views/index.jet": viewsIndexJet,
|
||||
"views/includes/_partial.jet": viewsIncludes_partialJet,
|
||||
"views/includes/blocks.jet": viewsIncludesBlocksJet,
|
||||
"views/index.jet": viewsIndexJet,
|
||||
"views/layouts/application.jet": viewsLayoutsApplicationJet,
|
||||
}
|
||||
|
||||
@@ -246,15 +246,16 @@ type bintree struct {
|
||||
Func func() (*asset, error)
|
||||
Children map[string]*bintree
|
||||
}
|
||||
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"views": &bintree{nil, map[string]*bintree{
|
||||
"includes": &bintree{nil, map[string]*bintree{
|
||||
"_partial.jet": &bintree{viewsIncludes_partialJet, map[string]*bintree{}},
|
||||
"blocks.jet": &bintree{viewsIncludesBlocksJet, map[string]*bintree{}},
|
||||
"views": {nil, map[string]*bintree{
|
||||
"includes": {nil, map[string]*bintree{
|
||||
"_partial.jet": {viewsIncludes_partialJet, map[string]*bintree{}},
|
||||
"blocks.jet": {viewsIncludesBlocksJet, map[string]*bintree{}},
|
||||
}},
|
||||
"index.jet": &bintree{viewsIndexJet, map[string]*bintree{}},
|
||||
"layouts": &bintree{nil, map[string]*bintree{
|
||||
"application.jet": &bintree{viewsLayoutsApplicationJet, map[string]*bintree{}},
|
||||
"index.jet": {viewsIndexJet, map[string]*bintree{}},
|
||||
"layouts": {nil, map[string]*bintree{
|
||||
"application.jet": {viewsLayoutsApplicationJet, map[string]*bintree{}},
|
||||
}},
|
||||
}},
|
||||
}}
|
||||
@@ -305,4 +306,3 @@ func _filePath(dir, name string) string {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ func main() {
|
||||
app.HandleDir("/", "./client")
|
||||
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
// ctx.Gzip(true)
|
||||
// ctx.Compress(true)
|
||||
ctx.ServeFile("./client/hello.html")
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user