如何使用 Java 在 Http Get 方法中设置 Cookie

Posted

技术标签:

【中文标题】如何使用 Java 在 Http Get 方法中设置 Cookie【英文标题】:How to set Cookies at Http Get method using Java 【发布时间】:2011-03-16 00:23:27 【问题描述】:

我想使用 cookie 进行手动 GET 以下载和解析网页。我需要提取安全令牌,以便在论坛上发帖。我已完成登录,已阅读响应并提取了 cookie(3 对 (name,value) )。然后我写了这样的包含 cookie 的字符串:

CookieString="name1=value1; name2=value2; name3=value3"

然后我执行以下操作

HttpURLConnection connection
connection = (HttpURLConnection)(new URL(Link).openConnection());
connection.setRequestMethod("GET");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Cookie", CookieString );
connection.connect();

然后我阅读了该页面,但它显示我没有登录论坛。我做错了什么?

编辑:我知道如果我想发帖,我必须提取安全令牌。我的思路是,为了提取它,我需要获取这个特定页面。但是要使安全令牌成为隐藏字段,我必须在线,因此我需要 cookie。但是当我 GET 页面并如上所述设置 cookie 时,我将页面作为访客获取,这表明我不在线并且安全令牌的值是访客,这对我没有用。我会检查你给我的链接,希望能找到解决办法。

【问题讨论】:

【参考方案1】:

可以肯定的是,您应该从响应的 Set-Cookie 标头中收集 cookie。要在后续请求中将它们发送回来,您应该使用URLConnection#addRequestProperty() 将它们一一设置。

基本上:

// ...

// Grab Set-Cookie headers:
List<String> cookies = connection.getHeaderFields().get("Set-Cookie");

// ...

// Send them back in subsequent requests:
for (String cookie : cookies) 
    connection.addRequestProperty("Cookie", cookie.split(";", 2)[0]);


// ...

split(";", 2) 用于摆脱与服务器端无关的 cookie 属性,例如 expirespath 等。

对于更方便的 HTTP 客户端,我建议查看Apache HttpComponents Client。它可以更透明地处理所有 cookie 内容。

另见:

How to use URLConnection?

更新:根据 cmets,这不是 cookie 问题。错误的请求令牌意味着服务器内置了 CSRF/bot 预防(以防止像你这样的人)。您需要从带有表单的请求页面中提取令牌作为隐藏输入字段,并将其作为请求参数重新发送。 Jsoup 可能有助于提取所有(隐藏的)输入字段。不要忘记传递您想以编程方式“按下”的按钮的名称-值对。另请参阅上述链接以获取更多提示。

将来,您真的应该更清楚您检索到的确切错误,而不是胡乱猜测。复制粘贴确切的错误信息等等。

【讨论】:

这就是我所做的,但它不起作用。我从响应的 Set-Cookie 标头中读取了 cookie。我曾经将它们与 setRequestProperty 一起设置。我一一尝试了 addRequestProperty 但结果是一样的。我找不到我做错了什么。如果可能的话,我宁愿避免使用第 3 方库。 那么问题出在其他地方。网址是什么?像 Fiddler 这样的 HTTP 跟踪器工具是怎么说的? 网址是一个vbulletin论坛的帖子回复页面。奇怪的是,当我使用带有 POST 方法的同一链接中的 cookie 来发布回复时,响应是一个页面,显示我没有有效的安全令牌,但它看到我在线,因此饼干工作。当我尝试使用相同的 cookie 获取相同的页面以提取安全令牌时,它要求我登录。我将安装 fiddler,看看它是如何工作的,然后会回复你。如果你有任何想法请告诉我。 FWIW,对于在 android 上工作的人,我最近尝试将多个 cookie 附加到 UrlConnection 并发现 addRequestProperty() 实际上并没有添加多个同名标题。这种观察可能是错误的,但我能让服务器识别我的多个 cookie 的唯一方法是将它们加入一个 String,并用 ; 分隔它们。然后将StringaddRequestProperty()/setRequestProperty() 设置为“Cookie”标头,如上所示。我似乎发现了关于 addRequest...setRequest... 实际做什么的相互矛盾的信息。 试过了,我相信cookie.split(";", 1)[0] 应该是cookie.split(";", 2)[0](限制参数表示要返回的片段数,其中最后的片段会自动占用字符串的剩余部分)。 【参考方案2】:

假设 cookie 值不是硬编码而是从先前的请求中获得的,那么使用 @987654321@ 类可能是最简单的。

CookieHandler.setDefault(new CookieManager());

然后您的HttpURLConnection 将自动保存它收到的所有 cookie,并将它们与下一个请求一起发送回同一主机。

【讨论】:

【参考方案3】:
// Grab Set-Cookie headers:
List<String> cookies = connection.getHeaderFields().get("Set-Cookie");

// ...

// Send them back in subsequent requests:
for (String cookie : cookies) 
    connection.addRequestProperty("Cookie", cookie.split(";", 1)[0]);

上面的代码可以发送多个 cookie,只需使用 setRequestProperty 而不是 addRequestProperty。工作代码是:

// Grab Set-Cookie headers:
List<String> cookies = connection.getHeaderFields().get("Set-Cookie");

// ...

// Send them back in subsequent requests:
for (String cookie : cookies) 
    connection.setRequestProperty("Cookie", cookie.split(";", 1)[0]);

【讨论】:

以上是关于如何使用 Java 在 Http Get 方法中设置 Cookie的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 HTTPBuilder 在 Groovy 中设置 GET-Response

如何在 Java 中执行 HTTP GET? [复制]

如何在 Ruby 的 RestClient gem 中设置超时?

使用 QNetworkManager 在 QT 中设计多个嵌套的 GET/POST 的最佳方法

在 node.js 中的 HTTP GET 中设置 URL 参数的默认值

在 python memoization 装饰器类中设置 get/set 属性