如何在ruby net/http?中实现cookie支持?

时间:2022-09-02 13:29:50

I'd like to add cookie support to a ruby class utilizing net/http to browse the web. Cookies have to be stored in a file to survive after the script has ended. Of course I can read the specs and write some kind of a handler, use some cookie.txt format and so on, but it seems to mean reinventing the wheel. Is there a better way to accomplish this task? Maybe some kind of a cooie jar class to take care of cookies?

我想将cookie支持添加到使用net/http浏览web的ruby类中。脚本结束后,必须将cookie保存在文件中。当然,我可以阅读规格说明并编写某种处理程序,使用一些cookie。txt格式等等,但它似乎意味着重新发明*。有更好的方法来完成这个任务吗?可能是某个cooie jar类来处理cookie ?

6 个解决方案

#1


33  

Taken from DZone Snippets

取自DZone片段

http = Net::HTTP.new('profil.wp.pl', 443)
http.use_ssl = true
path = '/login.html'

# GET request -> so the host can set his cookies
resp, data = http.get(path, nil)
cookie = resp.response['set-cookie'].split('; ')[0]


# POST request -> logging in
data = 'serwis=wp.pl&url=profil.html&tryLogin=1&countTest=1&logowaniessl=1&login_username=blah&login_password=blah'
headers = {
  'Cookie' => cookie,
  'Referer' => 'http://profil.wp.pl/login.html',
  'Content-Type' => 'application/x-www-form-urlencoded'
}

resp, data = http.post(path, data, headers)


# Output on the screen -> we should get either a 302 redirect (after a successful login) or an error page
puts 'Code = ' + resp.code
puts 'Message = ' + resp.message
resp.each {|key, val| puts key + ' = ' + val}
puts data

update

更新

#To save the cookies, you can use PStore
cookies = PStore.new("cookies.pstore")

# Save the cookie  
cookies.transaction do
  cookies[:some_identifier] = cookie
end

# Retrieve the cookie back
cookies.transaction do
  cookie = cookies[:some_identifier] 
end

#2


40  

The accepted answer will not work if your server returns and expects multiple cookies. This could happen, for example, if the server returns a set of FedAuth[n] cookies. If this affects you, you might want to look into using something along the lines of the following instead:

如果您的服务器返回并期望有多个cookie,那么所接受的答案将无法工作。例如,如果服务器返回一组FedAuth[n] cookie,就可能发生这种情况。如果这会影响到您,您可能想要使用以下内容:

http = Net::HTTP.new('https://example.com', 443)
http.use_ssl = true
path1 = '/index.html'
path2 = '/index2.html'

# make a request to get the server's cookies
response = http.get(path)
if (response.code == '200')
    all_cookies = response.get_fields('set-cookie')
    cookies_array = Array.new
    all_cookies.each { | cookie |
        cookies_array.push(cookie.split('; ')[0])
    }
    cookies = cookies_array.join('; ')

    # now make a request using the cookies
    response = http.get(path2, { 'Cookie' => cookies })
end

#3


12  

The accepted answer does not work. You need to access the internal representation of the response header where the multiple set-cookie values are stores separately and then remove everything after the first semicolon from these string and join them together. Here is code that works

公认的答案行不通。您需要访问响应头的内部表示,其中多个set-cookie值分别存储,然后从这些字符串中删除第一个分号后的所有内容,并将它们连接在一起。下面是有效的代码

r = http.get(path)
cookie = {'Cookie'=>r.to_hash['set-cookie'].collect{|ea|ea[/^.*?;/]}.join}
r = http.get(next_path,cookie)

#4


5  

Use http-cookie, which implements RFC-compliant parsing and rendering, plus a jar.

使用http-cookie,它实现与rpc兼容的解析和呈现,外加一个jar。

A crude example that happens to follow a redirect post-login:

一个简单的例子,它发生在重定向后登录:

require 'uri'
require 'net/http'
require 'http-cookie'

uri = URI('...')
jar = HTTP::CookieJar.new

Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
  req = Net::HTTP::Post.new uri
  req.form_data = { ... }
  res = http.request req
  res.get_fields('Set-Cookie').each do |value|
    jar.parse(value, req.uri)
  end

  fail unless res.code == '302'

  req = Net::HTTP::Get.new(uri + res['Location'])
  req['Cookie'] = HTTP::Cookie.cookie_value(jar.cookies(uri))
  res = http.request req
end

Why do this? Because the answers above are incredibly insufficient and flat out don't work in many RFC-compliant scenarios (happened to me), so relying on the very lib implementing just what's needed is infinitely more robust if you want to handle more than one particular case.

为什么这样做呢?因为上面的答案是非常不充分的,而且在许多符合rpc的场景中都不起作用(我也遇到过这种情况),所以如果您想处理多个特定的情况,那么依赖于真正需要的库实现就会更加健壮。

#5


3  

I've used Curb and Mechanize for a similar project. Just enable cookies support and save the cookies to a temp cookiejar... If your using net/http or packages without cookie support built in, you will need to write your own cookie handling.

我曾在一个类似的项目中使用过控制和机械化。只需启用cookie支持,并将cookie保存到临时库基贾(temp cookiejar)……如果您使用的是没有内置cookie支持的net/http或软件包,您将需要编写自己的cookie处理。

#6


1  

You can send receive cookies using headers.

您可以使用header发送接收cookie。

You can store the header in any persistence framework. Whether it is some sort of database, or files.

可以将header存储在任何持久性框架中。不管是数据库还是文件。

#1


33  

Taken from DZone Snippets

取自DZone片段

http = Net::HTTP.new('profil.wp.pl', 443)
http.use_ssl = true
path = '/login.html'

# GET request -> so the host can set his cookies
resp, data = http.get(path, nil)
cookie = resp.response['set-cookie'].split('; ')[0]


# POST request -> logging in
data = 'serwis=wp.pl&url=profil.html&tryLogin=1&countTest=1&logowaniessl=1&login_username=blah&login_password=blah'
headers = {
  'Cookie' => cookie,
  'Referer' => 'http://profil.wp.pl/login.html',
  'Content-Type' => 'application/x-www-form-urlencoded'
}

resp, data = http.post(path, data, headers)


# Output on the screen -> we should get either a 302 redirect (after a successful login) or an error page
puts 'Code = ' + resp.code
puts 'Message = ' + resp.message
resp.each {|key, val| puts key + ' = ' + val}
puts data

update

更新

#To save the cookies, you can use PStore
cookies = PStore.new("cookies.pstore")

# Save the cookie  
cookies.transaction do
  cookies[:some_identifier] = cookie
end

# Retrieve the cookie back
cookies.transaction do
  cookie = cookies[:some_identifier] 
end

#2


40  

The accepted answer will not work if your server returns and expects multiple cookies. This could happen, for example, if the server returns a set of FedAuth[n] cookies. If this affects you, you might want to look into using something along the lines of the following instead:

如果您的服务器返回并期望有多个cookie,那么所接受的答案将无法工作。例如,如果服务器返回一组FedAuth[n] cookie,就可能发生这种情况。如果这会影响到您,您可能想要使用以下内容:

http = Net::HTTP.new('https://example.com', 443)
http.use_ssl = true
path1 = '/index.html'
path2 = '/index2.html'

# make a request to get the server's cookies
response = http.get(path)
if (response.code == '200')
    all_cookies = response.get_fields('set-cookie')
    cookies_array = Array.new
    all_cookies.each { | cookie |
        cookies_array.push(cookie.split('; ')[0])
    }
    cookies = cookies_array.join('; ')

    # now make a request using the cookies
    response = http.get(path2, { 'Cookie' => cookies })
end

#3


12  

The accepted answer does not work. You need to access the internal representation of the response header where the multiple set-cookie values are stores separately and then remove everything after the first semicolon from these string and join them together. Here is code that works

公认的答案行不通。您需要访问响应头的内部表示,其中多个set-cookie值分别存储,然后从这些字符串中删除第一个分号后的所有内容,并将它们连接在一起。下面是有效的代码

r = http.get(path)
cookie = {'Cookie'=>r.to_hash['set-cookie'].collect{|ea|ea[/^.*?;/]}.join}
r = http.get(next_path,cookie)

#4


5  

Use http-cookie, which implements RFC-compliant parsing and rendering, plus a jar.

使用http-cookie,它实现与rpc兼容的解析和呈现,外加一个jar。

A crude example that happens to follow a redirect post-login:

一个简单的例子,它发生在重定向后登录:

require 'uri'
require 'net/http'
require 'http-cookie'

uri = URI('...')
jar = HTTP::CookieJar.new

Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
  req = Net::HTTP::Post.new uri
  req.form_data = { ... }
  res = http.request req
  res.get_fields('Set-Cookie').each do |value|
    jar.parse(value, req.uri)
  end

  fail unless res.code == '302'

  req = Net::HTTP::Get.new(uri + res['Location'])
  req['Cookie'] = HTTP::Cookie.cookie_value(jar.cookies(uri))
  res = http.request req
end

Why do this? Because the answers above are incredibly insufficient and flat out don't work in many RFC-compliant scenarios (happened to me), so relying on the very lib implementing just what's needed is infinitely more robust if you want to handle more than one particular case.

为什么这样做呢?因为上面的答案是非常不充分的,而且在许多符合rpc的场景中都不起作用(我也遇到过这种情况),所以如果您想处理多个特定的情况,那么依赖于真正需要的库实现就会更加健壮。

#5


3  

I've used Curb and Mechanize for a similar project. Just enable cookies support and save the cookies to a temp cookiejar... If your using net/http or packages without cookie support built in, you will need to write your own cookie handling.

我曾在一个类似的项目中使用过控制和机械化。只需启用cookie支持,并将cookie保存到临时库基贾(temp cookiejar)……如果您使用的是没有内置cookie支持的net/http或软件包,您将需要编写自己的cookie处理。

#6


1  

You can send receive cookies using headers.

您可以使用header发送接收cookie。

You can store the header in any persistence framework. Whether it is some sort of database, or files.

可以将header存储在任何持久性框架中。不管是数据库还是文件。