Recientemente estaba migrando desde C # y buscaba crear algunas de mis aplicaciones antiguas. Como tal, necesitaba encontrar una manera de administrar sesiones dentro de las solicitudes web de Go. Encontré una solución en forma de este código:

// Jar is session object struct - cookie jar including mutex for syncing
type Jar struct {
    sync.Mutex
    cookies map[string][]*http.Cookie
}

// NewJar is a function for creating cookie jar for use
func NewJar() *Jar {
    jar := new(Jar)
    jar.cookies = make(map[string][]*http.Cookie)
    return jar
}

// SetCookies sets the cookies for the jar
func (jar *Jar) SetCookies(u *url.URL, cookies []*http.Cookie) {
    jar.Lock()
    if _, ok := jar.cookies[u.Host]; ok {
        for _, c := range cookies {
            jar.cookies[u.Host] = append(jar.cookies[u.Host], c)
        }
    } else {
        jar.cookies[u.Host] = cookies
    }
    jar.Unlock()
}

// Cookies returns cookies for each host
func (jar *Jar) Cookies(u *url.URL) []*http.Cookie {
    return jar.cookies[u.Host]
}

// NewJarClient creates new client, utilising a NewJar()
func NewJarClient() *http.Client {

    proxyURL, _ := url.Parse("http://127.0.0.1:8888")

    tr := &http.Transport{
        MaxIdleConns:       10,
        IdleConnTimeout:    30 * time.Second,
        DisableCompression: true,
        Proxy:              http.ProxyURL(proxyURL),
    }

    return &http.Client{
        Jar:       NewJar(),
        Transport: tr,
    }
}

El problema que tengo es entender cómo funciona esto. Creo un cliente haciendo lo siguiente

client := NewJarClient()

Pero luego, cuando emito funciones de red usándolo, como una solicitud de obtención, las cookies continúan automáticamente y todo funciona según lo planeado. El problema es que no tengo ni idea de por qué. No veo ninguna mención de métodos como el de Cookies o el de SetCookies que alguna vez se haya llamado y parece que solo maneja cada uno ejecutando mágicamente las funciones. ¿Podría alguien anotar o explicar los métodos dados línea por línea o de alguna manera para que tengan más sentido para mí viniendo de un fondo de C #? Gracias :)

0
James Morgan 14 nov. 2017 a las 22:18

2 respuestas

La mejor respuesta

NewJar asigna y devuelve una nueva instancia de tipo *Jar, ahora tipo *Jar, gracias a los métodos definidos en él, implementa la interfaz llamada CookieJar, implícitamente.

El tipo http.Client tiene un campo llamado Jar que se define como de tipo CookieJar, eso significa que puede configurar http.Client.Jar para cualquier cosa que implemente CookieJar interfaz, incluido el tipo *Jar. La función NewJarClient devuelve una nueva instancia de *http.Client con su campo Jar configurado en la instancia *Jar devuelta por NewJar.

Esto permite que el valor del cliente devuelto use los métodos de *Jar sin saber realmente que es un *Jar, solo sabe que el valor en su campo Jar tiene el mismo conjunto de métodos que esos definido por la interfaz CookieJar.

Entonces, la instancia de http.Client, cuando envía solicitudes, usa su *Jar llamando a sus métodos que proporcionan los parámetros y manejan los valores devueltos. La forma en que el cliente utiliza su *Jar es un detalle de implementación del tipo http.Client y no tiene que preocuparse por eso. Solo necesita asegurarse de que los métodos que implementan la interfaz CookieJar hagan lo que usted quiere que hagan, cómo y cuándo se llaman depende del cliente.

Pero si está interesado en los detalles de implementación del cliente de todos modos, puede consultar el archivo fuente de http.Client.

0
mkopriva 14 nov. 2017 a las 20:06

Debido a la desinformación en forma de algunas publicaciones de blog fechadas, tuve la impresión de que no podía mantener las cookies en las solicitudes en curso, por alguna extraña razón. Habiendo pensado eso, investigué y busqué crear mi propia implementación que se puede ver arriba. Me han llamado la atención que mi implementación está completamente rota y defectuosa y que la propia biblioteca http estándar puede manejar perfectamente el mantenimiento de cookies, simplemente incluyendo un valor para Jar al crear un cliente. Por ejemplo:

jar, _ := cookiejar.New(nil)

proxyURL, _ := url.Parse("http://127.0.0.1:8888")

tr := &http.Transport{
    MaxIdleConns:       10,
    IdleConnTimeout:    30 * time.Second,
    DisableCompression: true,
    Proxy:              http.ProxyURL(proxyURL),
}

c := &http.Client{
    Jar:       jar,
    Transport: tr,
} 
0
James Morgan 15 nov. 2017 a las 10:55