【问题标题】:Setting a session cookie with the Java 11 HttpClient使用 Java 11 HttpClient 设置会话 cookie
【发布时间】:2021-11-04 09:43:14
【问题描述】:

我正在尝试使用 Java 11 HttpClient 获取页面的内容。由于该页面使用 OAuth,我想使用我的会话 cookie 进行身份验证。我目前使用以下代码,灵感来自this question:

public static void main(String[] args) throws IOException, InterruptedException {
  String year = args[0];
  String day = args[1];
  String session = System.getenv("AOCSESSION");
  System.out.println(session);
  
  HttpRequest req = HttpRequest.newBuilder()
      .uri(URI.create("https://adventofcode.com/"+year+"/day/"+day+"/input")).GET().build();
  CookieManager cookieManager = new CookieManager();
  HttpCookie cookie = new HttpCookie("session", session);
  cookieManager.getCookieStore().add(URI.create("https://adventofcode.com"), cookie);
  HttpClient client = HttpClient.newBuilder().cookieHandler(cookieManager).build();

  String body = client.send(req, BodyHandlers.ofString()).body();
  System.out.println(body);
}

但是,请求结果未经身份验证(响应:Puzzle inputs differ by user. Please log in to get your puzzle input.)。我已经尝试将其他字段添加到 cookie:

cookie.setDomain(".adventofcode.com");
cookie.setMaxAge(Instant.parse("2031-11-01T18:26:23.293Z").getEpochSecond());
cookie.setPath("/");
cookie.setHttpOnly(true);
cookie.setSecure(true);

但这并不能解决问题。

如何在请求中添加会话 cookie?

【问题讨论】:

    标签: java cookies httpclient java-11


    【解决方案1】:

    下面的解决方案是使用适当的 CookieManager 而不是对标头进行硬编码:

    public static void main(String[] args) throws Exception {
    
            CookieHandler.setDefault(new CookieManager());
    
            HttpCookie sessionCookie = new HttpCookie("session", "53616c7465645f5f9d467d3ae831ec1b1e7289ef45d256224786e1ed13");
            sessionCookie.setPath("/");
            sessionCookie.setVersion(0);
    
            ((CookieManager) CookieHandler.getDefault()).getCookieStore().add(new URI("https://adventofcode.com"),
                    sessionCookie);
    
            HttpClient client = HttpClient.newBuilder()
                    .cookieHandler(CookieHandler.getDefault())
                    .connectTimeout(Duration.ofSeconds(10))
                    .build();
    
            HttpRequest req = HttpRequest.newBuilder()
                    .uri(URI.create("https://adventofcode.com/2020/day/1/input"))
                    .GET().build();
    
    
            System.out.println(client.send(req, HttpResponse.BodyHandlers.ofString()).body());
    
        }
    

    sessionCookie.setPath("/"); 重要提示:Java 具有实际匹配请求 URI 路径和 Cookie 路径的 CookieFilter。

    sessionCookie.setVersion(0); 重要提示:此站点不喜欢版本 1(HttpCookie 中的默认值,符合 RFC 2965/2109)

    版本 0 符合原始的 Netscape cookie 并且 AdventOfCode 喜欢它。

    版本 0 和版本 1 的区别在于 Cookie 的外观:

    版本 0:

    INFO: HEADERS: HEADERS FRAME (stream=1)
        :authority: adventofcode.com
        :method: GET
        :path: /2020/day/1/input
        :scheme: https
        Cookie: session=53616c7465645f5f9d467....
        User-Agent: Java-http-client/11.0.7
    

    版本 1:

    INFO: HEADERS: HEADERS FRAME (stream=1)
        :authority: adventofcode.com
        :method: GET
        :path: /2020/day/1/input
        :scheme: https
        Cookie: $Version="1"
        Cookie: session="53616c7465645f5f9d467.....13";$Path="/"
        User-Agent: Java-http-client/11.0.7
    

    版本 1 会从网站抛出 500 服务器错误。

    为了帮助您调试 HttpClient 日志,请将以下内容添加到您的程序参数中:

    -Djdk.httpclient.HttpClient.log=errors,requests,headers,frames[:control:data:window:all],content,ssl,trace,channel,all
    

    日志:

    jdk.internal.net.http.HttpClientImpl$SelectorManager run
    INFO: CHANNEL: HttpClient-1-SelectorManager: starting
    nov. 04, 2021 3:35:39 EM jdk.internal.net.http.MultiExchange requestFilters
    INFO: MISC: Applying request filters
    nov. 04, 2021 3:35:39 EM jdk.internal.net.http.MultiExchange requestFilters
    INFO: MISC: Applying jdk.internal.net.http.AuthenticationFilter@49ec71f8
    nov. 04, 2021 3:35:39 EM jdk.internal.net.http.MultiExchange requestFilters
    INFO: MISC: Applying jdk.internal.net.http.RedirectFilter@8f4ea7c
    nov. 04, 2021 3:35:39 EM jdk.internal.net.http.MultiExchange requestFilters
    INFO: MISC: Applying jdk.internal.net.http.CookieFilter@436813f3
    nov. 04, 2021 3:35:39 EM jdk.internal.net.http.CookieFilter request
    INFO: MISC: Request: adding cookies for https://adventofcode.com/2020/day/1/input
    nov. 04, 2021 3:35:39 EM jdk.internal.net.http.MultiExchange requestFilters
    INFO: MISC: All filters applied
    nov. 04, 2021 3:35:39 EM jdk.internal.net.http.AbstractAsyncSSLConnection createSSLParameters
    INFO: SSL: AbstractAsyncSSLConnection: Setting application protocols: [h2, http/1.1]
    nov. 04, 2021 3:35:39 EM jdk.internal.net.http.AbstractAsyncSSLConnection <init>
    INFO: SSL: SSLParameters:
        cipher: TLS_AES_128_GCM_SHA256
        cipher: TLS_AES_256_GCM_SHA384
        cipher: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        cipher: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        cipher: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        cipher: TLS_RSA_WITH_AES_256_GCM_SHA384
        cipher: TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
        cipher: TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
        cipher: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
        cipher: TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
        cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        cipher: TLS_RSA_WITH_AES_128_GCM_SHA256
        cipher: TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
        cipher: TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
        cipher: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
        cipher: TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
        cipher: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
        cipher: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
        cipher: TLS_RSA_WITH_AES_256_CBC_SHA256
        cipher: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
        cipher: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
        cipher: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
        cipher: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
        cipher: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
        cipher: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
        cipher: TLS_RSA_WITH_AES_256_CBC_SHA
        cipher: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
        cipher: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
        cipher: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
        cipher: TLS_DHE_DSS_WITH_AES_256_CBC_SHA
        cipher: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
        cipher: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
        cipher: TLS_RSA_WITH_AES_128_CBC_SHA256
        cipher: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
        cipher: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
        cipher: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
        cipher: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
        cipher: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
        cipher: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
        cipher: TLS_RSA_WITH_AES_128_CBC_SHA
        cipher: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
        cipher: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
        cipher: TLS_DHE_RSA_WITH_AES_128_CBC_SHA
        cipher: TLS_DHE_DSS_WITH_AES_128_CBC_SHA
        cipher: TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        application protocol: h2
        application protocol: http/1.1
        protocol: TLSv1.3
        protocol: TLSv1.2
        endpointIdAlg: HTTPS
        server name: type=host_name (0), value=adventofcode.com
    
    nov. 04, 2021 3:35:39 EM jdk.internal.net.http.HttpClientImpl registerTimer
    INFO: MISC: Registering timer ConnectTimerEvent, TimeoutEvent[id=1, duration=PT10S, deadline=2021-11-04T14:35:49.817109800Z]
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.SocketTube$InternalReadPublisher$InternalReadSubscription handleSubscribeEvent
    INFO: CHANNEL: Start reading from java.nio.channels.SocketChannel[connected local=/100.120.31.175:57725 remote=adventofcode.com/54.166.48.177:443]
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.SocketTube$InternalWriteSubscriber startSubscription
    INFO: CHANNEL: Start requesting bytes for writing to channel: java.nio.channels.SocketChannel[connected local=/100.120.31.175:57725 remote=adventofcode.com/54.166.48.177:443]
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.HttpClientImpl cancelTimer
    INFO: MISC: Canceling timer ConnectTimerEvent, TimeoutEvent[id=1, duration=PT10S, deadline=2021-11-04T14:35:49.817109800Z]
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection <init>
    INFO: MISC: Connection send window size 65 535 
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection sendConnectionPreface
    INFO: MISC: /100.120.31.175:57725: start sending connection preface to adventofcode.com/54.166.48.177:443
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection sendConnectionPreface
    INFO: FRAME: OUT: SETTINGS: length=30, streamid=0, flags=0  Settings: HEADER_TABLE_SIZE=16384 ENABLE_PUSH=1 MAX_CONCURRENT_STREAMS=100 INITIAL_WINDOW_SIZE=16777216 MAX_FRAME_SIZE=16384 
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection sendConnectionPreface
    INFO: MISC: PREFACE_BYTES sent
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection sendConnectionPreface
    INFO: MISC: Settings Frame sent
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection sendConnectionPreface
    INFO: CHANNEL: Sending initial connection window update frame: 33 488 897 (33 554 432 - 65 535)
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection encodeFrame
    INFO: FRAME: OUT: WINDOW_UPDATE: length=4, streamid=0, flags=0  WindowUpdate: 33488897
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection sendConnectionPreface
    INFO: MISC: finished sending connection preface
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream sendHeadersAsync
    INFO: REQUEST: https://adventofcode.com/2020/day/1/input GET
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection encodeHeaders
    INFO: HEADERS: HEADERS FRAME (stream=1)
        :authority: adventofcode.com
        :method: GET
        :path: /2020/day/1/input
        :scheme: https
        Cookie: session=53616c7465645f5f9d467d3ae831
        User-Agent: Java-http-client/11.0.7
    
    
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection lambda$encodeFrames$9
    INFO: FRAME: OUT: HEADERS: length=126, streamid=1, flags=END_STREAM END_HEADERS 
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream getResponseAsync
    INFO: MISC: Response future (stream=1) is: jdk.internal.net.http.common.MinimalFuture@374f597e[Not completed] (id=43)
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection processFrame
    INFO: FRAME: IN: SETTINGS: length=18, streamid=0, flags=0  Settings: MAX_CONCURRENT_STREAMS=128 INITIAL_WINDOW_SIZE=65536 MAX_FRAME_SIZE=16777215 
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection encodeFrame
    INFO: FRAME: OUT: SETTINGS: length=0, streamid=0, flags=ACK  Settings: 
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection processFrame
    INFO: FRAME: IN: WINDOW_UPDATE: length=4, streamid=0, flags=0  WindowUpdate: 2147418112
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection processFrame
    INFO: FRAME: IN: SETTINGS: length=0, streamid=0, flags=ACK  Settings: 
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection processFrame
    INFO: FRAME: IN: HEADERS: length=118, streamid=1, flags=END_HEADERS 
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream$HeadersConsumer onDecoded
    INFO: MISC: RECEIVED HEADER (streamid=1): :status: 200
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream$HeadersConsumer onDecoded
    INFO: MISC: RECEIVED HEADER (streamid=1): date: Thu, 04 Nov 2021 14:35:40 GMT
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream$HeadersConsumer onDecoded
    INFO: MISC: RECEIVED HEADER (streamid=1): content-type: text/plain
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream$HeadersConsumer onDecoded
    INFO: MISC: RECEIVED HEADER (streamid=1): content-length: 990
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream$HeadersConsumer onDecoded
    INFO: MISC: RECEIVED HEADER (streamid=1): server: Apache
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream$HeadersConsumer onDecoded
    INFO: MISC: RECEIVED HEADER (streamid=1): server-ip: 172.31.16.87
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream$HeadersConsumer onDecoded
    INFO: MISC: RECEIVED HEADER (streamid=1): vary: Accept-Encoding
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream$HeadersConsumer onDecoded
    INFO: MISC: RECEIVED HEADER (streamid=1): strict-transport-security: max-age=300
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream incoming
    INFO: MISC: handling response (streamid=1)
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream handleResponse
    INFO: HEADERS: RESPONSE HEADERS:
        :status: 200
        content-length: 990
        content-type: text/plain
        date: Thu, 04 Nov 2021 14:35:40 GMT
        server: Apache
        server-ip: 172.31.16.87
        strict-transport-security: max-age=300
        vary: Accept-Encoding
    
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream completeResponse
    INFO: MISC: Completing response (streamid=1): jdk.internal.net.http.common.MinimalFuture@113d2103[Not completed, 1 dependents] (id=42)
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Exchange lambda$wrapForLog$11
    INFO: RESPONSE: (GET https://adventofcode.com/2020/day/1/input) 200 HTTP_2 Local port:  57725
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.MultiExchange responseFilters
    INFO: MISC: Applying response filters
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.MultiExchange responseFilters
    INFO: MISC: Applying jdk.internal.net.http.CookieFilter@436813f3
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.CookieFilter response
    INFO: MISC: Response: processing cookies for https://adventofcode.com/2020/day/1/input
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.CookieFilter response
    INFO: MISC: Response: parsing cookies from {:status=[200], content-length=[990], content-type=[text/plain], date=[Thu, 04 Nov 2021 14:35:40 GMT], server=[Apache], server-ip=[172.31.16.87], strict-transport-security=[max-age=300], vary=[Accept-Encoding]}
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.MultiExchange responseFilters
    INFO: MISC: Applying jdk.internal.net.http.RedirectFilter@8f4ea7c
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.MultiExchange responseFilters
    INFO: MISC: Applying jdk.internal.net.http.AuthenticationFilter@49ec71f8
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.MultiExchange responseFilters
    INFO: MISC: All filters applied
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream readBodyAsync
    INFO: MISC: Reading body on stream 1
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection processFrame
    INFO: FRAME: IN: DATA: length=990, streamid=1, flags=0 
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream schedule
    INFO: MISC: responseSubscriber.onNext 990
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Http2Connection processFrame
    INFO: FRAME: IN: DATA: length=0, streamid=1, flags=END_STREAM 
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream schedule
    INFO: MISC: responseSubscriber.onComplete
    1337
    1906
    2007
    1939
    818
    1556
    2005
    1722
    1484
    1381
    1682
    1253
    1967
    1718
    2002
    1398
    1439
    1689
    1746
    1979
    1985
    1387
    1509
    1566
    1276
    1625
    1853
    882
    1750
    1390
    1731
    1555
    1860
    1675
    1457
    1554
    1506
    1639
    1543
    1849
    1062
    1869
    1769
    1858
    1916
    1504
    1747
    1925
    1275
    1273
    1383
    1816
    1814
    1481
    1649
    1993
    1759
    1949
    1499
    1374
    1613
    1424
    783
    1765
    1576
    1933
    1270
    1844
    1856
    1634
    1261
    1293
    1741
    668
    1573
    1599
    1877
    1474
    1918
    476
    1515
    1029
    202
    1589
    1867
    1503
    1582
    1605
    1557
    587
    1462
    1955
    1806
    1834
    1739
    1343
    1594
    1622
    1972
    1527
    1798
    1719
    1866
    134
    2000
    1992
    1966
    1909
    1340
    1621
    1921
    1256
    1365
    1314
    1748
    1963
    1379
    1627
    1848
    1977
    1917
    1826
    1716
    1631
    1404
    1936
    1677
    1661
    1986
    1997
    1603
    1932
    1780
    1902
    2009
    1257
    1871
    1362
    1662
    1507
    1255
    1539
    1962
    1886
    1513
    1264
    1873
    1700
    807
    1426
    1697
    1698
    1519
    1791
    1240
    1542
    1497
    1761
    1640
    1502
    1770
    1437
    1333
    1805
    1591
    1644
    1420
    1809
    1587
    1421
    1540
    1942
    470
    1940
    1831
    1247
    1632
    1975
    1774
    1919
    1829
    1944
    1553
    1361
    1483
    1995
    1868
    1601
    1552
    1854
    1490
    1855
    1987
    1538
    1389
    1454
    1427
    1686
    1456
    1974
    
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream close
    INFO: MISC: Closing stream 1
    nov. 04, 2021 3:35:40 EM jdk.internal.net.http.Stream close
    INFO: MISC: Stream 1 closed
    
    Process finished with exit code 0
    

    ps:弄清楚这件事真是太有趣了:D

    【讨论】:

    • 对我来说,这仍然不能通过网站验证我的身份。尝试使用我自己的有效会话密钥访问https://adventofcode.com/2020/day/1/input 时,我仍然得到Puzzle inputs differ by user. Please log in to get your puzzle input.。还是我错过了身份验证可能需要的东西?
    • @SimonBaars 我修复了一切以使用 CookieManager 而不是对 Header 进行硬编码。请立即尝试。我在本地对其进行了测试,它对 day/1/input 有效
    • 成功了!非常感谢!
    • 真的很高兴它帮助了@SimonBaars
    【解决方案2】:

    Java 11 HttpClient 内置了对 Session-Cookie 的支持。如果你像这样创建一个客户端:

    var client = HttpClient.newBuilder()
                    .cookieHandler(new CookieManager())
                    .version(HttpClient.Version.HTTP_2)
                    .build();
    

    然后客户端会自动保存第一次授权请求中的所有cookies。此客户端发出的任何后续请求都将设置 cookie。

    如果您想在发送初始请求之前为 cookie 设置一些值,请尝试:

    var cookieManager = new cookieManager();
    cookieManager.getCookieStore().add(someHostURI, someSessionCookie);
    
    //Now this cookie can be used to create the client:
    var client = HttpClient.newBuilder()
                    .cookieHandler(cookieManager)
                    .version(HttpClient.Version.HTTP_2)
                    .build();
    

    更详细的解释,请查看this article

    【讨论】:

    • 如果您需要在发出初始请求之前设置 cookie,那么这不是一个合适的解决方案。
    • 你能解释一下原因吗?我的意思是CookieManager 可以由var cookie = new CookieManager() 初始化,然后将所需的值添加到这个cookie,最后在制作client 时使用这个cookie,就像上面的代码一样。很想知道任何更好的想法。
    猜你喜欢
    • 2013-02-07
    • 2013-01-27
    • 2019-11-18
    • 1970-01-01
    • 2013-11-19
    • 2015-12-27
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    相关资源
    最近更新 更多