使用語言和框架:本人后端開發使用的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