groovy/grails - Невозможно заставить HTTPBuilder работать с URL (предоставляется Paypal)

ПОЖАЛУЙСТА, ОБРАТИТЕ ВНИМАНИЕ: с кодом / информацией ниже, эта проблема может быть воспроизведена в течение 2-3 минут.

ПРЕДПОСЫЛКИ: Во-первых, я не нашел плагин, который помог бы с расширенным интерфейсом Paypal (их решение среднего уровня между "Standard" и "Pro"), но если мне не нужно катить свой собственный HTTPBuilder и другой код интерфейса Я определенно за это.

Теперь я могу сузить проблему HTTPBuilder, чтобы заставить команду curl работать из командной строки DOS, используя правильный URL; Я просто не могу заставить его работать с HTTPBuilder от Groovy.

Итак, что работает, что можно легко попробовать это:

 c:\groovy\ex>curl https://pilot-payflowpro.paypal.com
 curl: (52) Empty reply from server

Но все же ответ. Или реальный URL для возврата SECURETOKEN от Paypal больше похож на:

c:\groovy\ex>curl https://pilot-payflowpro.paypal.com -kd "PARTNER=PayPal&VENDOR=ROAdvanced&USER=ROAdvanced&PWD=joespizza1&TRXTYPE=S&MODE=TEST&AMT=40&CREATESECURETOKEN=Y&SECURETOKENID=12528208de1413abc3d60c86233"
RESULT=0&SECURETOKEN=15XTWEZtFlkeNqtWCBZHSTgcs&SECURETOKENID=12528208de1413abc3d60c86233&RESPMSG=Approved

OR you'll get a result like the following, but either result is good, since Paypal is sending a response in both cases!

RESULT=7&SECURETOKENID=12528208de1413abc3d60c86233&RESPMSG=Field format error: Secure Token Id already been used

Хорошо, мой код выглядит следующим образом. Пожалуйста, запишите мои ошибки кода с немедленной ошибкой, хотя (я думаю) я использую задержку:

 Class: org.apache.http.NoHttpResponseException
 Message: The target server failed to respond

Это происходит вокруг

  http.request(GET, ContentType.ANY) {

Обратите внимание, что даже при установке задержек на HTTPBuilder, эта ошибка происходит НЕМЕДЛЕННО. Я добавлю весь код / ​​трассировку стека в конце. Также обратите внимание, что если вы добавите защиту SSL, как описано в этом посте, результатом будет та же ошибка, то есть сервер не ответит.


Итак, код:

 package apps

 import grails.converters.*
 import org.codehaus.groovy.grails.web.json.*; // package containing JSONObject,  JSONArray,...
 import groovyx.net.http.*
 import static groovyx.net.http.ContentType.*
 import static groovyx.net.http.Method.*

 import javax.net.ssl.X509TrustManager
 import javax.net.ssl.SSLContext
 import java.security.cert.X509Certificate
 import javax.net.ssl.TrustManager
 import java.security.SecureRandom
 import org.apache.http.conn.ssl.SSLSocketFactory
 import org.apache.http.conn.scheme.Scheme
 import org.apache.http.conn.scheme.SchemeRegistry
 import org.apache.http.conn.ssl.X509HostnameVerifier


class PaypalController {

   def index() {
    def paypalUrl = "https://pilot-payflowpro.paypal.com?PARTNER=PayPal&VENDOR=ROAdvanced&USER=ROAdvanced&PWD=joespizza1&TRXTYPE=S&MODE=TEST&AMT=40&CREATESECURETOKEN=Y&SECURETOKENID=12528208de1413abc3d60c86cdr87"
    //def paypalUrl = "https://pilot-payflowpro.paypal.com"
    println "Making new http Builder with paypalURL ..."
    def http = new HTTPBuilder(paypalUrl)

    println "Now setting timeouts ..."
    http.getClient().getParams().setParameter("http.connection.timeout", new Integer(12000))
    http.getClient().getParams().setParameter("http.socket.timeout", new Integer(30000))

    //=== SSL UNSECURE CERTIFICATE ===

    println "Don't know if needed, but since timeouts don't work to get a response, setting up SSL bypass"

    def sslContext = SSLContext.getInstance("SSL")
    sslContext.init(null, [new X509TrustManager() {
        public X509Certificate[] getAcceptedIssuers() {null }

        public void checkClientTrusted(X509Certificate[] certs, String authType) { }

        public void checkServerTrusted(X509Certificate[] certs, String authType) { }
    }] as TrustManager[], new SecureRandom())

    //SSLSocketFactory sf = new org.apache.http.conn.ssl.SSLSocketFactory(sslContext, org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)

    SSLSocketFactory sf = new org.apache.http.conn.ssl.SSLSocketFactory(sslContext)
    sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
    def httpsScheme = new Scheme("https", sf, 443)
    http.client.connectionManager.schemeRegistry.register(httpsScheme)


    println "Now doing the get"
    // perform a GET request, expecting JSON response data
    try {
        http.request(GET, ContentType.ANY) {
            println "Issued the get waiting for the response"
            // Sleeping doesn't help
            //Thread.sleep(2000)
            // println "Done sleeping, looking to process success"

            response.success = { resp, any ->
                println "in success code"
                println "My response handler got response: ${resp.statusLine}"
                println "Response length: ${resp.headers.'Content-Length'}"
                assert resp.status == 200

                def result = any.results;

                render(view: "index", model: [message: "Request sent", result: result]);
            }
            println "past the success code"
        }//end of request
    } catch (groovyx.net.http.HttpResponseException ex) {
        println "Had response exception ...."
        ex.printStackTrace()
        return null
    } catch (java.net.ConnectException ex) {
        println "Had connection exception ...."
        ex.printStackTrace()
        return null
    }

    finally {
        http.shutdown()
    }
}//end of method


def fail() {}

def success() {}

}

------------------- Запуск этого кода я получаю (без задержек нигде) -------------------- -----

  Making new http Builder with paypalURL ...
  Now setting timeouts ...
  Don't know if needed, but since timeouts don't work to get a response, setting up SSL bypass
  Now doing the get
  Issued the get waiting for the response
  past the success code
  | Error 2013-07-19 13:27:32,301 [http-bio-8080-exec-10] ERROR errors.GrailsExceptionResolver  - NoHttpResponseException occurred when processing request: [GET] /apps/paypal/index
  The target server failed to respond. Stacktrace follows:
  Message: The target server failed to respond
  Line | Method
  ->> 101 | parseHead             in org.apache.http.impl.conn.DefaultResponseParser
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
  |   210 | parse                 in org.apache.http.impl.io.AbstractMessageParser
  |   271 | receiveResponseHeader in org.apache.http.impl.AbstractHttpClientConnection
  |   233 | receiveResponseHeader in org.apache.http.impl.conn.DefaultClientConnection
  |   209 | receiveResponseHeader in org.apache.http.impl.conn.AbstractClientConnAdapter
  |   292 | doReceiveResponse     in org.apache.http.protocol.HttpRequestExecutor
  |   126 | execute . . . . . . . in     ''
  |   483 | execute               in org.apache.http.impl.client.DefaultRequestDirector
  |   641 | execute . . . . . . . in org.apache.http.impl.client.AbstractHttpClient
  |   576 | execute               in     ''
  |   477 | doRequest . . . . . . in groovyx.net.http.HTTPBuilder
  |   441 | doRequest             in     ''
  |   390 | request . . . . . . . in     ''
  |    56 | index                 in apps.PaypalController$$EOC4TiIi
  |   195 | doFilter . . . . . .  in grails.plugin.cache.web.filter.PageFragmentCachingFilter
  |    63 | doFilter              in grails.plugin.cache.web.filter.AbstractFilter
  |   886 | runTask . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
  |   908 | run                   in     ''
  ^   619 | run . . . . . . . . . in java.lang.Thread

----------------- Мне нужно было добавить следующее в BuildConfig.groovy, чтобы получить эту работу ----

...

dependencies {
    // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes e.g.
    compile('org.codehaus.groovy.modules.http-builder:http-builder:0.5.2') {
            excludes "commons-logging", "xml-apis", "groovy"
    }

---------------------------- Обновление кода по ответу Ральфа -------------

Код, который должен соответствовать документации Groovy HTTPBuilder:

Обратите внимание, что это производит ту же ошибку в той же строке, т.е.

org.apache.http.NoHttpResponseException, Message: The target server failed to respond

в строке: http.request(POST) {

class PaypalController {

def index() {
    def paypalUrl = "https://pilot-payflowpro.paypal.com?PARTNER=PayPal&VENDOR=ROAdvanced&USER=ROAdvanced&PWD=joespizza1&TRXTYPE=S&MODE=TEST&AMT=40&CREATESECURETOKEN=Y&SECURETOKENID=12528208de1413abc3d60c86cdr87"

    println "Making new http Builder with paypalURL ..."
    def http = new HTTPBuilder(paypalUrl)

    println "Now doing the post as a request per example"
    // perform a GET request, expecting JSON response data
    try {
        http.request(POST) {
            body =  [ status : 'update!' , source : 'httpbuilder' ]
            requestContentType = ContentType.URLENC
            println "Issued the post waiting for the response"

            response.success = { resp ->
                println "in success code"
                println "My response handler got response: ${resp.statusLine}"
                println "Response length: ${resp.headers.'Content-Length'}"
                assert resp.status == 200

                //def result = any.results;

                render(view: "index", model: [message: "Request sent", result: result]);
            }
            println "past the success code"
        }//end of request
    } catch (groovyx.net.http.HttpResponseException ex) {
        println "Had response exception ...."
        ex.printStackTrace()
        return null
    } catch (java.net.ConnectException ex) {
        println "Had connection exception ...."
        ex.printStackTrace()
        return null
    }

    finally {
        http.shutdown()
    }
}//end of method

def fail() {}
def success() {}
}

2 ответа

Решение

Нашел вашу проблему: curl -d это не GET, а POST-запрос. Если вы пропустите опцию -d в своем запросе curl, вы столкнетесь с той же проблемой, что и с вашим Groovy...

Попробуйте этот отличный код:

def url = new URL("https://pilot-payflowpro.paypal.com")
def body= "PARTNER=PayPal&VENDOR=ROAdvanced&USER=ROAdvanced&PWD=..."
def connection = url.openConnection()
connection.setRequestMethod("POST")
connection.doOutput = true

def writer = new OutputStreamWriter(connection.outputStream)
writer.write(body)
writer.flush()
writer.close()
connection.connect()
def response = connection.content.text

Вот код http-builder с правильным телом:

    @Grab(group='org.codehaus.groovy.modules.http-builder',module='http-builder', version='0.5.0')
     import grails.converters.*
     import org.codehaus.groovy.grails.web.json.*; // package containing JSONObject,  JSONArray,...
     import groovyx.net.http.*
     import static groovyx.net.http.ContentType.*
     import static groovyx.net.http.Method.*

    class PaypalController {

    def index() {
        def paypalUrl = "https://pilot-payflowpro.paypal.com"

        println "Making new http Builder with paypalURL ..."
        def http = new HTTPBuilder(paypalUrl)

        println "Now doing the post as a request per example"
        // perform a GET request, expecting JSON response data
        try {
            http.request(POST,JSON) {
                body =  [ 
                    PARTNER:'PayPal',
                    VENDOR:'yyy',
                    USER:'yyy',
                    PWD:'xxx',
                    TRXTYPE:'S',
                    MODE:'TEST',
                    AMT:'40',
                    CREATESECURETOKEN:'Y',
                    SECURETOKENID:'xxx'
                ]
                requestContentType = ContentType.URLENC
                println "Issued the post waiting for the response"

                response.success = { resp ->
                    println "in success code"
                    println "My response handler got response: ${resp.statusLine}"
                    println "Response length: ${resp.headers.'Content-Length'}"
                    assert resp.status == 200

                    //def result = any.results;

                    render(view: "index", model: [message: "Request sent", result: result]);
                }
                println "past the success code"
            }//end of request
        } catch (groovyx.net.http.HttpResponseException ex) {
            println "Had response exception ...."
            ex.printStackTrace()
            return null
        } catch (java.net.ConnectException ex) {
            println "Had connection exception ...."
            ex.printStackTrace()
            return null
        }

        finally {
            http.shutdown()
        }
    }//end of method
    }
    def controller = new PaypalController()
    controller.index()

@Grab оператор позволяет вам выполнить это в groovyConsole...

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