Odoo 14按钮触发短信发送失败,请求技术排查
短信未发送问题排查与解决方案
核心故障点排查
1. API密钥获取逻辑存在风险
- 未处理请求失败场景:
requests.get未校验响应状态码(如401认证失败、404接口不存在),若接口返回非200状态,r.text.split(':')[1]会抛出索引错误,或获取到无效密钥。 - 路径参数拼接不规范:密码为空时,最终URL会以
/结尾(如http://bulksms.skill.jobs/getkey/C2006884/),可能不符合第三方API的路径规则。 - 硬编码空密码:若第三方API获取密钥必须验证密码,空密码会导致获取的密钥无效。
2. 短信发送请求未做错误校验
- 未解析响应内容:仅打印
r(响应对象),无法得知API返回的具体错误(如密钥无效、手机号格式错误、账户余额不足)。 - 请求参数格式可能不符合要求:部分短信API要求用
json格式传参而非data(表单格式),当前用data=params可能导致参数无法被正确解析。 - 手机号格式不明确:
self.restaurant_id.mobile可能缺少国际区号(如+880),或格式不符合API要求(如含非数字字符)。 - 状态更新逻辑不合理:无论请求是否成功,直接将
state设为sent,无法区分发送成功/失败状态。
3. 消息内容存在无效占位符
消息字符串中on .是无效内容(因注释了date_and_time变量),虽不直接导致发送失败,但可能影响短信可读性,甚至部分API会拦截格式异常的内容。
针对性解决方案
1. 修复API密钥获取逻辑
def get_api_key(self, url='', username='', password=''): if not url: url = 'http://bulksms.skill.jobs/getkey' if not username: username = 'C2006884' # 请确认第三方API是否需要密码,若需要补全正确密码 if not password: password = "你的实际密码" # 使用查询参数而非路径参数(若API支持),避免空密码导致的路径异常 params = {"username": username, "password": password} try: r = requests.get(url=url, params=params) # 校验响应状态码,非200则抛出异常 r.raise_for_status() # 先检查返回格式是否符合预期,避免split出错 if ':' not in r.text: raise ValueError("API返回格式异常,无法提取密钥") api_key = r.text.split(':')[1].strip() # 去除可能的空格 print(f"获取到API密钥: {api_key}") return api_key except Exception as e: print(f"获取API密钥失败: {str(e)}") # 可根据Odoo日志机制记录错误 self.env.cr.rollback() raise UserError(f"获取短信API密钥失败: {str(e)}")
2. 优化短信发送请求与错误处理
def send_sms(self, api_endpoint='', senderid='', **kw): if not api_endpoint: api_endpoint = "https://bulksms.skill.jobs/smsapi" if not senderid: senderid = "8809612436715" # 校验手机号格式 mobile = self.restaurant_id.mobile if not mobile or not mobile.strip().isdigit(): raise UserError("餐厅手机号格式无效,请检查") # 确保手机号带国际区号(根据第三方API要求调整) if not mobile.startswith('+'): mobile = f"+{mobile}" # 修复消息内容的无效占位符 message = "{customer_name} has sent a reservation in {restaurant_name}. Please call {customer_mobile} for further info.".format( customer_name=self.customer_id.name, restaurant_name=self.restaurant_id.name, customer_mobile=self.customer_id.mobile, ) try: api_key = self.get_api_key() params = { "api_key": api_key, "type": "text", "contacts": mobile, "senderid": senderid, "msg": message } # 若API要求JSON格式,替换为json=params # r = requests.post(url=api_endpoint, json=params) r = requests.post(url=api_endpoint, data=params) r.raise_for_status() # 解析响应内容,确认发送状态 response_data = r.json() if r.headers.get('content-type') == 'application/json' else r.text print(f"短信API响应: {response_data}") # 根据API返回的成功标识更新状态(需参考第三方API文档) if "success" in response_data.lower(): self.state = 'sent' else: self.state = 'failed' raise UserError(f"短信发送失败: {response_data}") return True except Exception as e: print(f"短信发送失败: {str(e)}") self.state = 'failed' self.env.cr.rollback() raise UserError(f"短信发送失败: {str(e)}")
3. 额外排查步骤
- 直接用Postman/curl调用第三方API,手动传入获取到的密钥、手机号、消息,验证API本身是否可正常发送短信,排除Odoo代码外的问题。
- 检查第三方短信账户状态:是否有余额、是否绑定了正确的发送号码(senderid)、是否有发送限制(如地区、频次)。
- 确认Odoo服务器可正常访问第三方API的域名(排查防火墙、网络代理问题)。
内容的提问来源于stack exchange,提问作者Nahid Jawad Angon
相关产品推荐
相关产品推荐

