Ruby 求助,super 引发的对象销毁问题。

praguepp · 2013年04月30日 · 最后由 hhuai 回复于 2013年05月02日 · 3780 次阅读
#coding:utf-8
class DCPatronClient < Patron::Session
  attr_accessor :get_header,:post_header,:cookie,:cookie_hash

  private:initialize
  def initialize
    super
    @cookie_hash = {"SINFORSESSID"=>"","LifeTime"=>"3600","PHPSESSID"=>""}
  end

  def DCPatronClient.get_client(url, connect_timeout=120000, insecure=true)
    @sess = DCPatronClient.new
    @sess.insecure = insecure
    @sess.base_url = url
    @sess.connect_timeout = connect_timeout
    @sess.timeout = connect_timeout/1000
    #@sess.handle_cookies  # req.headers = self.headers.merge(headers),由于需要手动维护cookie,因此这里不需要加上内部的维护
    @sess.get_header={"User-Agent"=>" Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET4.0C; .NET4.0E)"}
    @sess.post_header={"User-Agent"=>" Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET4.0C; .NET4.0E)"}

    return @sess
  end

  #构造post请求
  def form_post(uri, data)
    @post_header["Content-Type"]= "application/x-www-form-urlencoded"
   # ATT::KeyLog::debug "uri:#{uri},data:#{data}"
    ret=nil
    times = 0
    2.times do
      begin
        ret = super_post(uri, data, @post_header)
        times +=1
      rescue Patron::Error
        ret=nil
        if $!.to_s.include?("transfer closed with outstanding read data remaining")#修改登录端口会返回此错误,实际修改成功
          ret.body = "{\"success\":true,\"data\":[],\"total\":4,\"time\":0,\"img\":null}"
        end
        ATT::KeyLog.info("#{$!.to_s},http error,retrying...")
      rescue JSON::ParserError
        ATT::KeyLog.info("#{$!.to_s},need to login,retrying...")
        if not islogin?(ret) && times >0
          relogin
        else
          ATT::KeyLog.error("json parse error,server response:#{ret.body[0..20]}")
        end
        ret=nil
      rescue
        ret=nil
        sleep(10)
        ATT::KeyLog.info("#{$!.to_s},other error,retrying...")
      end
      break unless ret==nil
    end
    res = OpenStruct.new
    res.url = ret.url
    res.status = ret.status
    res.status_line = ret.status_line
    res.redirect_count = ret.redirect_count
    res.headers = ret.headers
    if res.status.to_s[0,1] != "2"
      res.body = "{\"success\":false, \"msg\":\"response error, code: #{ret.status}\", \"errorno\":-8}"
    else
      if ret.body.index(":undefined")#修正json返回不标准的情况
        ret.body.gsub!(":undefined",":false")
      end
         #ATT::KeyLog::debug  "status_line:#{ret.status_line},header:#{ret.headers},body:#{ret.body}"
      hash = JSON.parse(ret.body)
      if hash["success"] == true
        hash.store("errorno", 0)
        hash.store("msg", "default success msg while original msg is null") if hash["data"].nil?
      elsif hash["success"] == false && hash["msg"].to_s ==""
        hash.store("errorno", -255)
        hash.store("success", false)
        hash.store("msg", "unknow error type")
      end
      res.body = hash.to_json
    end
    return res
  end

  def islogin?(ret)
    begin
      if ret.body.include?("ActiveX")&&ret.body.include?("Dkey")
        return false
      else
        return true
      end
    rescue
      return false
    end
  end


  def hash_to_comma(hash)
    ret = ""
    hash.each {|key, value| ret = "#{key}=#{value};#{ret}"}
    return ret
  end


  def super_post(uri, data, header={})
    #ATT::KeyLog::debug "uri:#{uri},data:#{data}"
    Patron::Session.instance_method("post").bind(self).call(uri, data, header)
  end


  def relogin
    passwd=Digest::MD5.hexdigest($dcpasswd)
    ATT::KeyLog.info("relogin user:#{$user} password:#{$dcpasswd},MD5:#{passwd}")
    login_query = "login_user=#{$user}&login_password=#{passwd}&login_pin=&in=&pwd=&dkey=&login=true"
    ret =  super_post("/src/acloglogin.php",login_query,@get_header)
    #如果有set cookie,则表示需要提取cookie啦!~
    #    @cookie = ret.headers["Set-Cookie"].to_s=="" ? @cookie : ret.headers["Set-Cookie"].split(";")[0]  #PHPSESSID=d1a4cfefb265cc2cb1f3ccdd7cdb437e; path=/
    #    @cookie += ";LifeTime=3600; SINFORSESSID="
    #    @post_header["Cookie"] = @cookie+Time.now.to_i.to_s
    @cookie_hash = {"SINFORSESSID"=>"","LifeTime"=>"3600","PHPSESSID"=>""}

    @cookie_hash["PHPSESSID"] = ret.headers["Set-Cookie"].to_s=="" ? @cookie_hash["PHPSESSID"] : ret.headers["Set-Cookie"].split(";")[0]
    @cookie_hash["PHPSESSID"] = @cookie_hash["PHPSESSID"].split("=")[1] if @cookie_hash["PHPSESSID"].include?("PHPSESSID")

    @cookie_hash["SINFORSESSID"] = Time.now.to_i.to_s

    @post_header["Cookie"] = hash_to_comma(@cookie_hash) 

    @post_header["Content-Type"]= "application/json"
    @post_header["x-requested-with"]= "XMLHttpRequest"
    if islogin?(ret)
      ATT::KeyLog.info "Login datacenter ok..."
      return true
    else
      ATT::KeyLog.error "Login datacenter error:#{ret.body[0..20]}..."
      return false
    end
  end

  def logout
    ret = get("/src/acloglogin.php?in=1&logout=1",@get_header)
    ATT::KeyLog.info "logout query ret:#{ret}"
  end


  def hash_to_and(hash)
    ret = ""
    hash.each do |key, value|
      if value.class == String
        ret = "#{key}=#{URI.encode(value)}&#{ret}"
      else
        ret = "#{key}=#{value}&#{ret}"
      end
    end
    ret
  end

  #封装get请求
  def get(url, data)
    get_header = @post_header
    get_header["Content-Type"]= "application/x-www-form-urlencoded"
    get_header.delete("x-requested-with")
    uri = nil
    uri = url
    if data != nil
      if uri.to_s.include?("?")
        uri << "&"
      else
        uri << "?"
      end
      uri << hash_to_and(data)
    end

    ATT::KeyLog.info("uri:#{uri}")
    return super(uri,get_header)   //问题

  end



end

在调用 get 的方法后,重复调用,uri 的值会重复累加,请问该如何解决保证每次处理 uri 的值不累加?

先排代码吧,看说明。

已排查了一遍,发现 Uri 每次都保有值,,即使 uri = nil,个人觉得是 super 的问题 #1 楼 @chenge

private:initialize def initialize super @cookie_hash = {"SINFORSESSID"=>"","LifeTime"=>"3600","PHPSESSID"=>""} end

# 封装 get 请求 def get(url, data) get_header = @post_header get_header["Content-Type"]= "application/x-www-form-urlencoded" get_header.delete("x-requested-with") uri = nil uri = url if data != nil if uri.to_s.include?("?") uri << "&" else uri << "?" end uri << hash_to_and(data) end

ATT::KeyLog.info("uri:#{uri}") return super(uri,get_header) //问题 end

#2 楼 @praguepp 我是说排列整齐,方便别人看,是个礼貌。你看别人的帖子,都是彩色的代码。

private :initialize 这是要干嘛?

#3 楼 @chenge 抱歉,是从 netbeans copy 过来的,以为也是会格式化,没想到转换了下。。

#5 楼 @praguepp 替你格式化了一下。

 #coding: utf-8

class DCPatronClient < Patron::Session
  attr_accessor :get_header,:post_header,:cookie,:cookie_hash

  private:initialize
  def initialize
    super
    @cookie_hash = {"SINFORSESSID"=>"","LifeTime"=>"3600","PHPSESSID"=>""}
  end

  def DCPatronClient.get_client(url, connect_timeout=120000, insecure=true)
    @sess = DCPatronClient.new
    @sess.insecure = insecure
    @sess.base_url = url
    @sess.connect_timeout = connect_timeout
    @sess.timeout = connect_timeout/1000
    #@sess.handle_cookies # req.headers = self.headers.merge(headers),由于需要手动维护cookie,因此这里不需要加上内部的维护
    @sess.get_header={"User-Agent"=>" Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET4.0C; .NET4.0E)"}
    @sess.post_header={"User-Agent"=>" Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET4.0C; .NET4.0E)"}

    return @sess

  end

  #构造post请求
  def form_post(uri, data)
    @post_header["Content-Type"]= "application/x-www-form-urlencoded"
    # ATT::KeyLog::debug "uri:#{uri},data:#{data}"
    ret=nil
    times = 0
    2.times do
      begin
        ret = super_post(uri, data, @post_header)
        times +=1
      rescue Patron::Error
        ret=nil
        if $!.to_s.include?("transfer closed with outstanding read data remaining")#修改登录端口会返回此错误,实际修改成功
          ret.body = "{\"success\":true,\"data\":[],\"total\":4,\"time\":0,\"img\":null}"
        end
        ATT::KeyLog.info("#{$!.to_s},http error,retrying...")
      rescue JSON::ParserError
        ATT::KeyLog.info("#{$!.to_s},need to login,retrying...")
        if not islogin?(ret) && times >0
          relogin
        else
          ATT::KeyLog.error("json parse error,server response:#{ret.body[0..20]}")
        end
        ret=nil
      rescue
        ret=nil
        sleep(10)
        ATT::KeyLog.info("#{$!.to_s},other error,retrying...")
      end
      break unless ret==nil
    end
    res = OpenStruct.new
    res.url = ret.url
    res.status = ret.status
    res.status_line = ret.status_line
    res.redirect_count = ret.redirect_count
    res.headers = ret.headers
    if res.status.to_s[0,1] != "2"
      res.body = "{\"success\":false, \"msg\":\"response error, code: #{ret.status}\", \"errorno\":-8}"
    else
      if ret.body.index(":undefined")#修正json返回不标准的情况
        ret.body.gsub!(":undefined",":false")
      end
      #ATT::KeyLog::debug "status_line:#{ret.status_line},header:#{ret.headers},body:#{ret.body}"
      hash = JSON.parse(ret.body)
      if hash["success"] == true
        hash.store("errorno", 0)
        hash.store("msg", "default success msg while original msg is null") if hash["data"].nil?
      elsif hash["success"] == false && hash["msg"].to_s ==""
        hash.store("errorno", -255)
        hash.store("success", false)
        hash.store("msg", "unknow error type")
      end
      res.body = hash.to_json
    end
    return res
  end

  def islogin?(ret)
    begin
      if ret.body.include?("ActiveX")&&ret.body.include?("Dkey")
        return false
      else
        return true
      end
    rescue
      return false
    end
  end

  def hash_to_comma(hash)
    ret = ""
    hash.each {|key, value| ret = "#{key}=#{value};#{ret}"}
    return ret
  end

  def super_post(uri, data, header={})
    #ATT::KeyLog::debug "uri:#{uri},data:#{data}"
    Patron::Session.instance_method("post").bind(self).call(uri, data, header)
  end

  def relogin
    passwd=Digest::MD5.hexdigest($dcpasswd)
    ATT::KeyLog.info("relogin user:#{$user} password:#{$dcpasswd},MD5:#{passwd}")
    login_query = "login_user=#{$user}&login_password=#{passwd}&login_pin=&in=&pwd=&dkey=&login=true"
    ret = super_post("/src/acloglogin.php",login_query,@get_header)
    #如果有set cookie,则表示需要提取cookie啦!~
    # @cookie = ret.headers["Set-Cookie"].to_s=="" ? @cookie : ret.headers["Set-Cookie"].split(";")[0] #PHPSESSID=d1a4cfefb265cc2cb1f3ccdd7cdb437e; path=/
    # @cookie += ";LifeTime=3600; SINFORSESSID="
    # @post_header["Cookie"] = @cookie+Time.now.to_i.to_s
    @cookie_hash = {"SINFORSESSID"=>"","LifeTime"=>"3600","PHPSESSID"=>""}

    @cookie_hash["PHPSESSID"] = ret.headers["Set-Cookie"].to_s=="" ? @cookie_hash["PHPSESSID"] : ret.headers["Set-Cookie"].split(";")[0]
    @cookie_hash["PHPSESSID"] = @cookie_hash["PHPSESSID"].split("=")[1] if @cookie_hash["PHPSESSID"].include?("PHPSESSID")

    @cookie_hash["SINFORSESSID"] = Time.now.to_i.to_s

    @post_header["Cookie"] = hash_to_comma(@cookie_hash) 

    @post_header["Content-Type"]= "application/json"
    @post_header["x-requested-with"]= "XMLHttpRequest"
    if islogin?(ret)
      ATT::KeyLog.info "Login datacenter ok..."
      return true
    else
      ATT::KeyLog.error "Login datacenter error:#{ret.body[0..20]}..."
      return false
    end

  end

  def logout
    ret = get("/src/acloglogin.php?in=1&logout=1",@get_header)
    ATT::KeyLog.info "logout query ret:#{ret}"
  end

  def hash_to_and(hash)
    ret = ""
    hash.each do |key, value|
      if value.class == String
        ret = "#{key}=#{URI.encode(value)}&#{ret}"
      else
        ret = "#{key}=#{value}&#{ret}"
      end
    end
    ret
  end

  #封装get请求
  def get(url, data)
    get_header = @post_header
    get_header["Content-Type"]= "application/x-www-form-urlencoded"
    get_header.delete("x-requested-with")
    uri = nil
    uri = url
    if data != nil
      if uri.to_s.include?("?")
        uri << "&"
      else
        uri << "?"
      end
      uri << hash_to_and(data)
    end

    ATT::KeyLog.info("uri:#{uri}")
    return super(uri,get_header)

  end

end

#7 楼 @praguepp 建议不要贴太长的代码,只贴出相关的部分。

#coding: utf-8

class DCPatronClient < Patron::Session
  attr_accessor :get_header,:post_header,:cookie,:cookie_hash

  private:initialize
  def initialize
    super
    @cookie_hash = {"SINFORSESSID"=>"","LifeTime"=>"3600","PHPSESSID"=>""}
  end

  def DCPatronClient.get_client(url, connect_timeout=120000, insecure=true)
    @sess = DCPatronClient.new
    @sess.insecure = insecure
    @sess.base_url = url
    @sess.connect_timeout = connect_timeout
    @sess.timeout = connect_timeout/1000
    #@sess.handle_cookies # req.headers = self.headers.merge(headers),由于需要手动维护cookie,因此这里不需要加上内部的维护
    @sess.get_header={"User-Agent"=>" Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET4.0C; .NET4.0E)"}
    @sess.post_header={"User-Agent"=>" Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET4.0C; .NET4.0E)"}

    return @sess

  end


  def super_post(uri, data, header={})
    #ATT::KeyLog::debug "uri:#{uri},data:#{data}"
    Patron::Session.instance_method("post").bind(self).call(uri, data, header)
  end


  #封装get请求
  def get(url, data)
    get_header = @post_header
    get_header["Content-Type"]= "application/x-www-form-urlencoded"
    get_header.delete("x-requested-with")
    uri = nil
    uri = url
    if data != nil
      if uri.to_s.include?("?")
        uri << "&"
      else
        uri << "?"
      end
      uri << hash_to_and(data)
    end

    ATT::KeyLog.info("uri:#{uri}")
    return super(uri,get_header)

  end

end

#6 楼 @edgar_wang_cn 怎样格式化?在编辑器里面是可以的

M 键会告诉你。

#coding: utf-8

class DCPatronClient < Patron::Session
  attr_accessor :get_header,:post_header,:cookie,:cookie_hash

  private:initialize

  def initialize
    super
    @cookie_hash = {"SINFORSESSID"=>"","LifeTime"=>"3600","PHPSESSID"=>""}
  end

  def DCPatronClient.get_client(url, connect_timeout=120000, insecure=true)
    @sess = DCPatronClient.new
    @sess.insecure = insecure
    @sess.base_url = url
    @sess.connect_timeout = connect_timeout
    @sess.timeout = connect_timeout/1000
    #@sess.handle_cookies # req.headers = self.headers.merge(headers),由于需要手动维护cookie,因此这里不需要加上内部的维护
    @sess.get_header={"User-Agent"=>" Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET4.0C; .NET4.0E)"}
    @sess.post_header={"User-Agent"=>" Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET4.0C; .NET4.0E)"}

    return @sess

  end

  def super_post(uri, data, header={})
    #ATT::KeyLog::debug "uri:#{uri},data:#{data}"
    Patron::Session.instance_method("post").bind(self).call(uri, data, header)
  end

  #封装get请求
  def get(url, data)
    get_header = @post_header
    get_header["Content-Type"]= "application/x-www-form-urlencoded"
    get_header.delete("x-requested-with")
    uri = nil
    uri = url
    if data != nil
      if uri.to_s.include?("?")
        uri << "&"
      else
        uri << "?"
      end
      uri << hash_to_and(data)
    end

    ATT::KeyLog.info("uri:#{uri}")
    return super(uri,get_header)

  end

end

#10 楼 @praguepp 我先用 Vim 自动格式化代码,然后你可以参照回复框下的帮助。

#11 楼 @chenge 知道了,呵呵

我在外层是直接调用类方法

def self.dc_get(php,get_header,mode,type="html")
     dcclient = getlogon_dc_client(mode)
     ATT::KeyLog::debug "#{php}"
     ret = dcclient.get(php, get_header)
     if type=="html"
       return ret.body.to_s
     else
       res = ret.body.to_s
       begin
         hash = JSON.parse(res)
         return  hash
       rescue JSON::ParserError
         ATT::KeyLog.debug("the operation result is: #{hash.to_s}" )
         raise
       end
     end
   end

uri 来自 url 参数,是不是你的 url 在变啊?

这代码看不出来是想闹哪样... 不如删掉 def get(...) 算了:

def logout
  data = @get_header.merge "Content-Type" => "application/x-www-form-urlencoded"
  data.delete "x-requested-with"
  ret = get("/src/acloglogin.php?in=1&logout=1&" + data.to_param, {})
  ATT::KeyLog.info "logout query ret:#{ret}"
end

url 是会变化的,,我单元测试的调用结果是这样,后面的 url 都被不断的加在后面,类似于 uri+=uri,这段代码是作用是向服务器发起 get 的请求,然后解析 csv,在 get 请求发现 uri 被不断 uri+=uri 了,最后长度超长,导致服务返回错误

INFO  13-04-30 19:01:14 judge_result.rb:354:in `judge_export': <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>414 Request-URI Too Large</title>
</head><body>
<h1>Request-URI Too Large</h1>
<p>The requested URL's length exceeds the capacity
limit for this server.<br />
</p>
<hr>
<address>Apache/2.2.15 (Red Hat) Server at localhost.localdomain Port 80</address>
</body></html>
ERROR 13-04-30 19:01:14 keyword.rb:33:in `execute': 执行关键字中发生异常,异常类: CSV::IllegalFormatError, 异常消息: CSV::IllegalFormatError
ERROR 13-04-30 19:01:14 keyword.rb:43:in `print_bkt': C:/ATT_rake_server_ruby187/ruby/lib/ruby/1.8/csv.rb:607:in `get_row'
C:/ATT_rake_server_ruby187/ruby/lib/ruby/1.8/csv.rb:567:in `shift'
./lib/judge_result.rb:356:in `judge_export'
./lib/operator_page_check.rb:50:in `target_dimension_export'

#16 楼 @chenge 方法作用是是传入不同 url 构造 get 请求进行处理

#17 楼 @luikore 方法作用是是传入不同 url 构造 get 请求进行处理

调用两次的结果。

DEBUG 13-04-30 19:18:51 dc_connect.rb:82:in `dc_get': /src/json_data.php?csv_download=1&page=1&sortorder=desc&qtype=json&rp=100&sortname=hot_spot&area_type=city&query=%7B%22realtime%22:true,%22hour%22:%220%22,%22timetype%22:0,%22city%22:%22%E4%BB%BB%E6%84%8F%22,%22date_range%22:%222013-04-30%202013-04-30%22%7D&type=service&
INFO  13-04-30 19:18:51 dcpatronclient.rb:173:in `get': uri:/src/json_data.php?csv_download=1&page=1&sortorder=desc&qtype=json&rp=100&sortname=hot_spot&area_type=city&query=%7B%22realtime%22:true,%22hour%22:%220%22,%22timetype%22:0,%22city%22:%22%E4%BB%BB%E6%84%8F%22,%22date_range%22:%222013-04-30%202013-04-30%22%7D&type=service&&csv_download=1&page=1&sortorder=desc&qtype=json&rp=100&sortname=ap&area_type=hotspot&query=%7B%22realtime%22:true,%22hour%22:%220%22,%22timetype%22:0,%22city%22:%22%22,%22date_range%22:%222013-04-30%202013-04-30%22,%22hotspot_name%22:%22%22,%22hotspot_type%22:%22%22%7
D&type=service&

#17 楼 @luikore get 的方法是构造请求,解析 csv 文件

问题已发现,但不清楚为什么常量 T 会一直保留上次的值。 定位是这样: 在 A 文件中有定义了常量,有方法 test

module A
T="test"
def test(var)
var = var + "tt"
puts var
end
end
B文件中include A,有方法test1
module B
include A
class TT
def  test1(T)
test(T)

end

end
TT.new.test1
TT.new.test1
这样调用多次,
T的值就会不断增加

#23 楼 @praguepp 直接 = 这样应该不会,但如果你用<<或带 ! 的改变自身方法就会。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册