Gout — это HTTP-клиент, написанный на языке Go. Он разработан для повышения эффективности работы.
Архитектура:
Иконка: изображение gout-ad.png, расположенное по адресу https://github.com/guonaihong/images/blob/master/gout/gout-v0.0.8.png?raw=true.
Функции:
Демонстрация:
Изображение: gif-файл gout-example.gif, расположенный по адресу https://raw.githubusercontent.com/guonaihong/images/master/gout/gout-example.gif.
Содержание:
go get github.com/guonaihong/gout
Пример
В каталоге _example находятся примеры, которые можно запустить напрямую. Если вы не понимаете, как использовать пример, вы можете описать то, что вызывает у вас затруднения, и создать issue.
Запуск команды:
cd _example
# GOPROXY — это открытие go module прокси, можно быстрее загрузить модуль
# При первом запуске нужно добавить GOPROXY для загрузки модуля, если модули уже установлены, просто запустите go run 01-color-json.go
env GOPROXY=https://goproxy.cn go run 01-color-json.go
Быстрый старт
package main
import (
"fmt"
"github.com/guonaihong/gout"
"time"
)
// Используется для анализа тела ответа сервера
type RspBody struct {
ErrMsg string `json:"errmsg"`
ErrCode int `json:"errcode"`
Data string `json:"data"`
}
// Используется для анализа заголовка ответа сервера
type RspHeader struct {
Sid string `header:"sid"`
Time int `header:"time"`
}
func main() {
rsp := RspBody{}
header := RspHeader{}
//code := 0
err := gout.
// POST запрос
POST("127.0.0.1:8080").
// Открыть режим отладки
Debug(true).
// Установить строку запроса
SetQuery(gout.H{"page": 10, "size": 10}).
// Установить заголовок HTTP
SetHeader(gout.H{"X-IP": "127.0.0.1", "sid": fmt.Sprintf("%x", time.Now().UnixNano())}).
// SetJSON устанавливает тело HTTP в формате JSON
// Есть аналогичные функции: BindJSON, BindYAML, BindXML, BindForm, BindWWWForm
SetJSON(gout.H{"text": "gout"}).
// BindJSON анализирует содержимое тела ответа
// Аналогичные функции: BindBody, BindYAML, BindXML
BindJSON(&rsp).
// Анализировать заголовок ответа
BindHeader(&header).
// код HTTP
// Code(&code).
// Завершить функцию
Do()
// Проверить ошибку
if err != nil {
fmt.Printf("send fail:%s\n", err)
}
}
/*
> POST /?page=10&size=10 HTTP/1.1
> Sid: 15d9b742ef32c130
> X-Ip: 127.0.0.1
> Content-Type: application/json
>
{
"text": "gout"
}
*/
Примеры API
GET, POST, PUT, DELETE, PATH, HEAD, OPTIONS
package main
import (
"github.com/guonaihong/gout"
)
func main() {
url := "https://github.com"
// Отправить GET запрос
gout.GET(url).Do()
// Отправить POST запрос
gout.POST(url).Do()
// Отправить PUT запрос
gout.PUT(url).Do()
// Отправить DELETE запрос
gout.DELETE(url).Do()
// Отправить PATH запрос
gout.PATCH(url).Do()
// Отправить HEAD запрос
gout.HEAD(url).Do()
// Отправить OPTIONS запрос
gout.OPTIONS(url).Do()
}
Параметры запроса
SetQuery
package main
import (
"fmt"
"github.com/guonaihong/gout"
"time"
)
func main() {
err := gout.
// Устанавливаем GET запрос и url, :8080/test.query — это 127.0.0.1:8080/test.query в сокращённом виде
GET(":8080/test.query").
// Включаем режим отладки
Debug(true).
// Устанавливаем строку запроса
SetQuery(gout.H{
"q1": "v1",
"q2": 2,
"q3": float32(3.14),
"q4": 4.56,
"q5": time.Now().Unix(),
"q6": time.Now().UnixNano(),
"q7": time.Now().Format("2006-01-02")}).
// Заканчиваем функцию
Do()
if err != nil {
fmt.Printf("%s\n", err)
return
}
}
/*
> GET /test.query?q1=v1&q2=2&q3=3.14&q4=4.56&q5=1574081600&q6=1574081600258009213&q7=2019-11-18 HTTP/1.1
>
< HTTP/1.1 200 OK
< Content-Length: 0
*/
SetQuery поддерживает больше типов данных
package main
import (
"github.com/guonaihong/gout"
)
func main() {
code := 0
err := gout. ```
// Отправляем GET запрос :8080/testquery на 127.0.0.1:8080/testquery в краткой форме
GET(":8080/testquery").
// Устанавливаем строку запроса
SetQuery( /*см. ниже поддерживаемые случаи*/ ).
// Анализируем код HTTP, если не интересует ответ сервера, то эту функцию можно не устанавливать
Code(&code).
Do()
if err != nil {
}
}
/*
Поддерживаются следующие типы для SetQuery:
* string
* map[string]interface{} (можно использовать gout.H как псевдоним)
* struct
* array, slice (длина должна быть чётной)
*/
// 1. string
SetQuery("check_in=2019-06-18&check_out=2018-06-18")
// 2. gout.H или map[string]interface{}
SetQuery(gout.H{
"check_in":"2019-06-18",
"check_out":"2019-06-18",
})
// 3. struct
type testQuery struct {
CheckIn string `query:checkin`
CheckOut string `query:checkout`
}
SetQuery(&testQuery{CheckIn:2019-06-18, CheckOut:2019-06-18})
// 4. array or slice
// ?active=enable&action=drop
SetQuery([]string{"active", "enable", "action", "drop"})```
package main
import (
"fmt"
"github.com/guonaihong/gout"
"time"
)
func main() {
err := gout.
// Устанавливаем GET запрос и url, :8080/test.header — это 127.0.0.1:8080/test.header в краткой записи
GET(":8080/test.header").
// Включаем режим отладки
Debug(true).
// Устанавливаем заголовок HTTP
SetHeader(gout.H{
"h1": "v1",
"h2": 2,
"h3": float32(3.14),
"h4": 4.56,
"h5": time.Now().Unix(),
"h6": time.Now().UnixNano(),
"h7": time.Now().Format("2006-01-02")}).
Do()
if err != nil {
fmt.Printf("%s\n", err)
return
}
}
/*
> GET /test.header HTTP/1.1
> H2: 2
> H3: 3.14
> H4: 4.56
> H5: 1574081686
> H6: 1574081686471347098
> H7: 2019-11-18
> H1: v1
>
< HTTP/1.1 200 OK
< Content-Length: 0
*/
package main
import (
"fmt"
"github.com/guonaihong/gout"
"time"
)
// Аналогично анализу JSON, для анализа HTTP заголовка необходимо установить тег header
type rspHeader struct {
Total int `header:"total"`
Sid string `header:"sid"`
Time time.Time `header:"time" time_format:"2006-01-02"`
}
func main() {
rsp := rspHeader{}
err := gout.
// :8080/test.header — http://127.0.0.1:8080/test.header в краткой записи
GET(":8080/test.header").
// Включить режим отладки
Debug(true).
// Привязать заголовок запроса к структуре
BindHeader(&rsp).
// Завершить функцию
Do()
if err != nil {
fmt.Printf("%s\n", err)
return
}
fmt.Printf("rsp header:\n%#v \nTime:%s\n", rsp, rsp.Time)
}
/*
> GET /test.header HTTP/1.1
>
< HTTP/1.1 200 OK
< Content-Length: 0
< Sid: 1234
< Time: 2019-11-18
< Total: 2048
*/
### SetHeader и BindHeader поддерживают больше типов
<details>
```go
package main
import (
"fmt"
"github.com/guonaihong/gout"
)
type testHeader struct {
CheckIn string `header:checkin`
CheckOut string `header:checkout`
}
func main() {
t := testHeader{}
code := 0
err := gout.
GET(":8080/testquery").
Code(&code).
SetHeader( /*см. ниже поддерживаемый тип*/ ).
BindHeader(&t).
Do()
if err != nil {
fmt.Printf("fail:%s\n", err)
}
}
// struct
type testHeader struct {
CheckIn string `header:checkin`
CheckOut string `header:checkout`
}
/*
map[string]interface{}, можно использовать gout.H как псевдоним
struct
array, slice (длины должны быть чётными)
*/
// gout.H либо map[string]interface{}
SetHeader(gout.H{
"check_in":"2019-06-18",
"check_out":"2019-06-18",
})
// struct
type testHeader struct {
CheckIn string `header:checkin`
CheckOut string `header:checkout`
}
SetHeader(&testHeader{CheckIn:2019-06-18, CheckOut:2019-06-18})
// array или slice
// -H active:enable -H action:drop
SetHeader([]string{"active", "enable", "action", "drop"})
type testValid struct {
Val string valid:"required"
}
func main() { tv := testValid{} err := gout. // Установить POST метод и URL POST(":8080/req/body"). // Включить режим отладки Debug(true). // Разобрать JSON
并且当需要的字段没有值时, 返回错误 BindJSON(&tv). //结�ончание функции Do()
if err != nil {
fmt.Printf("%s\n", err)
return
}
}
## responseUse
response中间件,在Bind()之前执行。可以对response进行通用逻辑处理。
Если только нужна логика замыкания, можно использовать WithResponseMiddlerFunc, и не нужно создавать структуру, в следующем примере используются оба метода.
```go
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/gin-gonic/gin"
middler "github.com/guonaihong/gout/interface"
"io/ioutil"
"log"
"net/http"
"time"
)
// response拦截器修改示例
type demoResponseMiddler struct{}
func (d *demoResponseMiddler) ModifyResponse(response *http.Response) error {
// 修改responseBody。 Потому что возвращаемое значение, вероятно, будет иметь поля { code, data,msg}, надеемся провести унифицированную обработку
//здесь хотим проверить код. Если не подходит, то возвращаем ошибку. В противном случае записываем содержимое data в body, чтобы при последующем BindJson можно было напрямую обработать бизнес
all, err := ioutil.ReadAll(response.Body)
если err != nil, {
вернуть err
}
obj := make(map[string]interface{})
err = json.Unmarshal(all, &obj)
если err != nil, {
вернуть err
}
code := obj["code"]
msg := obj["msg"]
data := obj["data"]
// Go中json中的数字 после десериализации станут типом float64
если float64(200) != code, {
вернуть errors.New(fmt.Sprintf("запрос не удался, code %d msg %s", code, msg))
} иначе {
byt, _ := json.Marshal(&data)
response.Body = ioutil.NopCloser(bytes.NewReader(byt))
вернуть nil
}
}
func demoResponse() *demoResponseMiddler {
вернуть &demoResponseMiddler{}
}
func main() {
go server() //запустить тестовый сервис
time.Sleep(time.Millisecond * 500) //использовать время для ожидания синхронизации
responseUseExample()
}
func responseUseExample() {
//успешный запрос
successRes := new(map[string]interface{})
err := gout.GET(":8080/success").ResponseUse(
demoResponse(),
// обратите внимание на использование WithResponseMiddlerFunc здесь
middler.WithResponseMiddlerFunc(func(response *http.Response) error {
// Do your magic
вернуть nil
}),
).BindJSON(&successRes).Do()
log.Printf("успешный запрос --> ответ %s \n err %s \n ", successRes, err)
//неудачный запрос
failRes := new(map[string]interface{})
err = gout.GET(":8080/fail").ResponseUse(demoResponse()).BindJSON(&failRes).Do()
log.Printf("неудачный запрос --> ответ %s \n err %s \n ", successRes, err)
}
type Result struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}
type Item struct {
Id string `json:"id"`
Name string `json:"name"`
}
func server() {
router := gin.New()
router.GET("/success", func(c *gin.Context) {
c.JSON(200, Result{200, "запрос выполнен успешно", Item{"001", "Чжан Сань"}})
})
router.GET("/fail", func(c *gin.Context) {
c.JSON(200, Result{500, "ошибка запроса к базе данных", nil})
})
router.Run()
}
Перевод:
И далее, когда требуется значение поля, возвращается ошибка: BindJSON(&tv). //Завершение функции. Do().
Если err не равно nil, то: fmt.Printf("%s\n", err); return.
Response — это промежуточное ПО, которое выполняется перед Bind(). Оно позволяет выполнять общую логику обработки ответа. Если вам нужна только логика закрытия, вы можете использовать WithResponseMiddlerFunc и не создавать структуру. В следующем примере используется оба метода.
Импорт:
"bytes",
"encoding/json",
"errors",
"fmt",
"github.com/gin-gonic/gin",
middler "github.com/guonaihong/gout/interface",
"io/ioutil",
"log",
"net/http",
"time",
```
**Пример модификации response-перехватчика:**
Тип demoResponseMiddler представляет собой пустую структуру.
Функция (d * demoResponseMiddler) ModifyResponse принимает ответ * http.Response в качестве аргумента и возвращает ошибку. Она изменяет responseBody, потому что возвращаемое значение может содержать поля {code, data, msg}. Мы надеемся выполнить унифицированную обработку. Здесь мы хотим проверить код, если он не подходит, мы возвращаем ошибку, иначе мы записываем содержимое данных в тело, чтобы мы могли напрямую обрабатывать бизнес при последующем BindJSON.
Все, err: = ioutil.ReadAll (response.Body), если err! = nil, вернуть err.
Obj: = make (map [string] interface {}), err = json.Unmarshal (all, & obj), если err! = nil, вернуть err.
Код: = obj ["код"], msg: = obj ["msg"], данные: = obj ["данные"].
В Go числа после десериализации становятся типом float64. Если float64 (200)! = код, верните errors.New (fmt.Sprintf ("запрос не выполнен, код % d msg % s", код, msg)). Иначе byt, _: = json.Marshal (& data), response.Body = ioutil.NopCloser (bytes.NewReader (byt)), вернуть nil.
DemoResponse: = & demoResponseMiddler возвращает * demoResponseMiddler.
Основная функция запускает тестовый сервер с помощью go server (), ждёт синхронизации с time.Sleep (time.Millisecond * 500), затем вызывает responseUseExample ().
ResponseUseExample выполняет успешный и неудачный запросы.
Успешный запрос: successRes: = new (map [строка] интерфейс {}), err: = gout.GET (": 8080 / успех"). ResponseUse (demoResponse (), middler.WithResponseMiddlerFunc (func (ответ * http.Response) ошибка {Do your magic, return nil}), BindJSON (& successRes), Do ()). Log.Printf ("успешный запрос -> ответ % s \n err % s \n", successRes, err).
Неудачный запрос: failRes: = new (map [строка] интерфейс {}), err: = gout.GET (": 8080 / сбой"). ResponseUse (demoResponse ()), BindJSON (& failRes), Do (). Log.Printf («неудачный запрос -> ответ % s \n err % s \n», successRes, err).
Структура результата содержит код int Msg string Data interface {}, структура элемента содержит Id string Name string.
Серверная функция создаёт маршрутизатор gin.New (), добавляет маршруты GET / success и GET / fail, которые возвращают результаты успешного и неудачного запросов соответственно. Затем запускается маршрутизатор с помощью router.Run (). **Текст запроса на русском языке:**
Использование различных методов отправки данных в запросах:
* использование структуры;
* x-www-form-urlencoded;
* protobuf;
* callback;
* get .Response;
* multiple binding functions;
* set request timeout;
* proxy;
* socks5.
**Основной язык текста запроса:** язык Go.
В запросе присутствуют фрагменты кода, которые не удалось перевести. Это связано с тем, что некоторые конструкции специфичны для языка программирования Go и не имеют прямых аналогов в русском языке. **benchConcurrent = 30**)
func main() {
err := gout.
POST(":8080"). //давление на локальный порт 8080
SetJSON(gout.H{"hello": "world"}). //установка содержимого запроса body
Filter(). //открытие фильтра
Bench(). //выбор функции bench
Concurrent(benchConcurrent). //количество одновременных запросов
Durations(benchTime). //время тестирования
Do()
if err != nil {
fmt.Printf("%v\n", err)
}
}
**benchmark-rate**
Следующий пример запускает 20 одновременных запросов. Для сервиса порта :8080 проводится тестирование с общим количеством запросов 3000, при этом каждую секунду отправляется 1000 запросов. Содержимое представляет собой структуру json:
```go
package main
import (
"fmt"
"github.com/guonaihong/gout"
)
const (
benchNumber = 3000
benchConcurrent = 20
)
func main() {
err := gout.
POST(":8080"). //давление на локальный порт 8080
SetJSON(gout.H{"hello": "world"}). //установка содержимого запроса body
Filter(). //открытие фильтра
Bench(). //выбор функции bench
Rate(1000). //1000 запросов в секунду
Concurrent(benchConcurrent). //количество одновременных запросов
Number(benchNumber). //количество запросов
Do()
if err != nil {
fmt.Printf("%v\n", err)
}
}
```
**Custom benchmark functions**
Пользовательские функции тестирования, создающие разные данные http-запроса для каждого теста:
```go
package main
import (
"fmt"
"github.com/google/uuid"
"github.com/guonaihong/gout"
"github.com/guonaihong/gout/filter"
"sync/atomic"
)
func main() {
i := int32(0)
err := filter.NewBench().
Concurrent(30). //запуск 30 горутин
Number(30000). //тестирование 30 000 раз
Loop(func(c *gout.Context) error {
// следующий код генерирует разные данные HTTP-запросов для каждого теста
uid := uuid.New() //создание uuid
id := atomic.AddInt32(&i, 1) //генерация id, можно понять как ++i, потокобезопасная версия
c.POST(":1234").SetJSON(gout.H{
"sid": uid.String(),
"appkey": fmt.Sprintf("ak:%d", id),
"text": fmt.Sprintf("test text :%d", id)})
return nil
}).Do()
if err != nil {
fmt.Printf("err = %v\n", err)
}
}
```
**retry-backoff**
Функция retry использует алгоритм с колебаниями и экспоненциальным откатом [backoff](http://www.awsarchitectureblog.com/2015/03/backoff.html):
```go
package main
import (
"fmt"
"github.com/guonaihong/gout"
"time"
)
func main() {
err := gout.HEAD("127.0.0.1:8080").
Debug(true). //включение режима отладки
Filter(). //открытие фильтра
Retry(). //включение функции повтора
Attempt(5). //максимум 5 попыток
WaitTime(500 * time.Millisecond). //основное время ожидания
MaxWaitTime(3 * time.Second). //максимальное время ожидания
Do()
if err != nil {
fmt.Printf("err = %v\n", err)
}
}
```
**retry conditions httpcode**
Указаны условия повтора, в этом примере сервер возвращает статус 209, после чего происходит повтор:
[полный код](_example/19c-retry-httpcode.go)
``` go
package main
import (
"fmt"
"github.com/guonaihong/gout"
"github.com/guonaihong/gout/filter"
"time"
)
func useRetryFuncCode() {
s := ""
err := gout.GET(":8080/code").Debug(true).BindBody(&s).F().
Retry().Attempt(3).WaitTime(time.Millisecond * 10).MaxWaitTime(time.Millisecond * 50).
Func(func(c *gout.Context) error {
if c.Error != nil || c.Code == 209 {
return filter.ErrRetry
}
return nil
}).Do()
fmt.Printf("err = %v\n", err)
}
```
**retry conditions backupurl**
Заданы условия повтора, здесь по умолчанию URL недоступен, используется резервный URL для доступа:
[полный код](_example/19b-retry-customize-backup.go)
```go
package main
import (
"fmt"
"github.com/guonaihong/gout"
"github.com/guonaihong/gout/core"
"github.com/guonaihong/gout/filter"
"time"
)
func useRetryFunc() {
// получение неиспользуемого порта
port := core.GetNoPortExists()
s := ""
err := gout.GET(":" + port).Debug(true).BindBody(&s).F().
Retry().Attempt(3).WaitTime(time.Millisecond * 10).MaxWaitTime(time.Millisecond * 50).
Func(func(c *gout.Context) error {
if c.Error != nil {
c.SetHost(":1234") //должен быть существующий порт
return filter.ErrRetry
}
return nil
}).Do()
fmt.Printf("err = %v\n", err)
}
``` ```
package main
import (
"fmt"
"github.com/guonaihong/gout"
)
func main() {
s := `POST /colorjson HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Go-http-client/1.1
Content-Length: 97
Content-Type: application/json
Accept-Encoding: gzip
{"array":["foo","bar","baz"],"bool":false,"null":null,"num":100,"obj":{"a":1,"b":2},"str":"foo"}`
err := gout.NewImport().RawText(s).Debug(true).SetHost(":1234").Do()
if err != nil {
fmt.Printf("err = %s\n", err)
return
}
}
```
```
package main
import (
"fmt"
"github.com/guonaihong/gout"
)
func main() {
// 1.formdata
err := gout.GET(":1234").
SetForm(gout.A{"text", "good", "mode", "A", "voice", gout.FormFile("./t8.go")}).
Export().Curl().Do()
// output:
// curl -X GET -F "text=good" -F "mode=A" -F "voice=@./voice" "http://127.0.0.1:1234"
// 2.json body
err = gout.GET(":1234").
SetJSON(gout.H{"key1": "val1", "key2": "val2"}).
Export().Curl().Do()
// output:
// curl -X GET -H "Content-Type:application/json" -d "{\"key1\":\"val1\",\"key2\":\"val2\"}" "http://127.0.0.1:1234"
fmt.Printf("%v\n", err)
}
```
```
package main
import (
"fmt"
"github.com/guonaihong/gout"
)
func main() {
// 1.formdata
err := gout.GET(":1234").
SetForm(gout.A{"text", "good", "mode", "A", "voice", gout.FormFile("./t8.go")}).
Export().Curl().GenAndSend().Do()
// output:
// curl -X GET -F "text=good" -F "mode=A" -F "voice=@./voice" "http://127.0.0.1:1234"
// 2.json body
err = gout.GET(":1234").
SetJSON(gout.H{"key1": "val1", "key2": "val2"}).
Export().Curl().GenAndSend().Do()
// output:
// curl -X GET -H "Content-Type:application/json" -d "{\"key1\":\"val1\",\"key2\":\"val2\"}" "http://127.0.0.1:1234"
fmt.Printf("%v\n", err)
}
```
```
package main
import (
"fmt"
"net/http"
"github.com/guonaihong/gout"
)
func main() {
c := &http.Client{} //http.Client里面有fd连接池,如果对这块优化不是太了解,只使用一个实例就行
err := gout.New(c). // New接口可传入http.Client对象
GET("www.qq.com").
Debug(true).
Do()
if err != nil {
fmt.Printf("err = %s\n", err)
return
}
}
```
```
package main
import (
"fmt"
"github.com/guonaihong/gout"
)
func main() {
err := gout.POST(":8080").
Chunked().
SetBody("11111111111").
Do()
if err != nil {
fmt.Printf("err :%v\n", err)
}
}
// 使用nc 起一个tcp服务, 使用上面的代码发起数据观察下结果
// nc -l 8080
```
```
package main
import (
"fmt"
"github.com/guonaihong/gout"
)
func main() {
err := gout.POST("/colorjson").
Chunked().
SetBody(`{"array":["foo","bar","baz"],"bool":false,"null":null,"num":100,"obj":{"a":1,"b":2},"str":"foo"}`).
Do()
if err != nil {
fmt.Printf("err :%v\n", err)
return
}
}
```
```
import (
"github.com/guonaihong/gout"
)
func main() {
globalWithOpt := gout.NewWithOpt(gout.WithInsecureSkipVerify())
err := globalWithOpt.GET("url").Do()
if err != nil {
fmt.Printf("err = %v\n" ,err)
return
}
}
```
```
import (
"github.com/guonaihong/gout"
)
func main() {
globalWithOpt := gout.NewWithOpt(gout.WithClose3xxJump())
err := globalWithOpt.GET("url").Do()
if err != nil {
fmt.Printf("err = %v\n" ,err)
return
}
}
```
```
import (
"github.com/guonaihong/gout"
)
func main() {
globalWithOpt := gout.NewWithOpt(gout.WithTimeout())
err := globalWithOpt.GET("url").Do()
if err != nil {
fmt.Printf("err = %v\n" ,err)
return
}
}
``` **err := globalWithOpt.GET("url").Do()**
if err != nil {
fmt.Printf("err = %v\n", err)
return
}
}
# Глобальная конфигурация
## Установка таймаута
Устанавливает глобальное время ожидания. Это может упростить некоторый код. При использовании глобальной конфигурации по умолчанию вы уже знаете о некоторых недостатках, которые она может вызвать.
```go
package main
import (
"fmt"
"github.com/guonaihong/gout"
"time"
)
func main() {
gout.SetTimeout(time.Second * 1)
err := gout.GET("www.baidu.com").Do()
if err != nil {
fmt.Printf("ошибка: %v\n")
}
}
```
## Включение отладки
Включает глобальный переключатель отладки.
```go
package main
import (
"fmt"
"github.com/guonaihong/gout"
)
func main() {
gout.SetDebug(true)
err := gout.GET(":8080/colorjson").Do()
if err != nil {
fmt.Printf("ошибка: %v\n")
}
}
```
# Уникальные функции
## Пересылка данных gin
Gout был разработан с учётом возможности совместной работы с gin. Ниже показано, как легко использовать gout для пересылки данных, связанных с gin.
```go
package main
import (
"github.com/gin-gonic/gin"
"github.com/guonaihong/gout"
)
type testQuery struct {
Size int `query:"size" form:"size"` // tag запроса — это то, что нужно gout для установки строки запроса
Page int `query:"page" form:"page"`
Ak string `query:"ak" form:"ak"`
}
// Следующий узел сервера
func nextSever() {
r := gin.Default()
r.GET("/query", func(c *gin.Context) {
q := testQuery{}
err := c.ShouldBindQuery(&q)
if err != nil {
return
}
c.JSON(200, q)
})
r.Run(":1234")
}
func main() {
go nextSever()
r := gin.Default()
// Демонстрация привязки строки запроса gin к узлу nextServer
r.GET("/query", func(c *gin.Context) {
q := testQuery{}
// Привязка строки запроса
err := c.ShouldBindQuery(&q)
if err != nil {
return
}
// Разработка пересылки, повторное использование переменной q структуры gin
code := 0 // код HTTP
err = gout.
// Отправка запроса GET
GET("127.0.0.1:1234/query").
// Установка строки запроса
SetQuery(q).
// Интересуемся возвращаемым статусом HTTP-сервера, устанавливаем эту функцию
Code(&code).
Do()
if err != nil || code != 200 { /* todo Need to handle errors here */
}
c.JSON(200, q)
})
r.Run()
}
// HTTP-клиент
// curl '127.0.0.1:8080/query?size=10&page=20&ak=test'
```
# Часто задаваемые вопросы
## Как обстоят дела с производительностью gout benchmark?
Ниже приведён сравнительный анализ производительности с apache ab [_example/16d-benchmark-vs-ab.go_](_example/16d-benchmark-vs-ab.go).
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )