与 Facebook 聊天连接时远程连接失败

Posted

技术标签:

【中文标题】与 Facebook 聊天连接时远程连接失败【英文标题】:remote-connection-failed when connecting with Facebook Chat 【发布时间】:2012-01-25 05:27:45 【问题描述】:

我正在尝试在我的 jQuery Mobile 上集成 Facebook Chat 并考虑关注

但是当我打开服务器(旁遮普语),并将以下必要的凭据放入与 facebook 相关的 javascript 中时,我收到 remote-connection-failed 错误 谁能告诉我缺少什么。

JID :          XXX@chat.facebook.com
PASSWORD:      <FacebookPassword>

传出和传入请求

  SENT:<body rid='1283282620' xmlns='http://jabber.org/protocol/httpbind' to='chat.facebook.com' xml:lang='en' wait='300' hold='1' content='text/xml; charset=utf-8' ver='1.6' xmpp:version='1.0' xmlns:xmpp='urn:xmpp:xbosh'/>

  RECV:<body xmlns='http://jabber.org/protocol/httpbind' type='terminate' condition='remote-connection-failed'/>

在 Windows XP 上启动服务器

Python twistd.py punjab

2012-01-26 10:41:45+0530 [-] Log opened.
2012-01-26 10:41:45+0530 [-] twistd 11.1.0 (C:\Python27\python.exe 2.7.2) starti
ng up.
2012-01-26 10:41:45+0530 [-] reactor class: twisted.internet.selectreactor.Selec
tReactor.
2012-01-26 10:41:45+0530 [-] Site starting on 5280
2012-01-26 10:41:45+0530 [-] Starting factory <twisted.web.server.Site instance
at 0x013A12B0>

当我点击 http://localhost:5280/http-bind 时,我得到 XEP-0124 - 波什

输入网址

http://localhost/strophejs/facebook-chat-example/facebook.html

facebook.html

<html>
<head>
<script src="http://connect.facebook.net/en_US/all.js" type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="strophe.min.js" type="text/javascript"></script>
<script src="facebook.js" type="text/javascript"></script>
<script>
var BOSH_SERVICE = 'http://localhost:5280/http-bind'
var connection = null;

function log(msg)

    $('#log').append('<div></div>').append(document.createTextNode(msg));


function rawInput(data)

    log('RECV: ' + data);


function rawOutput(data)

    log('SENT: ' + data);


function onConnect(status)

    if (status == Strophe.Status.CONNECTING) 
    log('Strophe is connecting.');
     else if (status == Strophe.Status.CONNFAIL) 
    log('Strophe failed to connect.');
    $('#connect').get(0).value = 'connect';
     else if (status == Strophe.Status.DISCONNECTING) 
    log('Strophe is disconnecting.');
     else if (status == Strophe.Status.DISCONNECTED) 
    log('Strophe is disconnected.');
    $('#connect').get(0).value = 'connect';
     else if (status == Strophe.Status.CONNECTED) 
    log('Strophe is connected.');
    connection.disconnect();
    


$(document).ready(function () 
    var access_token;
    FB.init(
            appId      : 'XXXXXXXXXXX',
            status     : true,
            cookie     : true,
            xfbml      : true,
            oauth      : true,
    );

    FB.login(function (response) 
        console.log(response);
        if (response.authResponse) 
            access_token = response.authResponse.accessToken;
            console.log(access_token);
         else 
            alert('User is logged out');
        
    ,scope: 'email,user_online_presence,friends_online_presence,xmpp_login');

    connection = new Strophe.Connection(BOSH_SERVICE);
    connection.rawInput = rawInput;
    connection.rawOutput = rawOutput;

    $('#connect').bind('click', function () 
    var button = $('#connect').get(0);
    if (button.value == 'connect') 
        button.value = 'disconnect';

        connection.facebookConnect($('#jid').get(0).value,
                    onConnect,
                    300,
                    1,
                    'XXXXXXXXXX' , /*app id*/
                    'XXXXXXXXXXXXXXXXXX',/*secret key*/
                    access_token);
     else 
        button.value = 'connect';
        connection.disconnect();
    
    );
);
</script>
</head>

<body>
<div id="fb-root"></div>
<div id='login' style='text-align: center'>
      <form name='cred'>
        <label for='jid'>JID:</label>
        <input type='text' id='jid'>
        <label for='pass'>Password:</label>
        <input type='password' id='pass'>
        <input type='button' id='connect' value='connect'>
      </form>
    </div>
    <hr>
    <div id='log'></div>
</body>
</html>

facebook.js

/*
    @author: Ruben J Garcia <rubenjgarciab@gmail.com>
    @version: 1.0

    This program is distributed under the terms of the MIT license.
    Please see the LICENSE file for details.

    Copyright 2006-2008, OGG, LLC
*/

/**
 * Split a string by string
 * @param delimiter string The boundary string.
 * @param string string The input string.
 * @param limit int[optional] If limit is set and positive, the returned array will contain
 *      a maximum of limit elements with the last
 *      element containing the rest of string.
 * 
 *      If the limit parameter is negative, all components
 *      except the last -limit are returned.
 * 
 *      If the limit parameter is zero, then this is treated as 1.
 * 
 * @returns array If delimiter is an empty string (""),
 *      explode will return false.
 *      If delimiter contains a value that is not
 *      contained in string and a negative
 *      limit is used, then an empty array will be
 *      returned. For any other limit, an array containing
 *      string will be returned.
 */
function explode(delimiter, string, limit) 
         var emptyArray =  0: '' ;

        // third argument is not required
        if ( arguments.length < 2 ||
            typeof arguments[0] == 'undefined' || typeof arguments[1] == 'undefined' ) 
            return null;
        

        if ( delimiter === '' || delimiter === false ||
            delimiter === null ) 
            return false;
        

        if ( typeof delimiter == 'function' || typeof delimiter == 'object' ||
            typeof string == 'function' || typeof string == 'object' ) 
                return emptyArray;    
        

        if ( delimiter === true ) 
            delimiter = '1';
          

        if (!limit) 
            return string.toString().split(delimiter.toString());
         else 
            // support for limit argument        
            var splitted = string.toString().split(delimiter.toString());
            var partA = splitted.splice(0, limit - 1);
            var partB = splitted.join(delimiter.toString());
            partA.push(partB);
            return partA;   
           
;

/**
 *  Handler for X-FACEBOOK-PLATFORM SASL authentication.
 *
 *  @param (XMLElement) elem - The challenge stanza.
 *
 *  @returns false to remove the handler.
 */
Strophe.Connection.prototype._sasl_challenge1_fb = function (elem)
    
        var challenge = Base64.decode(Strophe.getText(elem));
        var nonce = "";
        var method = "";
        var version = "";

        // remove unneeded handlers
        this.deleteHandler(this._sasl_failure_handler);

        var challenges = explode("&", challenge);
        for(i=0; i<challenges.length; i++) 
        
            map = explode("=", challenges[i]);
            switch (map[0]) 
            
                case "nonce":
                    nonce = map[1];
                    break;
                case "method":
                    method = map[1];
                    break;
                case "version":
                    version = map[1];
                    break;
          
        

        var responseText = "";

        responseText += 'api_key=' + this.apiKey;
        responseText += '&call_id=' + (Math.floor(new Date().getTime()/1000));
        responseText += '&method=' + method;
        responseText += '&nonce=' + nonce;
        responseText += '&access_token=' + this.sessionKey;
        responseText += '&v=' + '1.0';
        responseText += '&sig=' + MD5.hexdigest(responseText.replace(/&/g,"")+this.secretKey);

        this._sasl_challenge_handler = this._addSysHandler(
            this._sasl_challenge2_cb.bind(this), null,
            "challenge", null, null);
        this._sasl_success_handler = this._addSysHandler(
            this._sasl_success_cb.bind(this), null,
            "success", null, null);
        this._sasl_failure_handler = this._addSysHandler(
            this._sasl_failure_cb.bind(this), null,
            "failure", null, null);

        this.send($build('response', 
            xmlns: Strophe.NS.SASL
        ).t(Base64.encode(responseText)).tree());

        return false;
;

/**
 *  Handler for initial connection request with Facebokk.
 *
 *  This handler is used to process the initial connection request
 *  response from the BOSH server. It is used to set up authentication
 *  handlers and start the authentication process.
 *
 *  SASL authentication will be attempted if available, otherwise
 *  the code will fall back to legacy authentication.
 *
 *  @param (Strophe.Request) req - The current request.
 */
Strophe.Connection.prototype._connect_fb = function (req) 
        Strophe.info("_connect_fb was called");

        this.connected = true;
        var bodyWrap = req.getResponse();
        if (!bodyWrap)  return; 

        this.xmlInput(bodyWrap);
        this.rawInput(Strophe.serialize(bodyWrap));

        var typ = bodyWrap.getAttribute("type");
        var cond, conflict;
        if (typ !== null && typ == "terminate") 
            // an error occurred
            cond = bodyWrap.getAttribute("condition");
            conflict = bodyWrap.getElementsByTagName("conflict");
            if (cond !== null) 
                if (cond == "remote-stream-error" && conflict.length > 0) 
                    cond = "conflict";
                
                this._changeConnectStatus(Strophe.Status.CONNFAIL, cond);
             else 
                this._changeConnectStatus(Strophe.Status.CONNFAIL, "unknown");
            
            return;
        

        // check to make sure we don't overwrite these if _connect_fb is
        // called multiple times in the case of missing stream:features
        if (!this.sid) 
            this.sid = bodyWrap.getAttribute("sid");
        
        if (!this.stream_id) 
            this.stream_id = bodyWrap.getAttribute("authid");
        
        var wind = bodyWrap.getAttribute('requests');
        if (wind)  this.window = wind; 
        var hold = bodyWrap.getAttribute('hold');
        if (hold)  this.hold = hold; 
        var wait = bodyWrap.getAttribute('wait');
        if (wait)  this.wait = wait; 

        var mechanisms = bodyWrap.getElementsByTagName("mechanism");
        var i, mech, auth_str, hashed_auth_str, xfacebook;
        if (mechanisms.length == 0) 
            // we didn't get stream:features yet, so we need wait for it
            // by sending a blank poll request
            var body = this._buildBody();
            this._requests.push(
                new Strophe.Request(body.tree(),
                                    this._onRequestStateChange.bind(this)
                                      .prependArg(this._connect_cb.bind(this)),
                                    body.tree().getAttribute("rid")));
            this._throttledRequestHandler();
            return;
         else 
            for (i = 0; i < mechanisms.length; i++) 
                mech = Strophe.getText(mechanisms[i]);
                if (mech == 'X-FACEBOOK-PLATFORM') 
                    xfacebook = true;
                    break;
                
            
        

        if (!xfacebook) 
            return;
        

        this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);
        this._sasl_challenge_handler = this._addSysHandler(
            this._sasl_challenge1_fb.bind(this), null,
            "challenge", null, null);
        this._sasl_failure_handler = this._addSysHandler(
            this._sasl_challenge1_fb.bind(this), null,
            "failure", null, null);

        this.send($build("auth", 
            xmlns: Strophe.NS.SASL,
            mechanism: "X-FACEBOOK-PLATFORM"
        ).tree());
;

/**
 *  Starts the connection process with facebok XMPP Chat Server.
 *
 *  As the connection process proceeds, the user supplied callback will
 *  be triggered multiple times with status updates.  The callback
 *  should take two arguments - the status code and the error condition.
 *
 *  The status code will be one of the values in the Strophe.Status
 *  constants.  The error condition will be one of the conditions
 *  defined in RFC 3920 or the condition 'strophe-parsererror'.
 *
 *  Please see XEP 124 for a more detailed explanation of the optional
 *  parameters below.
 *
 *  @param (String) jid - The user's JID. It must be facebookid@chat.facebook.com,
 *      where facebook id is the number id of the facebook profile
 *  @param (Function) callback The connect callback function.
 *  @param (Integer) wait - The optional HTTPBIND wait value.  This is the
 *      time the server will wait before returning an empty result for
 *      a request.  The default setting of 60 seconds is recommended.
 *      Other settings will require tweaks to the Strophe.TIMEOUT value.
 *  @param (Integer) hold - The optional HTTPBIND hold value.  This is the
 *      number of connections the server will hold at one time.  This
 *      should almost always be set to 1 (the default).
 *  @param apiKey The API key of our Facebook Application
 *  @param secretKey The secret key of our Facebook Application
 *  @param sessionKey The actual session key for the user who we are attempting to log in
 */
Strophe.Connection.prototype.facebookConnect = function (jid, callback, wait, hold, apiKey, secretKey, sessionKey)
    this.jid = jid;
    this.connect_callback = callback;
    this.disconnecting = false;
    this.connected = false;
    this.authenticated = false;
    this.errors = 0;
    this.apiKey = apiKey;
    this.secretKey = secretKey;
    this.sessionKey = sessionKey;

    this.wait = wait || this.wait;
    this.hold = hold || this.hold;

    // parse jid for domain and resource
    this.domain = Strophe.getDomainFromJid(this.jid);

    // build the body tag
    var body = this._buildBody().attrs(
        to: this.domain,
        "xml:lang": "en",
        wait: this.wait,
        hold: this.hold,
        content: "text/xml; charset=utf-8",
        ver: "1.6",
        "xmpp:version": "1.0",
        "xmlns:xmpp": Strophe.NS.BOSH
    );

    this._changeConnectStatus(Strophe.Status.CONNECTING, null);

    this._requests.push(
        new Strophe.Request(body.tree(),
                            this._onRequestStateChange.bind(
                            this, this._connect_fb.bind(this)),
                             body.tree().getAttribute("rid")));
    this._throttledRequestHandler();
;

请有人建议我集成 Facebook 聊天的正确方法

【问题讨论】:

【参考方案1】:

这是一个非常古老的问题,但我只是遇到了同样的问题,并发布此问题以防万一有人遇到同样的问题。

我还没有安装 pyopenssl,安装它立即解决了问题。

【讨论】:

是的,正如 HyperGeek 提到的,安装 pyopenssl 为我修复了它!【参考方案2】:

你需要检查几件事:

punjab 返回的错误是远程连接失败。这意味着它无法打开与 chat.facebook.com 的连接。您的旁遮普语日志似乎不匹配,因为您没有尝试连接到 Facebook。 您可能会遇到跨域问题,这可能是您的客户端无法连接到旁遮普邦的原因。旁遮普在端口 5280 上运行,而您的客户端在端口 80 上提供服务。这是不同的服务,您的浏览器可能会阻止从端口 80 上提供服务的客户端连接回端口 5280。检查您的 Javascript 浏览器日志。我预计那里会出现错误。 Facebook 在使用代理时不支持标准身份验证。您将需要一个支持 X-FACEBOOK-PLATFORM SASL 身份验证机制的库。见:http://developers.facebook.com/docs/chat/

【讨论】:

我只需要旁遮普语还是我也需要ejabberd?

以上是关于与 Facebook 聊天连接时远程连接失败的主要内容,如果未能解决你的问题,请参考以下文章

SQLServer远程连接失败怎么办

云服务器远程连接不上,云服务器远程连接失败是啥原因?

mac下怎么解决连接失败

C#远程连接不上SQL2000,error:40

连接失败 错误为651 已拒绝远程链接

SQL Server 2008/2014无法远程连接的可能原因之一