Golang gin, когда использовать handleContext и когда перенаправить

Обработав запрос GET, я хочу перенаправить пользователя на новый URL-адрес, обрабатываемый моим приложением, который отображает результаты.

В документации по джину я нашел два разных способа сделать это. Один из них — использовать функцию redirect() gin, а другой — функцию маршрутизатора HandleContext(). В цитируемой документации говорится, что redirect() следует использовать для запроса POST или для запроса GET, но затем говорится, что HandleContext() следует использовать для перенаправления «Маршрутизатор». Я не уверен, что полностью понимаю последствия использования того или другого.

Первый вариант использования, приведенный в приведенной выше документации:

r.GET("/test", func(c *gin.Context) {
    c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
})

Отличительной особенностью здесь является то, что перенаправление осуществляется на внешний URL-адрес, а не на само приложение. Второй вариант использования, который описывается как «перенаправление маршрутизатора», следующий:

r.GET("/test", func(c *gin.Context) {
    c.Request.URL.Path = "/test2"
    r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {
    c.JSON(200, gin.H{"hello": "world"})
})

Похоже, это необходимо, если URL-адрес для перенаправления — это путь, обрабатываемый моим приложением.

Но это URL-адрес, как и любой другой. Так почему бы просто не использовать c.redirect() для перенаправления маршрутизатора?

Интуитивно это очевидно. Но я подозреваю, что это приводит к неожиданному поведению (или, по крайней мере, к поведению, которого я лично не ожидал)

Что плохого в использовании c.redirect() для перенаправления маршрутизатора и в чем разница между ним и router.HandleContext()?

Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
2
0
138
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Разница в том, что HandleContext() выполняет внутреннее перенаправление, которое клиент никогда не замечает, тогда как Redirect() фактически отправляет ответ Http-клиенту, уведомляя его о том, что ресурс изменился.

Я думаю, что лучше всего это можно проиллюстрировать, наблюдая за DevTools браузера.

HandleContext(): Как видите, здесь клиент даже не заметил, что запрос был внутренне перенаправлен на другой обработчик.

Redirect(): Здесь клиент был вынужден сделать два запроса, чтобы получить реальный ресурс. Также обратите внимание, что в строке URL-адреса теперь отображается URL-адрес перенаправленного запроса.

Очевидно, что выполнение двух запросов приводит к ухудшению производительности, поэтому для внутренних перенаправлений следует отдавать предпочтение router.HandleContext().

Если вы хотите проверить себя, вот код:

package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    // Switch the uncommented block in order to see the effect of HandleContext.
    /* r.GET("/test", func(c *gin.Context) {
        c.Request.URL.Path = "/test2"
        r.HandleContext(c)
    })
    r.GET("/test2", func(c *gin.Context) {
        c.JSON(200, gin.H{"hello": "world"})
    }) */

    r.GET("/test", func(c *gin.Context) {
        c.Redirect(http.StatusMovedPermanently, "/test2")
    })
    r.GET("/test2", func(c *gin.Context) {
        c.JSON(200, gin.H{"hello": "world"})
    })

    r.Run()
}

Большое спасибо. Это проясняет. Только один вопрос: правильно ли я считаю, что никаких негативных последствий, кроме небольшого снижения производительности, при использовании редиректа нет? Я спрашиваю об этом, потому что я также пишу сервер, который обрабатывает запросы API, и, по крайней мере, в целях разработки удобно проверять, был ли запрос отправлен.

ancient geek 07.05.2024 20:11

Если вас также устраивает, что клиент заметил перенаправление, тогда ответ должен быть утвердительным.

frankenapps 07.05.2024 20:45

Я обнаружил еще одну разницу между ctx.Redirect и HandleContext, которая может заинтересовать других.

В каком-то коде, который я писал, Redirect выдал следующее предупреждение:

[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 301 with 200

Код был следующим:

// if user has no simulations, redirect to the user dashboard
if user.CurrentSimulationID == 0 {
    ctx.Redirect(http.StatusMovedPermanently, "/user/dashboard")
    ctx.Abort()
}

в котором говорится, что когда пользователи пытаются отобразить страницу, в которой нет ничего полезного, они перенаправляются на страницу, которая позволяет им генерировать что-то полезное.

Если я правильно понял, Redirect создаёт заголовок со статусом 301. Но страница, на которую я перенаправляюсь, хочет создать заголовок со статусом 200.

Следующий код не вызывает такого конфликта:

// if user has no simulations, redirect to the user dashboard
if u.CurrentSimulationID == 0 {
    ctx.Request.URL.Path = `/user/dashboard`
    Router.HandleContext(ctx)
    ctx.Abort()
}

Вероятно, существует способ использовать Redirect таким образом, чтобы не было предупреждения, например, путем модифицированного вызова Abort. Или, может быть, другой вызов Redirect, который не устанавливает статус.

Я осмотрелся, но не нашел работающего решения. Но в любом случае вариант Router.HandleContext мне кажется лучше по причинам, указанным @frankenapps.

Суть вышесказанного в том, что между этими двумя вариантами, похоже, есть реальная практическая разница, кроме скорости.

Другие вопросы по теме