使用Python Chalice无法验证Facebook回调URL或验证令牌
问题描述
配置Facebook Messenger Webhook时,开发者页面始终提示验证失败:
The callback URL or verify token couldn't be validated. Please verify the provided information or try again later.
但查看CloudWatch日志,确认收到的hub.verify_token和我的VERIFY_TOKEN完全匹配,且服务返回了200响应和对应的hub.challenge值。以下是我的验证代码:
@app.route('/webhook', methods=['GET']) def webhook_verify(): print('testing') # Get all query parameters from the GET request query_params = app.current_request.query_params # Log all parameter names and values logger.info('Query parameters received:') for param_name, param_value in query_params.items(): print(f'{param_name}: {param_value}') hub_verify_token = query_params.get('hub.verify_token') hub_challenge = query_params.get('hub.challenge') if hub_verify_token == VERIFY_TOKEN: # Log a successful verification print('Webhook verification successful') return str(query_params.get("hub.challenge")), 200 # 200 OK # Log an unsuccessful verification print('Webhook verification failed: Wrong verify token') return {'error': 'Wrong verify token'}, 403 # 403 Forbidden
我已经参考过其他Python Facebook Messenger仓库的响应格式,但问题仍未解决。
排查与解决方案
清理响应中的额外内容:Facebook要求验证响应必须仅返回
hub.challenge的原始字符串,不能有任何额外输出(比如print语句的内容、空格、换行或HTTP头里的冗余信息)。你代码里的print语句如果被框架混入响应体,会直接导致验证失败。建议把所有print替换为logger.info,确保响应体只有纯净的挑战值。确认响应类型与格式:虽然用了
str()转换,但某些框架可能会自动给字符串响应添加Content-Type: text/html,而Facebook期望的是text/plain。可以手动指定响应头来规避这个问题:from flask import make_response # 替换验证成功分支的返回代码 if hub_verify_token == VERIFY_TOKEN: logger.info('Webhook verification successful') response = make_response(str(hub_challenge), 200) response.headers['Content-Type'] = 'text/plain' return response检查令牌的隐形字符:日志显示令牌匹配,但可能存在复制粘贴时引入的隐形空白字符(比如全角空格、换行符)。可以给令牌添加
strip()处理,消除这类干扰:if hub_verify_token and hub_verify_token.strip() == VERIFY_TOKEN.strip():排查中间代理的修改:如果服务部署在负载均衡或反向代理之后,中间层可能会修改响应内容(比如添加压缩、额外响应头)。检查CloudWatch中的完整响应日志,确认响应体没有被额外修改,响应头也符合要求。
内容的提问来源于stack exchange,提问作者Raphael Quiñones

