HTTP Builder / Groovy - потеря 302 (перенаправление) обработки? - PullRequest
6 голосов
/ 04 июня 2010

я читаю здесь http://groovy.codehaus.org/modules/http-builder/doc/handlers.html «В случаях, когда ответ отправляет код состояния перенаправления, это обрабатывается внутри Apache HttpClient, который по умолчанию просто следует за перенаправлением, повторно отправляя запрос на новый URL. следуйте 302 ответам. "

Кажется, это работает нормально, когда я просто использую методы get () или post () без замыкания.

Однако, когда я использую замыкание, я теряю 302 обработки. Есть ли способ, которым я могу справиться с этим сам? Спасибо

p.s. Вот мой вывод журнала, показывающий, что это 302 ответа

 [java] FINER: resp.statusLine: "HTTP/1.1 302 Found"

Вот соответствующий код:

// Copyright (C) 2010 Misha Koshelev. All Rights Reserved.
package com.mksoft.fbbday.main

import groovyx.net.http.ContentType

import java.util.logging.Level
import java.util.logging.Logger

class HTTPBuilder {
  def dataDirectory
  HTTPBuilder(dataDirectory) {
    this.dataDirectory=dataDirectory
  }

  // Main logic
  def logger=Logger.getLogger(this.class.name)
  def closure={resp,reader->
    logger.finer("resp.statusLine: \"${resp.statusLine}\"")
    if (logger.isLoggable(Level.FINEST)) {
      def respHeadersString='Headers:';
      resp.headers.each() { header->respHeadersString+="\n\t${header.name}=\"${header.value}\"" }
      logger.finest(respHeadersString)
    }

    def text=reader.text
    def lastHtml=new File("${dataDirectory}${File.separator}last.html")
    if (lastHtml.exists()) {
      lastHtml.delete()
    }
    lastHtml<<text
    new XmlSlurper(new org.cyberneko.html.parsers.SAXParser()).parseText(text)          
  }
  def processArgs(args) {
    if (logger.isLoggable(Level.FINER)) {
      def argsString='Args:';
      args.each() { arg->argsString+="\n\t${arg.key}=\"${arg.value}\"" }
      logger.finer(argsString)
    }
    args.contentType=groovyx.net.http.ContentType.TEXT
    args
  }

  // HTTPBuilder methods
  def httpBuilder=new groovyx.net.http.HTTPBuilder ()
  def get(args) {
    httpBuilder.get(processArgs(args),closure)
  }
  def post(args) {
    args.contentType=groovyx.net.http.ContentType.TEXT
    httpBuilder.post(processArgs(args),closure) 
  }
}

Вот специальный тестер:

#!/usr/bin/env groovy

import groovyx.net.http.HTTPBuilder
import groovyx.net.http.Method
import static groovyx.net.http.ContentType.URLENC

import java.util.logging.ConsoleHandler
import java.util.logging.Level
import java.util.logging.Logger

// MUST ENTER VALID FACEBOOK EMAIL AND PASSWORD BELOW !!!
def email=''
def pass=''

// Remove default loggers
def logger=Logger.getLogger('')
def handlers=logger.handlers
handlers.each() { handler->logger.removeHandler(handler) }

// Log ALL to Console
logger.setLevel Level.ALL
def consoleHandler=new ConsoleHandler()
consoleHandler.setLevel Level.ALL
logger.addHandler(consoleHandler)

// Facebook - need to get main page to capture cookies
def http = new HTTPBuilder()
http.get(uri:'http://www.facebook.com')

// Login
def html=http.post(uri:'https://login.facebook.com/login.php?login_attempt=1',body:[email:email,pass:pass])
assert html==null

// Why null?
html=http.post(uri:'https://login.facebook.com/login.php?login_attempt=1',body:[email:email,pass:pass]) { resp,reader->
  assert resp.statusLine.statusCode==302

  // Shouldn't we be redirected???
  // http://groovy.codehaus.org/modules/http-builder/doc/handlers.html
  // "In cases where a response sends a redirect status code, this is handled internally by Apache HttpClient, which by default will simply follow the redirect by re-sending the request to the new URL. You do not need to do anything special in order to follow 302 responses. "
}

Вот соответствующие журналы:

FINE: Receiving response: HTTP/1.1 302 Found
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << HTTP/1.1 302 Found
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << Expires: Sat, 01 Jan 2000 00:00:00 GMT
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << Location: http://www.facebook.com/home.php?
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << P3P: CP="DSP LAW"
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << Pragma: no-cache
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << Set-Cookie: datr=1275687438-9ff6ae60a89d444d0fd9917abf56e085d370277a6e9ed50c1ba79; expires=Sun, 03-Jun-2012 21:37:24 GMT; path=/; domain=.facebook.com
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << Set-Cookie: lxe=koshelev%40post.harvard.edu; expires=Tue, 28-Sep-2010 15:24:04 GMT; path=/; domain=.facebook.com; httponly
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << Set-Cookie: lxr=deleted; expires=Thu, 04-Jun-2009 21:37:23 GMT; path=/; domain=.facebook.com; httponly
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << Set-Cookie: pk=183883c0a9afab1608e95d59164cc7dd; path=/; domain=.facebook.com; httponly
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << Content-Type: text/html; charset=utf-8
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << X-Cnection: close
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << Date: Fri, 04 Jun 2010 21:37:24 GMT
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.DefaultClientConnection receiveResponseHeader
FINE: << Content-Length: 0
Jun 4, 2010 4:37:22 PM org.apache.http.client.protocol.ResponseProcessCookies processCookies
FINE: Cookie accepted: "[version: 0][name: datr][value: 1275687438-9ff6ae60a89d444d0fd9917abf56e085d370277a6e9ed50c1ba79][domain: .facebook.com][path: /][expiry: Sun Jun 03 16:37:24 CDT 2012]". 
Jun 4, 2010 4:37:22 PM org.apache.http.client.protocol.ResponseProcessCookies processCookies
FINE: Cookie accepted: "[version: 0][name: lxe][value: koshelev%40post.harvard.edu][domain: .facebook.com][path: /][expiry: Tue Sep 28 10:24:04 CDT 2010]". 
Jun 4, 2010 4:37:22 PM org.apache.http.client.protocol.ResponseProcessCookies processCookies
FINE: Cookie accepted: "[version: 0][name: lxr][value: deleted][domain: .facebook.com][path: /][expiry: Thu Jun 04 16:37:23 CDT 2009]". 
Jun 4, 2010 4:37:22 PM org.apache.http.client.protocol.ResponseProcessCookies processCookies
FINE: Cookie accepted: "[version: 0][name: pk][value: 183883c0a9afab1608e95d59164cc7dd][domain: .facebook.com][path: /][expiry: null]". 
Jun 4, 2010 4:37:22 PM org.apache.http.impl.client.DefaultRequestDirector execute
FINE: Connection can be kept alive indefinitely
Jun 4, 2010 4:37:22 PM groovyx.net.http.HTTPBuilder doRequest
FINE: Response code: 302; found handler: post302$_run_closure2@7023d08b
Jun 4, 2010 4:37:22 PM groovyx.net.http.HTTPBuilder doRequest
FINEST: response handler result: null
Jun 4, 2010 4:37:22 PM org.apache.http.impl.conn.SingleClientConnManager releaseConnection
FINE: Releasing connection org.apache.http.impl.conn.SingleClientConnManager$ConnAdapter@605b28c9

Вы можете видеть, что явно есть аргумент местоположения.

Спасибо Миша

Ответы [ 3 ]

11 голосов
/ 16 июня 2010

У меня была такая же проблема с HTTPBuilder, пока я не понял, что спецификация HTTP / 1.1 гласит:

Перенаправление 3xx

[..] Этот класс кода состояния указывает что дальнейшие действия должны быть
приняты пользовательским агентом для того, чтобы выполнить запрос. Акция
требуется МОЖЕТ выполняться пользовательский агент без взаимодействия с пользователь, если и только если метод используется во втором запросе GET или ГОЛОВА.

302 Найдено

[..] Если код состояния 302 получен в ответ на запрос, другой чем GET или HEAD, пользовательский агент НЕ ДОЛЖЕН автоматически перенаправлять запрос, если он не может быть подтвержден пользователем, так как это может изменить условия, на которых был выдан запрос.

По сути это означает, что запрос после перенаправления POST и 302 не будет работать автоматически и потребует вмешательства пользователя, если за спецификацией HTTP / 1.1 следует буква. Не все клиенты Http следуют этой практике, на самом деле большинство браузеров этого не делают. Однако Apache Http Client (который является базовым Http-клиентом для HttpBuilder) соответствует спецификации . Существует проблема в отслеживателе ошибок Apache Http Client , которая содержит дополнительную информацию и возможное решение проблемы.

1 голос
/ 21 сентября 2016
void test_myPage_shouldRedirectToLogin() {
  def baseURI = "http://servername"
  def httpBuilder = new HTTPBuilder(baseURI)
  // Make sure that HttpClient doesn't perform a redirect
  def dontHandleRedirectStrategy = [
    getRedirect : { request, response, context -> null},
    isRedirected : { request, response, context -> false}
  ]
  httpBuilder.client.setRedirectStrategy(dontHandleRedirectStrategy as RedirectStrategy)

  // Execute a GET request and expect a redirect
  httpBuilder.request(Method.GET, ContentType.TEXT) {
    req ->
      uri.path = '/webapp/de/de/myPage'
      response.success = { response, reader ->
        assertThat response.statusLine.statusCode, is(302)
        assertThat response.headers['Location'].value, startsWith("${baseURI}/webapp/login")
      }
      response.failure = { response, reader ->
        fail("Expected redirect but received ${response.statusLine} \n ${reader}")
      }
    }
  }
Статус

302 наступает, потому что после действия над любой ссылкой перенаправленный URL не следует HttpBuilder, поэтому нам нужно добавить "RedirectStrategy" явно.

0 голосов
/ 04 июня 2010

Какие еще заголовки вы видите при обработке ответа 302?Если бы вы включили протоколирование HTTP-клиента , вы бы ожидали, что HttpClient обработает ответ 302 и автоматически запросит URL в заголовке Location.Что вы видите, когда обрабатываете этот URL?Это работает для любого URL?

Попробуйте http://www.sun.com (теперь он перенаправляется в Oracle). Мне просто интересно, не работает ли сервер, с которым вы работаете, что-то странное, например отправка 302 без заголовка Location.

...