【问题标题】:GAE Refreshing due to a 401 (attempt 1/2)由于 401 导致 GAE 刷新(尝试 1/2)
【发布时间】:2017-03-14 17:57:55
【问题描述】:

我使用 gcloud app deploy 部署应用。它运行了几个小时,然后工作被以下信息日志卡住了:

03:54:59.748 Refreshing due to a 401 (attempt 1/2)
03:58:44.816 Refreshing due to a 401 (attempt 1/2)
03:58:55.781 Refreshing due to a 401 (attempt 1/2)
03:58:56.317 Refreshing due to a 401 (attempt 1/2)

似乎是从内部 serviceName: "appengine.googleapis.com" 记录下来的

部署的应用程序从 GCS 读取一些文件并使用 google pubsub 发布一些计算指标。我使用 google 客户端 api 库,它使用凭据进行身份验证。

    credentials = GoogleCredentials.get_application_default()
    if credentials.create_scoped_required():
        credentials = credentials.create_scoped(['https://www.googleapis.com/auth/devstorage.read_only)
    http = httplib2.Http()
    credentials.authorize(http)
    return discovery.build('storage', 'v1', http=http)

pubsub 也有类似的 sn-p。有没有人遇到过类似的问题,请求似乎永远卡在显示 401 状态代码的信息日志中。不知道为什么请求不会超时并导致失败。有什么解决方法吗?

【问题讨论】:

标签: google-app-engine google-cloud-storage google-cloud-platform google-authentication


【解决方案1】:

401 是未授权错误,这意味着 OAuth 不记名令牌不再有效,需要使用刷新令牌进行刷新。你解释的时间线与the duration of the bearer tokens一致。

我会使用cloud idiomatic libraries,或者如果您使用的是 GAE 标准,the appengine libraries directly。这些库自己处理身份验证(包括在令牌过期时刷新令牌),并包括在 App Engine 中使用的进一步优化。

【讨论】:

    【解决方案2】:

    这个让我很头疼,但我现在明白了。

    在我的应用程序中,我想扫描我的电子邮件中的关键字以获得最高的贝宝收据。当然,我不会透露我的全部机制,但我已经提供了超过必要的上下文和用法。我有一个个人帐户,我已重命名为 paypalEmailAccount@gmail.com,一个 api 管理员帐户已重命名为 office@myBusiness.com,网站我已重命名为 www.myBusiness.com。我不想冒险意外暴露任何漏洞。

    class Quickbooks(webapp2.RequestHandler):
        def get(self):
            self.post()
        def post(self):
            ping(self)
            user = users.get_current_user()
            if (levelOneUsers( user ) or levelTwoUsers( user )):
                nameField = self.request.get('pName')
                if nameField == 'e':
                    categoryLevel=0;
                    service = getUserGmail(self, 'paypalEmailAccount@gmail.com@gmail.com')
                    userName = 'paypalEmailAccount@gmail.com'
                    if( service ):
                        officeDriveService = getOfficeDrive()
                        topMessage = getTopMessage( service, officeDriveService, 'in:inbox service@paypal.com' )
        (main code then processes topMessage, no need to see any of that.....lol)
    
    def getUserGmail(self, emailAddress):
        if(emailAddress=='office@myBusiness.com'): 
            return getOfficeGmail()
        else:
            creds_query = Creds.query(ancestor=credsCounter_key(DEFAULT_CREDS_NAME)).order(-Creds.number)
            creds_query2 = creds_query.filter(Creds.number==emailAddress)
            creds_items = creds_query2.fetch(1)
            for creds_item in creds_items:
                jsonCreds = creds_item.jsonString
                check = json.loads(jsonCreds)
                token_info = urllib.urlopen("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" + check['access_token'])
                token_info_dict = json.loads(token_info.read())
                if( 'expires_in' in token_info_dict and token_info_dict['expires_in'] > 0 ):
                    credentials = OAuth2Credentials.from_json(jsonCreds)
                    http_auth = credentials.authorize(Http())
                    keepTrying = True
                    tryCounter = 0
                    while keepTrying:
                        try:
                            tryCounter += 1
                            service = build('gmail', 'v1', http=http_auth)
                        except:
                            time.sleep(1)
                            if (tryCounter >= 10):
                                raise
                        else:
                            keepTrying = False
                    return service
            flow = OAuth2WebServerFlow(client_id='???????????-??????????????????????????????????.apps.googleusercontent.com',
                                   client_secret='?????????????????????',
                                   scope='https://mail.google.com/', 
                                   redirect_uri='https://www.myBusiness.com.com/auth_return',
                                   login_hint=emailAddress)
            flow.params['access_type'] = 'offline'
            auth_uri = flow.step1_get_authorize_url()
            self.redirect(auth_uri)
    
    class Auth_Return(webapp2.RequestHandler):
        def get(self):
            self.post()
        def post(self):
            ping(self)
            code = nameField = self.request.get('code')
            flow = OAuth2WebServerFlow(client_id='?????????????-?????????????????????????.apps.googleusercontent.com',
                               client_secret='??????????????????',
                               scope='https://mail.google.com/', 
                               redirect_uri='https://www.myBusiness.com.com/auth_return')
            flow.params['access_type'] = 'offline'
            credentials = flow.step2_exchange(code)
            jsonCred = credentials.to_json()
            http_auth = credentials.authorize(Http())
            keepTrying = True
            tryCounter = 0
            while keepTrying:
                try:
                    tryCounter += 1
                    service = build('gmail', 'v1', http=http_auth)
                except:
                    time.sleep(1)
                    if (tryCounter >= 10):
                        raise
                else:
                    keepTrying = False
            response = service.users().getProfile(userId="me").execute()
            creds_query = Creds.query(ancestor=credsCounter_key(DEFAULT_CREDS_NAME)).order(-Creds.number)
            creds_query2 = creds_query.filter(Creds.number==response['emailAddress'])
            creds_items = creds_query2.fetch(1)
            if(len(creds_items) == 0):
                creds_item = Creds(parent=credsCounter_key(DEFAULT_CREDS_NAME))
                creds_item.number = response['emailAddress']
                creds_item.jsonString = jsonCred
                creds_item.put()
            else:
                for creds_item in creds_items:
                    creds_item.jsonString = jsonCred
                    creds_item.put()
            self.response.write('<b name="handshake_complete">A security handshake between server and email address: ' + response['emailAddress'] +  ' was required to continue. This is usually due to an expired certificate. This caused the previous request to be lost but the system will redirect back in 1 second...please wait.... A secure connection has been established.</b><br>' + """
    <script>
    window.location = "https://www.myBusiness.com/quickbooks?pName=????????";
    </script>
    """)
    
    app = webapp2.WSGIApplication([
        ('/', MainPageBlank ),
        ('/quickbooks', Quickbooks),
        ('/auth_return', Auth_Return),
        .......
    ], debug=True)
    

    好的....这么多,但只有一行要检查....其余的内容供您娱乐。不要批评我...不会听到...我是最伟大的

    if( 'expires_in' in token_info_dict and token_info_dict['expires_in'] > 0
    

    token_info_dict['expires_in'] 以秒为单位测量,“新鲜”时为 3600(1 小时) 每个人:Microsoft's Manage access tokens for API requests

    嗯,这是个问题。 google api 线程实例限制为 60 秒。如果 token_info_dict['expires_in'] 小于 60 但大于 0,则代码在 60 秒间隔内处理请求时可能会失败。此外,该错误最多有 1/60 的机会发生,因此很难确定。

    解决方案:

    if( 'expires_in' in token_info_dict and token_info_dict['expires_in'] > 60
    

    现在令牌不会在google api线程时间限制之前过期

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-06
      • 2021-05-20
      • 2017-04-03
      • 1970-01-01
      • 1970-01-01
      • 2011-09-16
      • 2018-07-17
      • 1970-01-01
      相关资源
      最近更新 更多