Eu ia escrever uma conta pública como uma ferramenta para lembretes de mensagens, então fui para a plataforma pública WeChat e planejei experimentá-la com a interface de conta de teste. Não há problema em escrever o código e o servidor já foi implantado. Basicamente todos os problemas foram verificados, mas a configuração ainda falha. Por fim, constatou-se que havia um problema no cabeçalho da solicitação.
Primeiro, liste os problemas que precisam de atenção e veja se você já fez isso. Se não, resolva-os primeiro.
- Deve usar o endereço que começa com https:// ou http:// (nome de domínio obrigatório)
- O endereço deve suportar a porta 80 e a porta 443 (encontre um site na Internet e verifique-o)
- O token pode ser em inglês ou um número, com mais de 3 dígitos, e você pode usar abcdefg como quiser.
O código do exemplo do site oficial também é um pouco problemático. Ele retorna true diretamente, mas na verdade retorna o valor de echostr. Então
há um poço nesta área! ! !
Note que o valor retornado deve ser o valor de echostr, e o cabeçalho da requisição retornada deve ser o mesmo aceito pelo WeChat oficial, eles receberam text/html; charset=utf-8 No começo, usei o framework rest_framework do Django, e o
Response retornado Como resultado, embora eu tenha definido o content_type, há um buraco nesta área. Deve-se notar que o comportamento padrão da classe Response é que os números passados para ela são serializados automaticamente no formato JSON, e o conteúdo O tipo padrão é application/json. Portanto, mesmo se eu definir content_type="text/html; charset=utf-8, o resultado retornado ainda estará no formato JSON. Cole o código Django do erro abaixo
from rest_framework.response import Response
from rest_framework.views import APIView
import hashlib
class WeChatSignatureView(APIView):
def get(self, request, *args, **kwargs):
received_signature = request.query_params.get("signature")
received_timestamp = request.query_params.get("timestamp")
received_nonce = request.query_params.get("nonce")
your_token = "your_token" # 替换为你的token
if self.check_signature(received_signature, received_timestamp, received_nonce, your_token):
echostr = request.query_params.get("echostr")
# 关键代码,虽然我指定了content_type但还是序列化了,没卵用
return Response(echostr, content_type="text/html; charset=utf-8")
else:
return Response("Invalid signature", status=403, content_type="text/plain")
def check_signature(self, signature, timestamp, nonce, token):
tmp_arr = [token, timestamp, nonce]
tmp_arr.sort()
tmp_str = ''.join(tmp_arr)
tmp_str = hashlib.sha1(tmp_str.encode()).hexdigest()
return tmp_str == signature
Se você deseja retornar o conteúdo HTML e precisa definir o tipo de conteúdo correto para text/html; charset=utf-8, você deve criar manualmente um objeto HttpResponse em vez de usar a resposta do DRF. Os seguintes são exemplos corretos:
from django.http import HttpResponse
def get(self, request):
received_signature = request.GET.get("signature")
received_timestamp = request.GET.get("timestamp")
received_nonce = request.GET.get("nonce")
yue_token = 'yueyue'
if self.check_signature(received_signature, received_timestamp, received_nonce, yue_token):
# 返回时用Django的HttpResponse就不会序列化,指定这个content_type就能起到作用
return HttpResponse(request.query_params.get("echostr"), content_type="text/html; charset=utf-8")
else:
return Response("Invalid signature", status=403)
def check_signature(self, signature, timestamp, nonce, token):
tmp_arr = [token, timestamp, nonce]
tmp_arr.sort()
tmp_str = ''.join(tmp_arr)
tmp_str = hashlib.sha1(tmp_str.encode()).hexdigest()
return tmp_str == signature
Finalmente acabou