Search code examples
xmlwechat

Wechat Receive Message API Not Sending XML?


I'm not sure if this is a problem on Wechat's end, or whether they have changed their API. We have an endpoint that is correctly responding to the WeChat endpoint verification (echoing the echostr), and we are also receiving POST messages whenever we receive a new message.

The problem is that the POST message we're getting when our account receives a message doesn't have any XML content in it. It sends everything else (signature, nonce, etc), but no message XML.

Did we do something wrong? Did the API change? Are we not hand-shaking them properly?


Solution

  • XML data is sent in raw HTTP request body.

    The raw HTTP request body as a byte string. This is useful for processing data in different ways than conventional HTML forms: binary images, XML payload etc.

    This is the request sent from Wechat to my Django server:

    GET:<QueryDict: {u'nonce': [u'886****76'], u'timestamp': [u'1440041636'], u'signature': [u'29cb245a0f9399*******33956c3e96c500c56']}>, 
    POST:<QueryDict: {}>,
    

    request.POST is empty, which means it's not conventional form data.

    This is how I handle POST message from Wechat on Django: Use request.read().

    @csrf_exempt
    def weixin(request):
        logger.debug(request)
        token = #YOUR TOKEN
        if not validate(request.GET['signature'],request.GET['timestamp'],request.GET['nonce'],token):
            return Http404('')
    
        if request.method == 'GET':
            echo_str = request.GET['echostr']
            if echo_str != None:
                return HttpResponse(echo_str)
            else:
                return Http404('')
    
        elif request.method == 'POST':
            reply_str = reply(request.read())
            return HttpResponse(reply_str)
    
        return Http404('')
    
    
    def validate(signature, timestamp, nonce, token):
    
        if signature == None or timestamp == None or nonce == None or token == None:
            return False
    
        seq = sorted([token, timestamp, nonce])
        logger.debug(seq)
    
        tmp_str = ''.join(seq)
        encode_str = hashlib.sha1(tmp_str).hexdigest()
        logger.debug(encode_str)
    
        if signature == encode_str:
            return True
        else:
            return False
    

    PHP code which I have not verified. Get DATA from $GLOBALS["HTTP_RAW_POST_DATA"].

    public function responseMsg()
        {
            $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
    
            if (!empty($postStr)){
                $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                $fromUsername = $postObj->FromUserName;
                $toUsername = $postObj->ToUserName;
                $keyword = trim($postObj->Content);
                $time = time();
                $textTpl = "<xml>
                            <ToUserName><![CDATA[%s]]></ToUserName>
                            <FromUserName><![CDATA[%s]]></FromUserName>
                            <CreateTime>%s</CreateTime>
                            <MsgType><![CDATA[%s]]></MsgType>
                            <Content><![CDATA[%s]]></Content>
                            <FuncFlag>0</FuncFlag>
                            </xml>";
                if($keyword == "?" || $keyword == "?")
                {
                    $msgType = "text";
                    $contentStr = date("Y-m-d H:i:s",time());
                    $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
                    echo $resultStr;
                }
            }else{
                echo "";
                exit;
            }
        }