TencentCloud/tencentcloud-sdk-ruby

需要使用多个模块功能,引用多个模块的时候,会出现冲突,导致只有一个模块的请求能成功

jasli2 opened this issue · 2 comments

如果需要使用多个模块功能的时候, 有出现一些问题。比如如下代码:

require 'tencentcloud-sdk-common'
require 'tencentcloud-sdk-sms'
require 'tencentcloud-sdk-captcha'
class Tc
    def self.send_sms(phone, template_id, params)
        begin
            cre = TencentCloud::Common::Credential.new(Rails.application.credentials.tc[:app_id], Rails.application.credentials.tc[:app_key])
            cli = TencentCloud::Sms::V20210111::Client.new(cre, 'ap-guangzhou')
            req = TencentCloud::Sms::V20210111::SendSmsRequest.new([phone], '1400531212', template_id, '五号代理', params)
            cli.SendSms(req)
        rescue TencentCloud::Common::TencentCloudSDKException => e
            Rails.logger.error '---- SendSms exception ----'
            Rails.logger.error e
            Rails.logger.error '---- end ----'
            raise e
        end
    end

    def self.captcha_check(appid, ticket, rand_str, ip)
        return false if appid != Rails.application.credentials.tc[:captcha_id]
        return false if ticket.nil? || rand_str.nil? || ip.nil?
        begin
            cre = TencentCloud::Common::Credential.new(Rails.application.credentials.tc[:app_id], Rails.application.credentials.tc[:app_key])
            cli = TencentCloud::Captcha::V20190722::Client.new(cre, 'ap-guangzhou')
            req = TencentCloud::Captcha::V20190722::DescribeCaptchaResultRequest.new(9, ticket, ip, rand_str, appid.to_i, Rails.application.credentials.tc[:captcha_key])
            response = cli.DescribeCaptchaResult(req)
            if response.CaptchaCode == 1
                return true
            else
                Rails.logger.error '---- DescribeCaptchaResult failed ----'
                Rails.logger.error response.CaptchaCode
                Rails.logger.error response.CaptchaMsg
                Rails.logger.error response.EvilLevel
                Rails.logger.error '---- end ----'
                return false
            end
            return true
        rescue TencentCloud::Common::TencentCloudSDKException => e
            Rails.logger.error '---- DescribeCaptchaResult exception ----'
            Rails.logger.error e
            Rails.logger.error '---- end ----'
            raise e
        end
    end
end

以上代码,如果调用 Tc.captcha_check(....), 调用会成功。
但是如果调用 Tc.send_sms(.....),则会报错:

[TencentCloudSDKError] Code=InvalidAction, Message=The request action=`SendSms` is invalid or not found in service=`captcha` and version=`2019-07-22`., RequestId=a00c0378-21c7-4d15-8465-1a4347cc3ff5

而且,require的顺序会带来不一样的错误。其行为是:只有最后引用的模块(如 tencentcloud-sdk-captcha )能正常运行。

问题根源

查看sdk源码,发现主要的问题是client的抽象父类中定义的class variable带来的:api_version,endpoint, sdk_version

    class AbstractClient
      include Log

      @@api_version = ''
      @@endpoint = ''
      @@sdk_version = '1.0.90'
      def initialize(credential, region, profile = nil)
        raise TencentCloudSDKException.new('InvalidCredential', 'Credential is None or invalid') unless credential

        @credential = credential
        @region = region
        @profile = profile || ClientProfile.new
        @request = ApiRequset.new(@profile.http_profile.scheme, endpoint, nil, @profile.http_profile.req_timeout, @profile.http_profile.proxy)
      end

这三个class variable,会在各个子类中覆盖,例如,在 tencentcloud-sdk-captcha 中:

module TencentCloud
  module Captcha
    module V20190722
      class Client < TencentCloud::Common::AbstractClient
        @@api_version = '2019-07-22'
        @@endpoint = 'captcha.tencentcloudapi.com'
        @@sdk_version = 'CAPTCHA_' + File.read(File.expand_path('../VERSION', __dir__)).strip

这样一来,这个class variable就会在引用的时候被写入。在只使用单个模块的时候不会有问题。但是多个模块的时候就会出问题。这个问题同样会造成同一个模块的不同版本被覆盖。比如 sms 模块中的不同版本。

临时解法

我目前的解决办法如下,在抽象的client类中这样定义这些变量为实例变量:

    class AbstractClient
      include Log

      def initialize(credential, region, profile = nil, api_version, endpoint, sdk_version)
        raise TencentCloudSDKException.new('InvalidCredential', 'Credential is None or invalid') unless credential

        @api_version = api_version
        @endpoint = endpoint
        @sdk_version = sdk_version
        @credential = credential
        @region = region
        @profile = profile || ClientProfile.new
        @request = ApiRequset.new(@profile.http_profile.scheme, endpoint, nil, @profile.http_profile.req_timeout, @profile.http_profile.proxy)
      end

然后在继承类的初始化函数中,初始化对应的变量。这样不同的模块示例不会互相干扰:

module Captcha
    module V20190722
      class Client < TencentCloud::Common::AbstractClient
        attr_writer :api_version, :endpoint, :sdk_version
        def initialize(credential, region, profile = nil)
            super(credential, region, profile, '2019-07-22', 'captcha.tencentcloudapi.com', 'CAPTCHA_' + File.read(File.expand_path('../VERSION', __dir__)).strip)
        end

但是这样的改法需要所有的模块都做出同样的改动,供你们参考。

zqfan commented

感谢反馈,我们刚根据您的建议发布了新版本,应该可以解决你的问题

好的,我想这个问题可以关闭了