我使用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发布一些计算的指标。我使用谷歌客户端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的类似代码段。有没有人遇到类似的问题,其中请求似乎永远停留在显示401状态代码的信息日志中。不确定为什么请求不会超时并导致失败。任何解决方法?
答案 0 :(得分:0)
401是未经授权的错误,这意味着OAuth承载令牌不再有效,需要使用刷新令牌进行刷新。您解释的时间表与the duration of the bearer tokens匹配。
我会使用cloud idiomatic libraries,或者如果您使用的是GAE标准the appengine libraries directly。这些库本身处理身份验证(包括在令牌过期时刷新令牌),并包含在App Engine中使用的进一步优化。
答案 1 :(得分:-1)
这让我很头疼,但我现在明白了。
在我的应用中,我想扫描电子邮件中的关键字以获取最高的贝宝收据。当然,我不会透露我的全部技巧,但是我提供了超出上下文和用法所必需的更多内容。我有一个个人帐户,我已重命名为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线程时间限制之前过期