使用语言和框架:本人后端开发使用的Python的DRF(Django REST framework)框架
需求:在微信公众号开发时,需要实现自动回复,即被关注回复、收到消息回复、关键词回复
发现问题:按照微信公众号的开发文档,在写完逻辑代码后,测试时发现:Content回复的消息内容,使用"\n",预期效果应该是文字内容有换行效果,微信的文档也说明了换行可以使用"\n"换行符,但是实际测试的效果是没有换行。这个问题纠结了一天,最后发现是我响应给微信服务器的数据类型错误了。
问题分析过程:微信公众号文档里的原话(当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。)
文档已经说得很明白,在接收到微信的Post请求后,处理完具体的业务逻辑后,要对微信服务器作响应回复,如果需要特定的回复则返回特定XML结构,如果不作任何处理推荐方式直接回复success
根本原因:因为使用的是DRF框架,自然而然的在响应的时候使用了rest_framework.response.Response,但其实响应给微信服务器的是一个响应体数据,而我使用Response响应给微信服务器的是响应对象
解决方案:使用django.http.HttpResponse响应返回数据
代码演示:
# 使用的是类视图APIView def post(self, request): """接收微信Post数据,并处理""" data = request.body.decode("utf-8") doc = xmltodict.parse(data) # 解析xml数据 to_user = doc["xml"]["ToUserName"] # 开发者微信号 from_user = doc["xml"]["FromUserName"] # 发送方帐号(一个OpenID) if doc["xml"]["MsgType"] == "text": # 文本消息处理 dict = { "ToUserName" = from_user "FromUserName" = to_user "CreateTime" = int(time.time()) "Content" = "欢迎关注公众号!\n新人好礼等你来拿" } # 返回回复文本消息特定XML结构 xml_form = """ <xml> <ToUserName><![CDATA[{ToUserName}]]></ToUserName> <FromUserName><![CDATA[{FromUserName}]]></FromUserName> <CreateTime>{CreateTime}</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[{Content}]]></Content> </xml> """ # 根据判断是否返回回复文本消息还是不作任何处理 if ....: # 回复文本消息 return HttpResponse(xml_form.format(**dict)) else: # 不作任何处理 return HttpResponse("success")
django.http.HttpResponse和rest_framework.response.Response的区别:
1、HttpResponse
可以使用django.http.HttpResponse来构造响应对象,HttpResponse对象由开发人员创建,适用于返回图片,视频,音频等二进制文件
格式:HttpResponse(content=响应体, content_type=响应体数据MIME类型, status=状态码)
MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型:
text/html html
text/plain 普通文本
application/json json
响应头设置: 可以直接将HttpResponse对象当做字典进行响应头键值对的设置
response = HttpResponse(\'响应内容\')
response[\'Itcast\'] = \'Python\' # 自定义响应头Itcast, 值为Python
2、Response
REST framework提供的一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。
格式:Response(data, status=None, headers=None, content_type=None)
参数说明:
data: 字典类型,为响应准备的序列化处理后的数据;
status: 状态码,默认200;
headers: 用于存放响应头信息的字典;
content_type: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。
补充:JsonResponse对象是HttpResponse 的常用子类
帮助我们将数据转换为json字符串,再返回给客户端,会设置响应头 Content-Type 为 application/json
from django.http import JsonResponse
def resp(request):
return JsonResponse({\'city\': \'beijing\', \'subject\': \'python\'})
当包含的内容中包含中文时,会返回该中文对应的编码,例如:
def resp(request):
# 最终看到的效果是: {"name": "\u5f20\u4e09"}
response = JsonResponse({"name":"张三"})
return response
解决:JsonResponse(data, json_dumps_params={\'ensure_ascii\':False})
JsonResponse可以接收非字典数据,需要指定 safe=False