mirror of
https://github.com/kataras/iris.git
synced 2025-01-22 18:21:03 +01:00
release version 12.2.10
This commit is contained in:
parent
12546322eb
commit
113ce190e6
|
@ -19,10 +19,15 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
|
|||
|
||||
**How to upgrade**: Open your command-line and execute this command: `go get github.com/kataras/iris/v12@latest` and `go mod tidy -compat=1.21`.
|
||||
|
||||
|
||||
# Next
|
||||
|
||||
Changes apply to `main` branch.
|
||||
|
||||
# Thu, 18 Jan 2024 | v12.2.10
|
||||
|
||||
- Simplify the `/core/host` subpackage and remove its `DeferFlow` and `RestoreFlow` methods.
|
||||
- Fix internal `trimHandlerName` and other minor stuff.
|
||||
- New `iris.NonBlocking()` configuration option to run the server without blocking the main routine, `Application.Wait(context.Context) error` method can be used to block and wait for the server to be up and running. Example:
|
||||
|
||||
```go
|
||||
|
|
|
@ -6,7 +6,7 @@ Try the official [Iris Command Line Interface](https://github.com/kataras/iris-c
|
|||
|
||||
# <a href="https://iris-go.com"><img src="https://iris-go.com/images/logo-new-lq-45.png"></a> Iris Web Framework <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg" /> <a href="README_JA.md"><img width="20px" height="20px" src="https://iris-go.com/images/flag-japan.svg" /></a> </a> <a href="README_FR.md"><img width="20px" src="https://iris-go.com/images/flag-france.svg" /></a> <a href="README_ZH_HANT.md"><img width="20px" src="https://iris-go.com/images/flag-taiwan.svg" /></a> <a href="README_ZH_HANS.md"><img width="20px" src="https://iris-go.com/images/flag-china.svg" /></a> <a href="README_ES.md"><img width="20px" src="https://iris-go.com/images/flag-spain.png" /></a> <a href="README_FA.md"><img width="20px" src="https://iris-go.com/images/flag-iran.svg" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg" /></a> <a href="README_KO.md"><img width="20px" src="https://iris-go.com/images/flag-south-korea.svg?v=12" /></a> <a href="README_PT_BR.md"><img width="20px" height="20px" src="https://iris-go.com/images/flag-brazil.svg" /></a> <a href="README_VN.md"><img width="20px" height="20px" src="https://iris-go.com/images/flag-vietnam.svg" /></a>
|
||||
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) <!--[![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)--> [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) <!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)--> <!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) <!--[![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)--> [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) <!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v)--> <!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
|
||||
Iris is a fast, simple yet fully featured and very efficient web framework for Go.
|
||||
|
||||
|
@ -586,7 +586,7 @@ The only requirement is the [Go Programming Language](https://go.dev/dl/).
|
|||
$ mkdir myapp
|
||||
$ cd myapp
|
||||
$ go mod init myapp
|
||||
$ go get github.com/kataras/iris/v12@latest # or @v12.2.9
|
||||
$ go get github.com/kataras/iris/v12@latest # or @v
|
||||
```
|
||||
|
||||
<details><summary>Install on existing project</summary>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Iris Web Framework
|
||||
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://iris-go.com/donate)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.10)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://iris-go.com/donate)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
|
||||
Iris es un framework web rápido, simple pero con muchas funcionalidades y muy eficiente para Go. Proporciona una base bellamente expresiva y fácil de usar para su próximo sitio web o API.
|
||||
|
||||
|
@ -49,7 +49,7 @@ $ go run ejemplo.go
|
|||
|
||||
Iris contiene un extenso y completo **[wiki](https://www.iris-go.com/#ebookDonateForm)** que facilita comenzar con el framework.
|
||||
|
||||
Para obtener una documentación técnica más detallada, puede dirigirse a nuestros [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9). Y para código ejecutable siempre puede visitar el subdirectorio del repositorio [\_examples](_examples/).
|
||||
Para obtener una documentación técnica más detallada, puede dirigirse a nuestros [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v). Y para código ejecutable siempre puede visitar el subdirectorio del repositorio [\_examples](_examples/).
|
||||
|
||||
### ¿Te gusta leer mientras viajas?
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
# Iris Web Framework
|
||||
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://iris-go.com/donate)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://iris-go.com/donate)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
|
||||
آیریس یک چارچوب وب پر سرعت ، ساده و در عین حال کاملاً برجسته و بسیار کارآمد برای Go است.
|
||||
</div>
|
||||
|
@ -137,7 +137,7 @@ func (c *userController) PutBy(id uint64, req request) response {
|
|||
$ mkdir myapp
|
||||
$ cd myapp
|
||||
$ go mod init myapp
|
||||
$ go get github.com/kataras/iris/v12@latest # or @v12.2.9
|
||||
$ go get github.com/kataras/iris/v12@latest # or @v
|
||||
```
|
||||
|
||||
<div dir="rtl">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Iris Web Framework
|
||||
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://iris-go.com/donate)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://iris-go.com/donate)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
|
||||
<a href="https://iris-go.com"> <img align="right" src="https://iris-go.com/images/logo-w169.png"></a>
|
||||
|
||||
|
@ -57,7 +57,7 @@ Iris possède un **[wiki](https://www.iris-go.com/#ebookDonateForm)** complet et
|
|||
|
||||
<!-- ![](https://media.giphy.com/media/Ur8iqy9FQfmPuyQpgy/giphy.gif) -->
|
||||
|
||||
Pour une documentation encore plus complète vous pouvez visiter notre [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9) (en Anglais). Et vous trouverez du code executable dans le dossier [\_examples](_examples/).
|
||||
Pour une documentation encore plus complète vous pouvez visiter notre [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v) (en Anglais). Et vous trouverez du code executable dans le dossier [\_examples](_examples/).
|
||||
|
||||
### Vous préférez une version PDF?
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Iris Web Framework
|
||||
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://iris-go.com/donate)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://iris-go.com/donate)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
|
||||
Το Iris είναι ένα γρήγορο, απλό αλλά και πλήρως λειτουργικό και πολύ αποδοτικό web framework για τη Go γλώσσα προγραμματισμού. Παρέχει ένα εκφραστικό και εύχρηστο υπόβαθρο για την επόμενη ιστοσελίδα σας.
|
||||
|
||||
|
@ -53,7 +53,7 @@ $ go run example.go
|
|||
|
||||
Το Iris περιέχει εκτενείς και λεπτομερείς **[book](https://www.iris-go.com/#ebookDonateForm)** καθιστώντας το εύκολο στην εκμάθηση.
|
||||
|
||||
Για λεπτομερέστερη τεχνική τεκμηρίωση μπορείτε να κατευθυνθείτε προς τα [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9) μας. Και για εκτελέσιμο κώδικα μπορείτε πάντα να επισκέπτεστε τα [παραδείγματα](_examples/).
|
||||
Για λεπτομερέστερη τεχνική τεκμηρίωση μπορείτε να κατευθυνθείτε προς τα [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v) μας. Και για εκτελέσιμο κώδικα μπορείτε πάντα να επισκέπτεστε τα [παραδείγματα](_examples/).
|
||||
|
||||
### Σας αρέσει να διαβάζετε ενώ ταξιδεύετε;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ Try the official [Iris Command Line Interface](https://github.com/kataras/iris-c
|
|||
|
||||
# <a href="https://iris-go.com"><img src="https://iris-go.com/images/logo-new-lq-45.png"></a> Iris Web Framework <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg" /></a> <a href="README_FR.md"><img width="20px" src="https://iris-go.com/images/flag-france.svg" /></a> <a href="README_ZH_HANT.md"><img width="20px" src="https://iris-go.com/images/flag-taiwan.svg" /></a> <a href="README_ZH_HANS.md"><img width="20px" src="https://iris-go.com/images/flag-china.svg" /></a> <a href="README_ES.md"><img width="20px" src="https://iris-go.com/images/flag-spain.png" /></a> <a href="README_FA.md"><img width="20px" src="https://iris-go.com/images/flag-iran.svg" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg" /></a> <a href="README_KO.md"><img width="20px" src="https://iris-go.com/images/flag-south-korea.svg?v=12" /></a> <a href="README_PT_BR.md"><img width="20px" height="20px" src="https://iris-go.com/images/flag-brazil.svg" /></a> <a href="README_JA.md"><img width="20px" height="20px" src="https://iris-go.com/images/flag-japan.svg" /></a>
|
||||
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) <!--[![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)--> [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) <!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)--> <!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) <!--[![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)--> [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) <!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v)--> <!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
|
||||
Irisは、高速でシンプルでありながら、十分な機能を備えた、非常に効率的なGo用Webフレームワークです。
|
||||
|
||||
|
@ -219,7 +219,7 @@ Irisが提供する機能の一部:
|
|||
$ mkdir myapp
|
||||
$ cd myapp
|
||||
$ go mod init myapp
|
||||
$ go get github.com/kataras/iris/v12@latest # or @v12.2.9
|
||||
$ go get github.com/kataras/iris/v12@latest # or @v
|
||||
```
|
||||
|
||||
<details><summary>既存のプロジェクトにインストールする場合</summary>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Iris Web Framework
|
||||
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://iris-go.com/donate)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://iris-go.com/donate)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
|
||||
Iris는 단순하고 빠르며 좋은 성능과 모든 기능을 갖춘 Go언어용 웹 프레임워크입니다. 당신의 웹사이트나 API를 위해서 아름답고 사용하기 쉬운 기반을 제공합니다.
|
||||
|
||||
|
@ -49,7 +49,7 @@ $ go run example.go
|
|||
|
||||
Iris는 광범위하고 꼼꼼한 **[wiki](https://www.iris-go.com/#ebookDonateForm)** 를 가지고 있기 때문에 쉽게 프레임워크를 시작할 수 있습니다.
|
||||
|
||||
더 자세한 기술문서를 보시려면 [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)를 방문하세요. 그리고 실행가능한 예제코드는 [\_examples](_examples/) 하위 디렉토리에 있습니다.
|
||||
더 자세한 기술문서를 보시려면 [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v)를 방문하세요. 그리고 실행가능한 예제코드는 [\_examples](_examples/) 하위 디렉토리에 있습니다.
|
||||
|
||||
### 여행하면서 독서를 즐기세요?
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Iris Web Framework <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg" /></a> <a href="README_FR.md"><img width="20px" src="https://iris-go.com/images/flag-france.svg" /></a> <a href="README_ZH.md"><img width="20px" src="https://iris-go.com/images/flag-china.svg" /></a> <a href="README_ES.md"><img width="20px" src="https://iris-go.com/images/flag-spain.png" /></a> <a href="README_FA.md"><img width="20px" src="https://iris-go.com/images/flag-iran.svg" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg" /></a> <a href="README_KO.md"><img width="20px" src="https://iris-go.com/images/flag-south-korea.svg?v=12" /></a> <a href="README_PT_BR.md"><img width="20px" align="center" src="https://www.iris-go.com/images/flag-brazil.svg" /></a> <a href="README_JA.md"><img width="20px" height="20px" src="https://iris-go.com/images/flag-japan.svg" /></a>
|
||||
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-270-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) <!--[![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)--> [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) <!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)--> <!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-270-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) <!--[![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)--> [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) <!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v)--> <!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
|
||||
<!-- <a href="https://iris-go.com"> <img align="right" src="https://iris-go.com/images/logo-w169.png"></a> -->
|
||||
|
||||
|
@ -226,7 +226,7 @@ O único requisito é a [Linguagem de programação Go](https://go.dev/dl/).
|
|||
$ mkdir myapp
|
||||
$ cd myapp
|
||||
$ go mod init myapp
|
||||
$ go get github.com/kataras/iris/v12@latest # or @v12.2.9
|
||||
$ go get github.com/kataras/iris/v12@latest # or @v
|
||||
```
|
||||
|
||||
<details><summary>Instalar num projeto existente</summary>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Iris Web Framework
|
||||
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://iris-go.com/donate)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)<!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v)--> [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community)<!--[![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://iris-go.com/donate)--><!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
Iris — это быстрый, простой, но полнофункциональный и эффективный веб-фреймворк для Go. Он обеспечивает красивую, выразительную и простую в использовании основу для вашего следующего веб-сайта или API.
|
||||
|
||||
Узнайте, что [говорят другие люди об Iris](https://iris-go.com/testimonials/) и поставьте **[звёздочку](https://github.com/kataras/iris/stargazers)** этому проекту с открытым исходным кодом, чтобы поддержать его потенциал.
|
||||
|
@ -50,7 +50,7 @@ $ go run example.go
|
|||
|
||||
<!-- ![](https://media.giphy.com/media/Ur8iqy9FQfmPuyQpgy/giphy.gif) -->
|
||||
|
||||
Для получения более подробной технической документации вы можете обратиться к нашему [godoc](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9). А для живых примеров кода — вы всегда можете посетить [\_examples](_examples/) в поддиректории этого репозитория.
|
||||
Для получения более подробной технической документации вы можете обратиться к нашему [godoc](https://pkg.go.dev/github.com/kataras/iris/v12@v). А для живых примеров кода — вы всегда можете посетить [\_examples](_examples/) в поддиректории этого репозитория.
|
||||
|
||||
### Вы любите читать во время путешествий?
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ Try the official [Iris Command Line Interface](https://github.com/kataras/iris-c
|
|||
|
||||
# <a href="https://iris-go.com"><img src="https://iris-go.com/images/logo-new-lq-45.png"></a> Iris Web Framework <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg" /></a> <a href="README_FR.md"><img width="20px" src="https://iris-go.com/images/flag-france.svg" /></a> <a href="README_ZH_HANT.md"><img width="20px" src="https://iris-go.com/images/flag-taiwan.svg" /></a> <a href="README_ZH_HANS.md"><img width="20px" src="https://iris-go.com/images/flag-china.svg" /></a> <a href="README_ES.md"><img width="20px" src="https://iris-go.com/images/flag-spain.png" /></a> <a href="README_FA.md"><img width="20px" src="https://iris-go.com/images/flag-iran.svg" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg" /></a> <a href="README_KO.md"><img width="20px" src="https://iris-go.com/images/flag-south-korea.svg?v=12" /></a> <a href="README_PT_BR.md"><img width="20px" height="20px" src="https://iris-go.com/images/flag-brazil.svg" /></a>
|
||||
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) <!--[![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)--> [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) <!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)--> <!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) <!--[![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)--> [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) <!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v)--> <!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
|
||||
Iris là một khung web nhanh, đơn giản nhưng đầy đủ tính năng và rất hiệu quả dành cho Go.
|
||||
|
||||
|
@ -220,7 +220,7 @@ Yêu cầu duy nhất là [Ngôn ngữ lập trình Go](https://go.dev/dl/).
|
|||
$ mkdir myapp
|
||||
$ cd myapp
|
||||
$ go mod init myapp
|
||||
$ go get github.com/kataras/iris/v12@latest # or @v12.2.9
|
||||
$ go get github.com/kataras/iris/v12@latest # or @v
|
||||
```
|
||||
|
||||
<details><summary>Cài đặt trên dự án hiện có</summary>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
# Iris Web Framework <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg" /></a> <a href="README_FR.md"><img width="20px" src="https://iris-go.com/images/flag-france.svg" /></a> <a href="README_ZH.md"><img width="20px" src="https://iris-go.com/images/flag-china.svg" /></a> <a href="README_ES.md"><img width="20px" src="https://iris-go.com/images/flag-spain.png" /></a> <a href="README_FA.md"><img width="20px" src="https://iris-go.com/images/flag-iran.svg" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg" /></a> <a href="README_KO.md"><img width="20px" src="https://iris-go.com/images/flag-south-korea.svg?v=12" /></a> <a href="README_JA.md"><img width="20px" height="20px" src="https://iris-go.com/images/flag-japan.svg" /></a>
|
||||
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-253-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) <!--[![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)--> [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) <!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)--> <!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-253-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) <!--[![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)--> [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) <!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v)--> <!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
|
||||
<!-- <a href="https://iris-go.com"> <img align="right" src="https://iris-go.com/images/logo-w169.png"></a> -->
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
# Iris Web 框架 <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg" /></a> <a href="README_FR.md"><img width="20px" src="https://iris-go.com/images/flag-france.svg" /></a> <a href="README_ZH.md"><img width="20px" src="https://iris-go.com/images/flag-china.svg" /></a> <a href="README_ES.md"><img width="20px" src="https://iris-go.com/images/flag-spain.png" /></a> <a href="README_FA.md"><img width="20px" src="https://iris-go.com/images/flag-iran.svg" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg" /></a> <a href="README_KO.md"><img width="20px" src="https://iris-go.com/images/flag-south-korea.svg?v=12" /></a> <a href="README_PT_BR.md"><img width="20px" height="20px" src="https://iris-go.com/images/flag-brazil.svg" /></a> <a href="README_JA.md"><img width="20px" height="20px" src="https://iris-go.com/images/flag-japan.svg" /></a>
|
||||
|
||||
[![組建狀態](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![查看範例](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![聊天室](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) <!--[![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)--> [![捐助](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) <!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)--> <!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
[![組建狀態](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![查看範例](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![聊天室](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) <!--[![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield)--> [![捐助](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) <!--[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris)--><!--[![godocs](https://img.shields.io/badge/go-%20docs-488AC7.svg?style=for-the-badge)](https://pkg.go.dev/github.com/kataras/iris/v12@v)--> <!-- [![release](https://img.shields.io/badge/release%20-v12.0-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) -->
|
||||
|
||||
<!-- <a href="https://iris-go.com"> <img align="right" src="https://iris-go.com/images/logo-w169.png"></a> -->
|
||||
|
||||
|
@ -237,7 +237,7 @@ Iris 提供了至少這些功能:
|
|||
$ mkdir myapp
|
||||
$ cd myapp
|
||||
$ go mod init myapp
|
||||
$ go get github.com/kataras/iris/v12@latest # 或 @v12.2.9
|
||||
$ go get github.com/kataras/iris/v12@latest # 或 @v
|
||||
```
|
||||
|
||||
<details><summary>在現有專案安裝</summary>
|
||||
|
|
|
@ -50,11 +50,11 @@ func (r resource) loadFromBase(dir string) string {
|
|||
}
|
||||
|
||||
result := string(b)
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
result = strings.ReplaceAll(result, "\n", "\r\n")
|
||||
result = strings.ReplaceAll(result, "\r\r", "")
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -50,6 +50,11 @@ func (r resource) loadFromBase(dir string) string {
|
|||
}
|
||||
|
||||
result := string(b)
|
||||
if runtime.GOOS != "windows" {
|
||||
result = strings.ReplaceAll(result, "\n", "\r\n")
|
||||
result = strings.ReplaceAll(result, "\r\r", "")
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
@ -30,7 +33,8 @@ func TestJSONLogger(t *testing.T) {
|
|||
|
||||
app.Get("/ping", ping)
|
||||
|
||||
const expectedLogStr = `{"level":"debug","message":"Request path: /ping","fields":{"request_id":null},"stacktrace":[{"function":"json-logger/ping","source":"/home/runner/work/iris/iris/_examples/logging/json-logger/main.go:78"}]}` // gh actions-specific.
|
||||
expectedSourceDir := getSourceDirPath()
|
||||
expectedLogStr := fmt.Sprintf(`{"level":"debug","message":"Request path: /ping","fields":{"request_id":null},"stacktrace":[{"function":"json-logger/ping","source":"%s/main.go:78"}]}`, expectedSourceDir) // gh actions-specific.
|
||||
e := httptest.New(t, app, httptest.LogLevel("debug"))
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(iters)
|
||||
|
@ -57,3 +61,12 @@ func TestJSONLogger(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getSourceDirPath() string {
|
||||
_, file, _, ok := runtime.Caller(1) // get the caller's file.
|
||||
if !ok {
|
||||
return "unknown source"
|
||||
}
|
||||
|
||||
return path.Dir(file) // get the directory of the file (delimiter: /).
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
|
@ -977,25 +976,19 @@ type Configuration struct {
|
|||
//
|
||||
// Defaults to empty map.
|
||||
Other map[string]interface{} `ini:"other" json:"other,omitempty" yaml:"Other" toml:"Other"`
|
||||
|
||||
mu sync.RWMutex // mutex for some of the configuration fields that may change during parallel jobs (see Application.NonBlocking & Wait).
|
||||
}
|
||||
|
||||
var _ context.ConfigurationReadOnly = (*Configuration)(nil)
|
||||
|
||||
// GetVHost returns the non-exported VHost config field.
|
||||
// GetVHost returns the VHost config field.
|
||||
func (c *Configuration) GetVHost() string {
|
||||
c.mu.RLock()
|
||||
vhost := c.VHost
|
||||
c.mu.RUnlock()
|
||||
return vhost
|
||||
}
|
||||
|
||||
// SetVHost sets the non-exported VHost config field.
|
||||
// SetVHost sets the VHost config field.
|
||||
func (c *Configuration) SetVHost(s string) {
|
||||
c.mu.Lock()
|
||||
c.VHost = s
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// GetLogLevel returns the LogLevel field.
|
||||
|
|
|
@ -18,7 +18,7 @@ func TestConfigurationStatic(t *testing.T) {
|
|||
afterNew := *app.config
|
||||
|
||||
if !reflect.DeepEqual(def, afterNew) {
|
||||
t.Fatalf("Default configuration is not the same after NewFromConfig expected:\n %#v \ngot:\n %#v", def, afterNew)
|
||||
t.Fatalf("Default configuration is not the same after New expected:\n %#v \ngot:\n %#v", def, afterNew)
|
||||
}
|
||||
|
||||
afterNew.Charset = "changed"
|
||||
|
@ -37,7 +37,7 @@ func TestConfigurationStatic(t *testing.T) {
|
|||
|
||||
app = New() // empty , means defaults so
|
||||
if !reflect.DeepEqual(def, *app.config) {
|
||||
t.Fatalf("Default configuration is not the same after NewFromConfig expected:\n %#v \ngot:\n %#v", def, *app.config)
|
||||
t.Fatalf("Default configuration is not the same after New expected:\n %#v \ngot:\n %#v", def, *app.config)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
var (
|
||||
// PackageName is the Iris Go module package name.
|
||||
PackageName = strings.TrimSuffix(reflect.TypeOf(Handlers{}).PkgPath(), "/context")
|
||||
PackageName = strings.TrimSuffix(reflect.TypeOf(Context{}).PkgPath(), "/context")
|
||||
|
||||
// WorkingDir is the (initial) current directory.
|
||||
WorkingDir, _ = os.Getwd()
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
package host_test
|
||||
|
||||
import (
|
||||
stdContext "context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/url"
|
||||
|
@ -30,6 +31,7 @@ func TestProxy(t *testing.T) {
|
|||
MinVersion: tls.VersionTLS13,
|
||||
}
|
||||
proxy := host.NewProxy("", u, config)
|
||||
proxy.Configure(host.NonBlocking())
|
||||
|
||||
addr := &net.TCPAddr{
|
||||
IP: net.IPv4(127, 0, 0, 1),
|
||||
|
@ -41,10 +43,15 @@ func TestProxy(t *testing.T) {
|
|||
t.Fatalf("%v while creating listener", err)
|
||||
}
|
||||
|
||||
go proxy.Serve(listener) // should be localhost/127.0.0.1:80 but travis throws permission denied.
|
||||
// non-blocking (see above).
|
||||
proxy.Serve(listener)
|
||||
|
||||
ctx, cancelFunc := stdContext.WithTimeout(stdContext.Background(), 15*time.Second)
|
||||
defer cancelFunc()
|
||||
|
||||
// Wait for up to 15 seconds or until the proxy is ready to serve or a serve failure.
|
||||
proxy.Wait(ctx)
|
||||
|
||||
t.Log(listener.Addr().String())
|
||||
<-time.After(time.Second)
|
||||
t.Log(listener.Addr().String())
|
||||
|
||||
app := iris.New()
|
||||
|
@ -60,7 +67,7 @@ func TestProxy(t *testing.T) {
|
|||
ctx.WriteString(unexpectedRoute)
|
||||
})
|
||||
|
||||
l, err := net.Listen("tcp", "localhost:4444") // should be localhost/127.0.0.1:443 but travis throws permission denied.
|
||||
l, err := net.Listen("tcp", "localhost:4444")
|
||||
if err != nil {
|
||||
t.Fatalf("%v while creating tcp4 listener for new tls local test listener", err)
|
||||
}
|
||||
|
|
|
@ -25,6 +25,13 @@ import (
|
|||
// Look the `Configure` func for more.
|
||||
type Configurator func(su *Supervisor)
|
||||
|
||||
// NonBlocking sets the server to non-blocking mode. Use its `Wait` method to wait for server to be up and running.
|
||||
func NonBlocking() Configurator {
|
||||
return func(su *Supervisor) {
|
||||
su.nonBlocking = true
|
||||
}
|
||||
}
|
||||
|
||||
// Supervisor is the wrapper and the manager for a compatible server
|
||||
// and it's relative actions, called Tasks.
|
||||
//
|
||||
|
@ -34,14 +41,12 @@ type Supervisor struct {
|
|||
// FriendlyAddr can be set to customize the "Now Listening on: {FriendlyAddr}".
|
||||
FriendlyAddr string // e.g mydomain.com instead of :443 when AutoTLS is used, see `WriteStartupLogOnServe` task.
|
||||
disableHTTP1ToHTTP2Redirection bool
|
||||
closedManually uint32 // future use, accessed atomically (non-zero means we've called the Shutdown)
|
||||
closedByInterruptHandler uint32 // non-zero means that the end-developer interrupted it by-purpose.
|
||||
manuallyTLS bool // we need that in order to determinate what to output on the console before the server begin.
|
||||
autoTLS bool
|
||||
shouldWait int32 // non-zero means that the host should wait for unblocking
|
||||
unblockChan chan struct{}
|
||||
|
||||
mu sync.Mutex
|
||||
closedByInterruptHandler uint32 // non-zero means that the end-developer interrupted it by-purpose.
|
||||
manuallyTLS bool // we need that in order to determinate what to output on the console before the server begin.
|
||||
autoTLS bool
|
||||
|
||||
mu sync.RWMutex
|
||||
|
||||
onServe []func(TaskHost)
|
||||
// IgnoreErrors should contains the errors that should be ignored
|
||||
|
@ -73,6 +78,10 @@ type Supervisor struct {
|
|||
// If more than zero then tcp keep alive listener is attached instead of the simple TCP listener.
|
||||
// See `iris.Configuration.KeepAlive`
|
||||
KeepAlive time.Duration
|
||||
|
||||
address string
|
||||
nonBlocking bool
|
||||
waiter *Waiter
|
||||
}
|
||||
|
||||
// New returns a new host supervisor
|
||||
|
@ -83,10 +92,12 @@ type Supervisor struct {
|
|||
// It has its own flow, which means that you can prevent
|
||||
// to return and exit and restore the flow too.
|
||||
func New(srv *http.Server) *Supervisor {
|
||||
return &Supervisor{
|
||||
Server: srv,
|
||||
unblockChan: make(chan struct{}, 1),
|
||||
su := &Supervisor{
|
||||
Server: srv,
|
||||
}
|
||||
|
||||
su.waiter = NewWaiter(7, su.getAddress)
|
||||
return su
|
||||
}
|
||||
|
||||
// Configure accepts one or more `Configurator`.
|
||||
|
@ -113,36 +124,6 @@ func (su *Supervisor) NoRedirect() {
|
|||
su.disableHTTP1ToHTTP2Redirection = true
|
||||
}
|
||||
|
||||
// DeferFlow defers the flow of the exeuction,
|
||||
// i.e: when server should return error and exit
|
||||
// from app, a DeferFlow call inside a Task
|
||||
// can wait for a `RestoreFlow` to exit or not exit if
|
||||
// host's server is "fixed".
|
||||
//
|
||||
// See `RestoreFlow` too.
|
||||
func (su *Supervisor) DeferFlow() {
|
||||
atomic.StoreInt32(&su.shouldWait, 1)
|
||||
}
|
||||
|
||||
// RestoreFlow restores the flow of the execution,
|
||||
// if called without a `DeferFlow` call before
|
||||
// then it does nothing.
|
||||
// See tests to understand how that can be useful on specific cases.
|
||||
//
|
||||
// See `DeferFlow` too.
|
||||
func (su *Supervisor) RestoreFlow() {
|
||||
if su.isWaiting() {
|
||||
atomic.StoreInt32(&su.shouldWait, 0)
|
||||
su.mu.Lock()
|
||||
su.unblockChan <- struct{}{}
|
||||
su.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (su *Supervisor) isWaiting() bool {
|
||||
return atomic.LoadInt32(&su.shouldWait) != 0
|
||||
}
|
||||
|
||||
func (su *Supervisor) newListener() (net.Listener, error) {
|
||||
var (
|
||||
l net.Listener
|
||||
|
@ -198,14 +179,28 @@ func (su *Supervisor) validateErr(err error) error {
|
|||
}
|
||||
|
||||
func (su *Supervisor) notifyErr(err error) {
|
||||
err = su.validateErr(err)
|
||||
if err != nil {
|
||||
su.mu.Lock()
|
||||
for _, f := range su.onErr {
|
||||
go f(err)
|
||||
}
|
||||
su.mu.Unlock()
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
su.mu.Lock()
|
||||
for _, f := range su.onErr {
|
||||
go f(err)
|
||||
}
|
||||
su.mu.Unlock()
|
||||
}
|
||||
|
||||
func (su *Supervisor) getAddress() string {
|
||||
su.mu.RLock()
|
||||
addr := su.address
|
||||
su.mu.RUnlock()
|
||||
return addr
|
||||
}
|
||||
|
||||
func (su *Supervisor) setAddress(addr string) {
|
||||
su.mu.Lock()
|
||||
su.address = addr
|
||||
su.mu.Unlock()
|
||||
}
|
||||
|
||||
// RegisterOnServe registers a function to call on
|
||||
|
@ -224,27 +219,36 @@ func (su *Supervisor) notifyServe(host TaskHost) {
|
|||
su.mu.Unlock()
|
||||
}
|
||||
|
||||
// Remove all channels, do it with events
|
||||
// or with channels but with a different channel on each task proc
|
||||
// I don't know channels are not so safe, when go func and race risk..
|
||||
// so better with callbacks....
|
||||
func (su *Supervisor) supervise(blockFunc func() error) error {
|
||||
host := createTaskHost(su)
|
||||
|
||||
su.notifyServe(host)
|
||||
atomic.StoreUint32(&su.closedByInterruptHandler, 0)
|
||||
atomic.StoreUint32(&su.closedManually, 0)
|
||||
|
||||
err := blockFunc()
|
||||
su.notifyErr(err)
|
||||
if su.nonBlocking {
|
||||
go func() {
|
||||
err := blockFunc()
|
||||
if err != nil {
|
||||
su.waiter.Fail(err)
|
||||
}
|
||||
|
||||
if su.isWaiting() {
|
||||
for range su.unblockChan {
|
||||
break
|
||||
}
|
||||
err = su.validateErr(err)
|
||||
su.notifyErr(err)
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return su.validateErr(err)
|
||||
err := blockFunc()
|
||||
err = su.validateErr(err)
|
||||
su.notifyErr(err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait blocks until server is up and running or a serve failure.
|
||||
func (su *Supervisor) Wait(ctx context.Context) error {
|
||||
return su.waiter.Wait(ctx)
|
||||
}
|
||||
|
||||
// Serve accepts incoming connections on the Listener l, creating a
|
||||
|
@ -259,7 +263,11 @@ func (su *Supervisor) supervise(blockFunc func() error) error {
|
|||
// Serve always returns a non-nil error. After Shutdown or Close, the
|
||||
// returned error is http.ErrServerClosed.
|
||||
func (su *Supervisor) Serve(l net.Listener) error {
|
||||
return su.supervise(func() error { return su.Server.Serve(l) })
|
||||
su.setAddress(l.Addr().String())
|
||||
|
||||
return su.supervise(func() error {
|
||||
return su.Server.Serve(l)
|
||||
})
|
||||
}
|
||||
|
||||
// ListenAndServe listens on the TCP network address addr
|
||||
|
@ -502,7 +510,6 @@ func (su *Supervisor) RegisterOnShutdown(cb func()) {
|
|||
// separately notify such long-lived connections of shutdown and wait
|
||||
// for them to close, if desired.
|
||||
func (su *Supervisor) Shutdown(ctx context.Context) error {
|
||||
atomic.StoreUint32(&su.closedManually, 1) // future-use
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
|
|
|
@ -4,10 +4,7 @@ package host
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -38,75 +35,3 @@ func ExampleSupervisor_RegisterOnError() {
|
|||
// http: Server closed
|
||||
// http: Server closed
|
||||
}
|
||||
|
||||
type myTestTask struct {
|
||||
restartEvery time.Duration
|
||||
maxRestarts int
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (m myTestTask) OnServe(host TaskHost) {
|
||||
host.Supervisor.DeferFlow() // don't exit on underline server's Shutdown.
|
||||
|
||||
ticker := time.NewTicker(m.restartEvery)
|
||||
defer ticker.Stop()
|
||||
rans := 0
|
||||
for range ticker.C {
|
||||
exitAfterXRestarts := m.maxRestarts
|
||||
if rans == exitAfterXRestarts {
|
||||
m.logger.Println("exit")
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
|
||||
_ = host.Supervisor.Shutdown(ctx) // total shutdown
|
||||
host.Supervisor.RestoreFlow() // free to exit (if shutdown)
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
|
||||
rans++
|
||||
|
||||
m.logger.Println(fmt.Sprintf("closed %d times", rans))
|
||||
host.Shutdown(context.TODO())
|
||||
|
||||
startDelay := 2 * time.Second
|
||||
time.AfterFunc(startDelay, func() {
|
||||
m.logger.Println("restart")
|
||||
if err := host.Serve(); err != nil { // restart
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleSupervisor_RegisterOnServe() {
|
||||
h := New(&http.Server{
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
}),
|
||||
})
|
||||
|
||||
logger := log.New(os.Stdout, "Supervisor: ", 0)
|
||||
|
||||
mytask := myTestTask{
|
||||
restartEvery: 3 * time.Second,
|
||||
maxRestarts: 2,
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
h.RegisterOnServe(mytask.OnServe)
|
||||
|
||||
ln, err := net.Listen("tcp4", ":9394")
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
logger.Println("server started...")
|
||||
h.Serve(ln)
|
||||
|
||||
// Output:
|
||||
// Supervisor: server started...
|
||||
// Supervisor: closed 1 times
|
||||
// Supervisor: restart
|
||||
// Supervisor: closed 2 times
|
||||
// Supervisor: restart
|
||||
// Supervisor: exit
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ func newTester(t *testing.T, baseURL string, handler http.Handler) *httpexpect.E
|
|||
BaseURL: baseURL,
|
||||
Client: &http.Client{
|
||||
Transport: transporter,
|
||||
Jar: httpexpect.NewJar(),
|
||||
Jar: httpexpect.NewCookieJar(),
|
||||
},
|
||||
Reporter: httpexpect.NewAssertReporter(t),
|
||||
}
|
||||
|
|
|
@ -94,10 +94,10 @@ func WriteStartupLogOnServe(w io.Writer) func(TaskHost) {
|
|||
// This function should be registered on Interrupt.
|
||||
func ShutdownOnInterrupt(su *Supervisor, shutdownTimeout time.Duration) func() {
|
||||
return func() {
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), shutdownTimeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
|
||||
defer cancel()
|
||||
|
||||
su.shutdownOnInterrupt(ctx)
|
||||
su.RestoreFlow()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
134
core/host/waiter.go
Normal file
134
core/host/waiter.go
Normal file
|
@ -0,0 +1,134 @@
|
|||
package host
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Waiter is a helper for waiting for a server to be up and running.
|
||||
type Waiter struct {
|
||||
defaultMaxRetries int
|
||||
addressFunc func() string
|
||||
|
||||
failure error // or runError for app.Run.
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewWaiter returns a new Waiter.
|
||||
func NewWaiter(defaultMaxRetries int, addressFunc func() string) *Waiter {
|
||||
if defaultMaxRetries <= 0 {
|
||||
defaultMaxRetries = 7 // 256 seconds max.
|
||||
}
|
||||
|
||||
return &Waiter{
|
||||
defaultMaxRetries: defaultMaxRetries,
|
||||
addressFunc: addressFunc,
|
||||
}
|
||||
}
|
||||
|
||||
// Wait blocks the main goroutine until the application is up and running.
|
||||
func (w *Waiter) Wait(ctx context.Context) error {
|
||||
// First check if there is an error already from Done.
|
||||
if err := w.getFailure(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the base for exponential backoff.
|
||||
base := 2.0
|
||||
|
||||
// Get the maximum number of retries by context or force to default max retries (e.g. 7).
|
||||
var maxRetries int
|
||||
// Get the deadline of the context.
|
||||
if deadline, ok := ctx.Deadline(); ok {
|
||||
now := time.Now()
|
||||
timeout := deadline.Sub(now)
|
||||
|
||||
maxRetries = getMaxRetries(timeout, base)
|
||||
} else {
|
||||
maxRetries = w.defaultMaxRetries
|
||||
}
|
||||
|
||||
// Set the initial retry interval.
|
||||
retryInterval := time.Second
|
||||
|
||||
return w.tryConnect(ctx, w.addressFunc, maxRetries, retryInterval, base)
|
||||
}
|
||||
|
||||
// getMaxRetries calculates the maximum number of retries from the retry interval and the base.
|
||||
func getMaxRetries(retryInterval time.Duration, base float64) int {
|
||||
// Convert the retry interval to seconds.
|
||||
seconds := retryInterval.Seconds()
|
||||
// Apply the inverse formula.
|
||||
retries := math.Log(seconds)/math.Log(base) - 1
|
||||
return int(math.Round(retries))
|
||||
}
|
||||
|
||||
// tryConnect tries to connect to the server with the given context and retry parameters.
|
||||
func (w *Waiter) tryConnect(ctx context.Context, addressFunc func() string, maxRetries int, retryInterval time.Duration, base float64) error {
|
||||
// Try to connect to the server in a loop.
|
||||
for i := 0; i < maxRetries; i++ {
|
||||
// Check the context before each attempt.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// Context is canceled, return the context error.
|
||||
return ctx.Err()
|
||||
default:
|
||||
address := addressFunc() // Get this server's listening address.
|
||||
if address == "" {
|
||||
i-- // Note that this may be modified at another go routine of the serve method. So it may be empty at first chance. So retry fetching the VHost every 1 second.
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
// Context is not canceled, proceed with the attempt.
|
||||
conn, err := net.Dial("tcp", address)
|
||||
if err == nil {
|
||||
// Connection successful, close the connection and return nil.
|
||||
conn.Close()
|
||||
return nil // exit.
|
||||
} // ignore error.
|
||||
|
||||
// Connection failed, wait for the retry interval and try again.
|
||||
time.Sleep(retryInterval)
|
||||
// After each failed attempt, check the server Run's error again.
|
||||
if err := w.getFailure(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Increase the retry interval by the base raised to the power of the number of attempts.
|
||||
/*
|
||||
0 2 seconds
|
||||
1 4 seconds
|
||||
2 8 seconds
|
||||
3 ~16 seconds
|
||||
4 ~32 seconds
|
||||
5 ~64 seconds
|
||||
6 ~128 seconds
|
||||
7 ~256 seconds
|
||||
8 ~512 seconds
|
||||
...
|
||||
*/
|
||||
retryInterval = time.Duration(math.Pow(base, float64(i+1))) * time.Second
|
||||
}
|
||||
}
|
||||
// All attempts failed, return an error.
|
||||
return fmt.Errorf("failed to connect to the server after %d retries", maxRetries)
|
||||
}
|
||||
|
||||
// Fail is called by the server's Run method when the server failed to start.
|
||||
func (w *Waiter) Fail(err error) {
|
||||
w.mu.Lock()
|
||||
w.failure = err
|
||||
w.mu.Unlock()
|
||||
}
|
||||
|
||||
func (w *Waiter) getFailure() error {
|
||||
w.mu.RLock()
|
||||
err := w.failure
|
||||
w.mu.RUnlock()
|
||||
return err
|
||||
}
|
2
doc.go
2
doc.go
|
@ -10,7 +10,7 @@ Source code and other details for the project are available at GitHub:
|
|||
|
||||
# Current Version
|
||||
|
||||
12.2.9
|
||||
12.2.10
|
||||
|
||||
# Installation
|
||||
|
||||
|
|
4
go.mod
4
go.mod
|
@ -35,12 +35,12 @@ require (
|
|||
github.com/redis/go-redis/v9 v9.4.0
|
||||
github.com/schollz/closestmatch v2.1.0+incompatible
|
||||
github.com/shirou/gopsutil/v3 v3.23.12
|
||||
github.com/tdewolff/minify/v2 v2.20.13
|
||||
github.com/tdewolff/minify/v2 v2.20.14
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||
github.com/yosssi/ace v0.0.5
|
||||
go.etcd.io/bbolt v1.3.8
|
||||
golang.org/x/crypto v0.18.0
|
||||
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e
|
||||
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3
|
||||
golang.org/x/net v0.20.0
|
||||
golang.org/x/sys v0.16.0
|
||||
golang.org/x/text v0.14.0
|
||||
|
|
12
go.sum
generated
12
go.sum
generated
|
@ -116,6 +116,8 @@ github.com/kataras/golog v0.1.11 h1:dGkcCVsIpqiAMWTlebn/ZULHxFvfG4K43LF1cNWSh20=
|
|||
github.com/kataras/golog v0.1.11/go.mod h1:mAkt1vbPowFUuUGvexyQ5NFW6djEgGyxQBIARJ0AH4A=
|
||||
github.com/kataras/jwt v0.1.12 h1:FHPgTTj5UqjlBye4PA4/oxknCY+kQ9K34XAi8d37glA=
|
||||
github.com/kataras/jwt v0.1.12/go.mod h1:xkimAtDhU/aGlQqjwvgtg+VyuPwMiyZHaY8LJRh0mYo=
|
||||
github.com/kataras/neffos v0.0.23 h1:Jlbn7aK+pl/U/4vfDs1508+tlIdcjE5BdKFtzePsrBI=
|
||||
github.com/kataras/neffos v0.0.23/go.mod h1:3pzx6A5QUvwavU1RF0uIl5/TNbwyYswmfnfG5z8VBm8=
|
||||
github.com/kataras/neffos v0.0.24-0.20240110215151-1db32f4ef9ed h1:iCsmmi2n7vUyWJ0NS1Wsu8N5oIS+C05fyIo3YTBQHMQ=
|
||||
github.com/kataras/neffos v0.0.24-0.20240110215151-1db32f4ef9ed/go.mod h1:VLyfPmZh2Tbxjc2XKe1J0xwwKqiUD2zTA36Xcp+UIDs=
|
||||
github.com/kataras/pio v0.0.13 h1:x0rXVX0fviDTXOOLOmr4MUxOabu1InVSTu5itF8CXCM=
|
||||
|
@ -158,6 +160,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
|||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E=
|
||||
github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8=
|
||||
github.com/nats-io/nkeys v0.4.5 h1:Zdz2BUlFm4fJlierwvGK+yl20IAKUm7eV6AAZXEhkPk=
|
||||
github.com/nats-io/nkeys v0.4.5/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
|
||||
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
|
||||
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
|
@ -219,8 +223,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
|||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
|
||||
github.com/tdewolff/minify/v2 v2.20.13 h1:TDWS1orkBJjq6Sz9NjEvHEeUnAvlfU7jgStGQBwBPGM=
|
||||
github.com/tdewolff/minify/v2 v2.20.13/go.mod h1:qnIJbnG2dSzk7LIa/UUwgN2OjS8ir6RRlqc0T/1q2xY=
|
||||
github.com/tdewolff/minify/v2 v2.20.14 h1:sktSuVixRwk0ryQjqvKBu/uYS+MWmkwEFMEWtFZ+TdE=
|
||||
github.com/tdewolff/minify/v2 v2.20.14/go.mod h1:qnIJbnG2dSzk7LIa/UUwgN2OjS8ir6RRlqc0T/1q2xY=
|
||||
github.com/tdewolff/parse/v2 v2.7.8 h1:1cnVqa8L63xFkc2vfRsZTM6Qy35nJpTvQ2Uvdv3vbvs=
|
||||
github.com/tdewolff/parse/v2 v2.7.8/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
|
||||
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||
|
@ -266,8 +270,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e h1:723BNChdd0c2Wk6WOE320qGBiPtYx0F0Bbm1kriShfE=
|
||||
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o=
|
||||
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
|
|
|
@ -134,7 +134,7 @@ func New(t IrisTesty, app *iris.Application, setters ...OptionSetter) *httpexpec
|
|||
BaseURL: conf.URL,
|
||||
Client: &http.Client{
|
||||
Transport: httpexpect.NewBinder(app),
|
||||
Jar: httpexpect.NewJar(),
|
||||
Jar: httpexpect.NewCookieJar(),
|
||||
},
|
||||
Reporter: reporter,
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ func NewInsecure(t IrisTesty, setters ...OptionSetter) *httpexpect.Expect {
|
|||
BaseURL: conf.URL,
|
||||
Client: &http.Client{
|
||||
Transport: transport,
|
||||
Jar: httpexpect.NewJar(),
|
||||
Jar: httpexpect.NewCookieJar(),
|
||||
},
|
||||
Reporter: httpexpect.NewAssertReporter(t),
|
||||
}
|
||||
|
|
51
iris.go
51
iris.go
|
@ -39,7 +39,7 @@ import (
|
|||
)
|
||||
|
||||
// Version is the current version of the Iris Web Framework.
|
||||
const Version = "12.2.9"
|
||||
const Version = "12.2.10"
|
||||
|
||||
// Byte unit helpers.
|
||||
const (
|
||||
|
@ -95,7 +95,7 @@ type Application struct {
|
|||
// Users can wrap it to accept more events.
|
||||
OnBuild func() error
|
||||
|
||||
mu sync.Mutex
|
||||
mu sync.RWMutex
|
||||
// name is the application name and the log prefix for
|
||||
// that Application instance's Logger. See `SetName` and `String`.
|
||||
// Defaults to IRIS_APP_NAME envrinoment variable otherwise empty.
|
||||
|
@ -517,10 +517,38 @@ func (l *customHostServerLogger) Write(p []byte) (int, error) {
|
|||
return l.parent.Write(p)
|
||||
}
|
||||
|
||||
// this may change during parallel jobs (see Application.NonBlocking & Wait).
|
||||
func (app *Application) getVHost() string {
|
||||
app.mu.RLock()
|
||||
vhost := app.config.VHost
|
||||
app.mu.RUnlock()
|
||||
return vhost
|
||||
}
|
||||
|
||||
func (app *Application) setVHost(vhost string) {
|
||||
app.mu.Lock()
|
||||
app.config.VHost = vhost
|
||||
app.mu.Unlock()
|
||||
}
|
||||
|
||||
// NewHost accepts a standard *http.Server object,
|
||||
// completes the necessary missing parts of that "srv"
|
||||
// and returns a new, ready-to-use, host (supervisor).
|
||||
func (app *Application) NewHost(srv *http.Server) *host.Supervisor {
|
||||
if app.getVHost() == "" { // vhost now is useful for router subdomain on wildcard subdomains,
|
||||
// in order to correct decide what to do on:
|
||||
// mydomain.com -> invalid
|
||||
// localhost -> invalid
|
||||
// sub.mydomain.com -> valid
|
||||
// sub.localhost -> valid
|
||||
// we need the host (without port if 80 or 443) in order to validate these, so:
|
||||
app.setVHost(netutil.ResolveVHost(srv.Addr))
|
||||
} else {
|
||||
context.GetDomain = func(_ string) string { // #1886
|
||||
return app.config.VHost // GetVHost: here we don't need mutex protection as it's request-time and all modifications are already made.
|
||||
}
|
||||
} // before lock.
|
||||
|
||||
app.mu.Lock()
|
||||
defer app.mu.Unlock()
|
||||
|
||||
|
@ -551,21 +579,6 @@ func (app *Application) NewHost(srv *http.Server) *host.Supervisor {
|
|||
// create the new host supervisor
|
||||
// bind the constructed server and return it
|
||||
su := host.New(srv)
|
||||
|
||||
if app.config.GetVHost() == "" { // vhost now is useful for router subdomain on wildcard subdomains,
|
||||
// in order to correct decide what to do on:
|
||||
// mydomain.com -> invalid
|
||||
// localhost -> invalid
|
||||
// sub.mydomain.com -> valid
|
||||
// sub.localhost -> valid
|
||||
// we need the host (without port if 80 or 443) in order to validate these, so:
|
||||
app.config.SetVHost(netutil.ResolveVHost(srv.Addr))
|
||||
} else {
|
||||
context.GetDomain = func(_ string) string { // #1886
|
||||
return app.config.VHost // GetVHost: here we don't need mutex protection as it's request-time and all modifications are already made.
|
||||
}
|
||||
}
|
||||
|
||||
// app.logger.Debugf("Host: virtual host is %s", app.config.VHost)
|
||||
|
||||
// the below schedules some tasks that will run among the server
|
||||
|
@ -1142,7 +1155,7 @@ func (app *Application) tryConnect(ctx stdContext.Context, maxRetries int, retry
|
|||
// Context is canceled, return the context error.
|
||||
return ctx.Err()
|
||||
default:
|
||||
address := app.config.GetVHost() // Get this server's listening address.
|
||||
address := app.getVHost() // Get this server's listening address.
|
||||
if address == "" {
|
||||
i-- // Note that this may be modified at another go routine of the serve method. So it may be empty at first chance. So retry fetching the VHost every 1 second.
|
||||
time.Sleep(time.Second)
|
||||
|
@ -1200,7 +1213,7 @@ func (app *Application) tryStartTunneling() {
|
|||
|
||||
publicAddr := publicAddrs[0]
|
||||
// to make subdomains resolution still based on this new remote, public addresses.
|
||||
app.config.SetVHost(publicAddr[strings.Index(publicAddr, "://")+3:])
|
||||
app.setVHost(publicAddr[strings.Index(publicAddr, "://")+3:])
|
||||
|
||||
directLog := []byte(fmt.Sprintf("• Public Address: %s\n", publicAddr))
|
||||
app.logger.Printer.Write(directLog) // nolint:errcheck
|
||||
|
|
Loading…
Reference in New Issue
Block a user