Exception Groovy HttpBuilder与Cookie的问题

Exception Groovy HttpBuilder与Cookie的问题,exception,cookies,groovy,httpresponse,httpbuilder,Exception,Cookies,Groovy,Httpresponse,Httpbuilder,我需要编写一个web客户端,它可以点击传统web应用程序,登录到它,从/widget页面中提取一些信息,并根据该页面的HTML进行一些工作。我选择使用Groovy/解决方案,原因超出了这个问题的范围 唯一的缺点(据我所知)是HttpBuilder不支持在请求之间保留cookie。这是一个主要问题,因为(Java)web应用程序使用JSESSIONIDcookies来确定用户是否登录、是否拥有权限等 因此,首先,如果我上面的断言不正确,并且HttpBuilder确实支持跨请求保留cookie,请纠

我需要编写一个web客户端,它可以点击传统web应用程序,登录到它,从
/widget
页面中提取一些信息,并根据该页面的HTML进行一些工作。我选择使用Groovy/解决方案,原因超出了这个问题的范围

唯一的缺点(据我所知)是HttpBuilder不支持在请求之间保留cookie。这是一个主要问题,因为(Java)web应用程序使用
JSESSIONID
cookies来确定用户是否登录、是否拥有权限等

因此,首先,如果我上面的断言不正确,并且HttpBuilder确实支持跨请求保留cookie,请纠正我,也许这里的答案是一个解决方案,它向我展示了如何利用HttpBuilder的这一部分。在这种情况下,我下面的所有代码都是没有意义的

假设我是正确的,而这不是由HttpBuilder处理的,我发现由于某种原因我无法工作,因此我提出了这个问题

我对该代码的修改(见上面的链接)如下:

TaskAutomator.groovy
====================
package com.me.myapp.tasker

import groovyx.net.http.ContentType
import groovyx.net.http.Method

class TaskAutomator {
    static void main(String[] args) {
        TaskAutomator tasker = new TaskAutomator()
        String result = tasker.doWork("http://myapp.example.com")

        println result
    }

    String doWork(String baseUrl) {
        CookieRetainingHttpBuilder cookiedBuilder = new CookieRetainingHttpBuilder(baseUrl)
        Map logins = [username: 'user', password: '12345']

        // Go to the main page where we will get back the HTML for a login screen.
        // We don't really care about the response here, so long as its HTTP 200.
        cookiedBuilder.request(Method.GET, ContentType.HTML, "", null)

        // Log in to the app, where, on success, we will get back the HTML for a the
        // "Main Menu" screen users see when they log in. We don't really care about
        // the response here, so long as its HTTP 200.
        cookiedBuilder.request(Method.POST, ContentType.HTML, "/auth", logins)

        // Finally, now that our JSESSIONID cookies is authenticated, go to the widget page
        // which is what we actually care about interacting with.
        def response = cookiedBuilder.request(Method.GET, ContentType.HTML, "/widget", null)

        // Test to make sure the response is what I think it is.
        print response

        String result

        // TODO: Now actually do work based off the response.

        result
    }
}

CookieRetainingHttpBuilder
==========================
package com.me.myapp.tasker

import groovyx.net.http.ContentType
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.HttpResponseDecorator
import groovyx.net.http.Method

class CookieRetainingHttpBuilder {
    private String baseUrl
    private HTTPBuilder httpBuilder
    private List<String> cookies

    CookieRetainingHttpBuilder(String baseUrl) {
        this.baseUrl = baseUrl
        this.httpBuilder = initializeHttpBuilder()
        this.cookies = []
    }

    public def request(Method method, ContentType contentType, String url, Map<String, Serializable> params) {
        httpBuilder.request(method, contentType) { request ->
            uri.path = url
            uri.query = params
            headers['Cookie'] = cookies.join(';')
        }
    }

    private HTTPBuilder initializeHttpBuilder() {
        def httpBuilder = new HTTPBuilder(baseUrl)

        httpBuilder.handler.success = { HttpResponseDecorator resp, reader ->
            resp.getHeaders('Set-Cookie').each {
                String cookie = it.value.split(';')[0]
                cookies.add(cookie)
            }

            reader
        }

        httpBuilder
    }
}
CookieRetainingHttpBuilder:20
这一行来自
请求

httpBuilder.request(method, contentType) { request ->
有人知道我为什么会这样吗?此外,我想确认我在
TaskAutomater#doWork(…)
方法中的方法/策略是我使用的
CookiiereTainingHttpBuilder
“正确”
,意思是我:

  • 转到主页面/登录页
  • 发布登录凭据并登录
  • 转到小部件页面

  • 或者有没有其他更好/更高效的方法来使用HttpBuilder(请记住,
    CookiiereTainingHttpBuilder
    毕竟只是HttpBuilder的包装器)。

    我认为,错误可能是由于缺少导入,或者可能是因为HttpBuilder的旧版本。查看HttpBuilder.Class,我看到了以下内容,这为我的建议提供了依据:

    protected java.lang.Object parseResponse(org.apache.http.HttpResponse resp, java.lang.Object contentType) throws groovyx.net.http.HttpResponseException { /* compiled code */ }
    
    我相当确定您可以在httpBuilder设置中使用
    头文件。'Set-Cookie
    。语法与您的不同,但变化很小且简单,这是我在使用HttpBuilder时使用的基本方法

    @Grab(group = 'org.codehaus.groovy.modules.http-builder', module = 'http-builder', version = '0.7)
        import groovyx.net.http.HTTPBuilder
        import org.apache.http.HttpException
        import static groovyx.net.http.ContentType.TEXT
        import static groovyx.net.http.Method.GET
    
        def http = new HTTPBuilder(urlToHit)
        http.request(urlToHit, GET, TEXT) { req ->
    
        headers.'User-Agent' = ${userAgent}
        headers.'Set-Cookie' = "${myCookie}"
    
        response.success = { resp, reader ->
            html = reader.getText()
        }
    
        response.failure = { resp, reader ->
            System.err.println "Failure response: ${resp.status}"
            throw new HttpException()        
        }        
    }
    
    另外需要注意的是,您没有故障处理。我不知道这是否会引起一个例外,但它可能值得研究

    编辑 正如建议的那样,我正在合并我的答案(谢谢你让我知道……我不确定什么是正确的礼仪)

    这是我想到的。我尽了最大努力重用你发布的代码。我尽我所能发表评论。如果你有任何问题,请告诉我

    @Grab(group = 'org.codehaus.groovy.modules.http-builder', module = 'http-builder', version = '0.7')
    import static groovyx.net.http.ContentType.HTML
    import static groovyx.net.http.Method.POST
    import static groovyx.net.http.Method.GET
    import groovyx.net.http.ContentType
    import groovyx.net.http.HTTPBuilder
    import groovyx.net.http.URIBuilder
    import groovyx.net.http.Method
    import org.apache.http.HttpException
    
    /**
     * This class defines the methods used for getting and using cookies
     * @param baseUrl The URL we will use to make HTTP requests. In this example, it is https://www.pinterest.com
     */
    
    class CookieRetainingHttpBuilder {
    
        String baseUrl
    
        /**
         * This method makes an http request and adds cookies to the array list for later use
         * @param method The method used to make the http request. In this example, we use GET and POST
         * @param contentType The content type we are requesting. In this example, we are getting HTML
         * @param url The URI path for the appropriate page. For example, /login/ is for the login page
         * @param params The URI query used for setting parameters. In this example, we are using login credentials
         */
    
        public request (Method method, ContentType contentType, String url, Map<String, Serializable> params) {
    
            List<String> cookies = new ArrayList<>()
    
            def http = new HTTPBuilder(baseUrl)
    
            http.request(baseUrl, method, contentType) { req ->
    
                URIBuilder uriBuilder = new URIBuilder(baseUrl)
                uriBuilder.query = params
                uriBuilder.path = url
    
                headers.'Accept' = HTML
                headers.'User-Agent' = "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36"
                headers.'Set-Cookie' = cookies.join(";")
    
                response.success = { resp, reader ->
    
                    resp.getHeaders('Set-Cookie').each {
                        def cookie = it.value.split(";").toString()
                        cookies.add(cookie)
                    }
    
                    return reader
    
                }
    
                response.failure = { resp, reader ->
                    System.err.println "Failure response: ${resp.status}"
                    throw new HttpException()
                }
    
            }
    
        }
    
    }
    
    /**
     * This class contains the method to make HTTP requests in the proper sequence
     * @param base The base URL
     * @param user The username of the site being logged in to
     * @param pass The password for the username
     */
    
    class TaskAutomator {
    
        private static String base = "http://myapp.example.com"
        private static String user = "thisIsMyUser"
        private static String pass = "thisIsMyPassword"
    
        /**
         * This method contains the functions in proper order to set cookies and login to a site
         * @return response Returns the HTML from the final GET request
         */
    
        static String doWork () {
    
            CookieHandler.setDefault(new CookieManager());
    
            CookieRetainingHttpBuilder cookiedBuilder = new CookieRetainingHttpBuilder(baseUrl: base)
            Map logins = [username: user, password: pass]
    
            // Go to the main page where we will get back the HTML for a login screen.
            // We don't really care about the response here, so long as its HTTP 200.
            cookiedBuilder.request(GET, HTML, "", null)
    
            // Log in to the app, where, on success, we will get back the HTML for a the
            // "Main Menu" screen users see when they log in. We don't really care about
            // the response here, so long as its HTTP 200.
            cookiedBuilder.request(POST, HTML, "/login/", logins)
    
            // Finally, now that our JSESSIONID cookies is authenticated, go to the widget page
            // which is what we actually care about interacting with.
            def response = cookiedBuilder.request(GET, HTML, "/", null)
    
            // Test to make sure the response is what I think it is.
            return response
    
            // TODO: Now actually do work based off the response.
    
        }
    
    }
    
    TaskAutomator tasker = new TaskAutomator()
    String result = tasker.doWork()
    println result
    
    @Grab(组='org.codehaus.groovy.modules.httpbuilder',模块='httpbuilder',版本='0.7')
    导入静态groovyx.net.http.ContentType.HTML
    导入静态groovyx.net.http.Method.POST
    导入静态groovyx.net.http.Method.GET
    导入groovyx.net.http.ContentType
    导入groovyx.net.http.HTTPBuilder
    导入groovyx.net.http.URIBuilder
    导入groovyx.net.http.Method
    导入org.apache.http.HttpException
    /**
    *此类定义用于获取和使用cookie的方法
    *@param baseUrl我们将用于发出HTTP请求的URL。在本例中,它是https://www.pinterest.com
    */
    类CookiiereTainingHttpBuilder{
    字符串baseUrl
    /**
    *此方法发出http请求并将Cookie添加到阵列列表中以供以后使用
    *@param method用于发出http请求的方法。在本例中,我们使用GET和POST
    *@param contentType我们请求的内容类型。在本例中,我们得到的是HTML
    *@param url相应页面的URI路径。例如,/login/表示登录页面
    *@param params用于设置参数的URI查询。在本例中,我们使用的是登录凭据
    */
    公共请求(方法、ContentType、字符串url、映射参数){
    列表cookies=newarraylist()
    def http=新的HTTPBuilder(baseUrl)
    请求(baseUrl、方法、contentType){req->
    URIBuilder URIBuilder=新的URIBuilder(baseUrl)
    uriBuilder.query=params
    uriBuilder.path=url
    headers.'Accept'=HTML
    headers.'User-Agent'=“Mozilla/5.0(Windows NT 6.3;Win64;x64)AppleWebKit/537.36(KHTML,如Gecko)Chrome/37.0.2049.0 Safari/537.36”
    headers.'Set-Cookie'=cookies.join(“;”)
    response.success={resp,reader->
    相应的getHeaders('Set-Cookie')。每个{
    def cookie=it.value.split(“;”).toString()
    cookies.add(cookie)
    }
    回传读取器
    }
    response.failure={resp,reader->
    System.err.println“故障响应:${resp.status}”
    抛出新的HttpException()
    }
    }
    }
    }
    /**
    *此类包含按正确顺序发出HTTP请求的方法
    *@param base基本URL
    *@param user登录到的站点的用户名
    *@param传递用户名的密码
    */
    类任务自动机{
    私有静态字符串基=”http://myapp.example.com"
    私有静态字符串user=“thismyuser”
    私有静态字符串pass=“thismypassword”
    /**
    *此方法包含按正确顺序设置cookie和登录站点的函数
    *@return response返回最终GET请求的HTML
    */
    静态字符串定位销(){
    setDefault(新的CookieManager());
    CookiiereTainingHttpBuilder cookiedBuilder=新CookiiereTainingHttpBuilder(baseUrl:base)
    地图登录=[用户名:用户,密码:通过]
    //转到主页,我们将返回登录屏幕的HTML。
    //我们并不真正关心这里的响应,只要它是HTTP200。
    请求(GET,HTML,“,null)
    //登录到该应用程序,成功后,我们将返回HTML以供下载
    //“主菜单”屏幕u
    
    @Grab(group = 'org.codehaus.groovy.modules.http-builder', module = 'http-builder', version = '0.7')
    import static groovyx.net.http.ContentType.HTML
    import static groovyx.net.http.Method.POST
    import static groovyx.net.http.Method.GET
    import groovyx.net.http.ContentType
    import groovyx.net.http.HTTPBuilder
    import groovyx.net.http.URIBuilder
    import groovyx.net.http.Method
    import org.apache.http.HttpException
    
    /**
     * This class defines the methods used for getting and using cookies
     * @param baseUrl The URL we will use to make HTTP requests. In this example, it is https://www.pinterest.com
     */
    
    class CookieRetainingHttpBuilder {
    
        String baseUrl
    
        /**
         * This method makes an http request and adds cookies to the array list for later use
         * @param method The method used to make the http request. In this example, we use GET and POST
         * @param contentType The content type we are requesting. In this example, we are getting HTML
         * @param url The URI path for the appropriate page. For example, /login/ is for the login page
         * @param params The URI query used for setting parameters. In this example, we are using login credentials
         */
    
        public request (Method method, ContentType contentType, String url, Map<String, Serializable> params) {
    
            List<String> cookies = new ArrayList<>()
    
            def http = new HTTPBuilder(baseUrl)
    
            http.request(baseUrl, method, contentType) { req ->
    
                URIBuilder uriBuilder = new URIBuilder(baseUrl)
                uriBuilder.query = params
                uriBuilder.path = url
    
                headers.'Accept' = HTML
                headers.'User-Agent' = "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36"
                headers.'Set-Cookie' = cookies.join(";")
    
                response.success = { resp, reader ->
    
                    resp.getHeaders('Set-Cookie').each {
                        def cookie = it.value.split(";").toString()
                        cookies.add(cookie)
                    }
    
                    return reader
    
                }
    
                response.failure = { resp, reader ->
                    System.err.println "Failure response: ${resp.status}"
                    throw new HttpException()
                }
    
            }
    
        }
    
    }
    
    /**
     * This class contains the method to make HTTP requests in the proper sequence
     * @param base The base URL
     * @param user The username of the site being logged in to
     * @param pass The password for the username
     */
    
    class TaskAutomator {
    
        private static String base = "http://myapp.example.com"
        private static String user = "thisIsMyUser"
        private static String pass = "thisIsMyPassword"
    
        /**
         * This method contains the functions in proper order to set cookies and login to a site
         * @return response Returns the HTML from the final GET request
         */
    
        static String doWork () {
    
            CookieHandler.setDefault(new CookieManager());
    
            CookieRetainingHttpBuilder cookiedBuilder = new CookieRetainingHttpBuilder(baseUrl: base)
            Map logins = [username: user, password: pass]
    
            // Go to the main page where we will get back the HTML for a login screen.
            // We don't really care about the response here, so long as its HTTP 200.
            cookiedBuilder.request(GET, HTML, "", null)
    
            // Log in to the app, where, on success, we will get back the HTML for a the
            // "Main Menu" screen users see when they log in. We don't really care about
            // the response here, so long as its HTTP 200.
            cookiedBuilder.request(POST, HTML, "/login/", logins)
    
            // Finally, now that our JSESSIONID cookies is authenticated, go to the widget page
            // which is what we actually care about interacting with.
            def response = cookiedBuilder.request(GET, HTML, "/", null)
    
            // Test to make sure the response is what I think it is.
            return response
    
            // TODO: Now actually do work based off the response.
    
        }
    
    }
    
    TaskAutomator tasker = new TaskAutomator()
    String result = tasker.doWork()
    println result