socket.io,webrtc,nodejs视频聊天应用程序通过https获取错误:ERR_SSL_PROTOCOL_ERROR,404(未找到)和ERR_CONNECTION_TIMED_OUT

时间:2016-11-17 15:54:35

标签: node.js iis socket.io webrtc windows-server-2012

我已经使用来自github的这个online tutorial的socket.io,webrtc,nodejs组建了一个视频聊天应用程序,但现在我在转换它时通过https使用时出错:

Request URL:https://telemed.caduceususa.com/socket.io/?EIO=3&transport=polling&t=1479396416422-0
Request Method:GET
Status Code:404 Not Found
Remote Address:10.9.2.169:443

我在此过程中遇到的其他错误如下:

当我尝试声明一个不同的PORT时,我得到了 - ERR_SSL_PROTOCOL_ERROR,

当我尝试声明端口80或8080时,我得到:ERR_CONNECTION_TIMED_OUT

socket.io.js中的这一行出了问题:

xhr.send(this.data);

我正在Windows Server 2012上运行node.js服务器,我已经设置了IIS来为PORT 80上的服务器提供服务。我在DNS中创建了子域https://telemed.caduceususa.com,并购买了一个受信任的SSL证书通过HTTPS运行网站。

以下是开发工具代码的摘录,其中包含导致错误的上述行以及我的其他代码:

/**
 * Creates the XHR object and sends the request.
 *
 * @api private
 */

Request.prototype.create = function(){
  var opts = { agent: this.agent, xdomain: this.xd, xscheme: this.xs, enablesXDR: this.enablesXDR };

  // SSL options for Node.js client
  opts.pfx = this.pfx;
  opts.key = this.key;
  opts.passphrase = this.passphrase;
  opts.cert = this.cert;
  opts.ca = this.ca;
  opts.ciphers = this.ciphers;
  opts.rejectUnauthorized = this.rejectUnauthorized;

  var xhr = this.xhr = new XMLHttpRequest(opts);
  var self = this;

  try {
    debug('xhr open %s: %s', this.method, this.uri);
    xhr.open(this.method, this.uri, this.async);
    if (this.supportsBinary) {
      // This has to be done after open because Firefox is stupid
      // https://stackoverflow.com/questions/13216903/get-binary-data-with-xmlhttprequest-in-a-firefox-extension
      xhr.responseType = 'arraybuffer';
    }

    if ('POST' == this.method) {
      try {
        if (this.isBinary) {
          xhr.setRequestHeader('Content-type', 'application/octet-stream');
        } else {
          xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
        }
      } catch (e) {}
    }

    // ie6 check
    if ('withCredentials' in xhr) {
      xhr.withCredentials = true;
    }

    if (this.hasXDR()) {
      xhr.onload = function(){
        self.onLoad();
      };
      xhr.onerror = function(){
        self.onError(xhr.responseText);
      };
    } else {
      xhr.onreadystatechange = function(){
        if (4 != xhr.readyState) return;
        if (200 == xhr.status || 1223 == xhr.status) {
          self.onLoad();
        } else {
          // make sure the `error` event handler that's user-set
          // does not throw in the same tick and gets caught here
          setTimeout(function(){
            self.onError(xhr.status);
          }, 0);
        }
      };
    }

    debug('xhr data %s', this.data);
    xhr.send(this.data);
  }

这是server.js文件:

var fs = require('fs');

var hskey = fs.readFileSync('ssl/telemed_internal_server.key');
var hscert = fs.readFileSync('ssl/telemed_internal_cert.pem');
var ca = fs.readFileSync('ssl/telemed_internal_key.pem');

var credentials = {
    ca: ca,
    key: hskey,
    cert: hscert
};

var static = require('node-static');
var https = require('https');
var util = require('util');
var file = new(static.Server)();
var app = https.createServer(credentials, function (req, res) {
  file.serve(req, res);
}).listen(process.env.PORT || 80);

var io = require('socket.io').listen(app);

io.sockets.on('connection', function (socket){

  // convenience function to log server messages on the client
    function log(){
        var array = [">>> Message from server: "];
      for (var i = 0; i < arguments.length; i++) {
        array.push(arguments[i]);
      }
        socket.emit('log', array);
    }

    // when receive sdp, broadcast sdp to other user
    socket.on('sdp', function(data){
        console.log('Received SDP from ' + socket.id);
        socket.to(data.room).emit('sdp received', data.sdp);
    });

    // when receive ice candidate, broadcast sdp to other user
    socket.on('ice candidate', function(data){
        console.log('Received ICE candidate from ' + socket.id + ' ' + data.candidate);
        socket.to(data.room).emit('ice candidate received', data.candidate);
    });

    socket.on('message', function (message) {
        log('Got message:', message);
    // for a real app, would be room only (not broadcast)
        socket.broadcast.emit('message', message);
    });

    socket.on('create or join', function (room) {
        // join room
        var existingRoom = io.sockets.adapter.rooms[room];
        var clients = [];

        if(existingRoom){
            clients = Object.keys(existingRoom);
        }

        if(clients.length == 0){
            socket.join(room);
            io.to(room).emit('empty', room);
        }
        else if(clients.length == 1){
            socket.join(room);
            socket.to(room).emit('joined', room, clients.length + 1);
        }
        // only allow 2 users max per room
        else{
            socket.emit('full', room);
        }
    });

    socket.on('error', function(error){
        console.error(error);
    })

});

这是main.js(config)文件:

//my signalling server
var serverIP = "https://telemed.caduceususa.com/";

// RTCPeerConnection Options
var server = {
    // Uses Google's STUN server
    iceServers: [{
        "url": "stun:stun4.l.google.com:19302"
    }, 
    {
        url: 'turn:numb.viagenie.ca',
        credential: 'muazkh',
        username: 'webrtc@live.com'
    }]
};
// various other development IPs
// var serverIP = "https://192.168.43.241:2013";
// var serverIP = "https://10.0.11.196:2013";

var localPeerConnection, signallingServer;

var btnSend = document.getElementById('btn-send');
var btnVideoStop = document.getElementById('btn-video-stop');
var btnVideoStart = document.getElementById('btn-video-start');
var btnVideoJoin = document.getElementById('btn-video-join');
var localVideo = document.getElementById('local-video');
var remoteVideo = document.getElementById('remote-video');

var inputRoomName = document.getElementById('room-name');

var localStream, localIsCaller;

btnVideoStop.onclick = function(e) {
    e.preventDefault();
    // stop video stream
    if (localStream != null) {
        localStream.stop();
    }

    // kill all connections
    if (localPeerConnection != null) {
        localPeerConnection.removeStream(localStream);
        localPeerConnection.close();
        signallingServer.close();
        localVideo.src = "";
        remoteVideo.src = "";
    }

    btnVideoStart.disabled = false;
    btnVideoJoin.disabled = false;
    btnVideoStop.disabled = true;
}

btnVideoStart.onclick = function(e) {
    e.preventDefault();
    // is starting the call
    localIsCaller = true;
    initConnection();
}

btnVideoJoin.onclick = function(e) {
    e.preventDefault();
    // just joining a call, not offering
    localIsCaller = false;
    initConnection();
}

function initConnection() {
    var room = inputRoomName.value;

    if (room == undefined || room.length <= 0) {
        alert('Please enter room name');
        return;
    }

    // start connection!
    connect(room);

    btnVideoStart.disabled = true;
    btnVideoJoin.disabled = true;
    btnVideoStop.disabled = false;
}


// WEBRTC STUFF STARTS HERE
// Set objects as most are currently prefixed
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection ||
    window.webkitRTCPeerConnection || window.msRTCPeerConnection;
window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription ||
    window.webkitRTCSessionDescription || window.msRTCSessionDescription;
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia ||
    navigator.webkitGetUserMedia || navigator.msGetUserMedia;
window.SignallingServer = window.SignallingServer;

var sdpConstraints = {
    optional: [],
    mandatory: {
        OfferToReceiveVideo: true,
    }
}

function connect(room) {
    // create peer connection
    localPeerConnection = new RTCPeerConnection(server);

    // create local data channel, send it to remote
    navigator.getUserMedia({
        video: true,
        audio: true
    }, function(stream) {
        // get and save local stream
        trace('Got stream, saving it now and starting RTC conn');

        // must add before calling setRemoteDescription() because then 
        // it triggers 'addstream' event
        localPeerConnection.addStream(stream);
        localStream = stream;

        // show local video
        localVideo.src = window.URL.createObjectURL(stream);

        // can start once have gotten local video
        establishRTCConnection(room);

    }, errorHandler)
}

function establishRTCConnection(room) {
    // create signalling server
    signallingServer = new SignallingServer(room, serverIP);
    signallingServer.connect();


    // a remote peer has joined room, initiate sdp exchange
    signallingServer.onGuestJoined = function() {
        trace('guest joined!')
        // set local description and send to remote
        localPeerConnection.createOffer(function(sessionDescription) {
            trace('set local session desc with offer');

            localPeerConnection.setLocalDescription(sessionDescription);

            // send local sdp to remote
            signallingServer.sendSDP(sessionDescription);
        });
    }

    // got sdp from remote
    signallingServer.onReceiveSdp = function(sdp) {
        // get stream again
        localPeerConnection.addStream(localStream);
        trace(localStream)

        // if local was the caller, set remote desc
        if (localIsCaller) {
            trace('is caller');
            trace('set remote session desc with answer');
            localPeerConnection.setRemoteDescription(new RTCSessionDescription(
                sdp));
        }
        // if local is joining a call, set remote sdp and create answer
        else {
            trace('set remote session desc with offer');
            localPeerConnection.setRemoteDescription(new RTCSessionDescription(
                sdp), function() {
                trace('make answer')
                localPeerConnection.createAnswer(function(
                    sessionDescription) {
                    // set local description
                    trace('set local session desc with answer');
                    localPeerConnection.setLocalDescription(
                        sessionDescription);

                    // send local sdp to remote too
                    signallingServer.sendSDP(sessionDescription);
                });
            });
        }
    }

    // when received ICE candidate
    signallingServer.onReceiveICECandidate = function(candidate) {
        trace('Set remote ice candidate');
        localPeerConnection.addIceCandidate(new RTCIceCandidate(candidate));
    }

    // when room is full, alert user
    signallingServer.onRoomFull = function(room) {
        window.alert('Room "' + room +
            '"" is full! Please join or create another room');
    }

    // get ice candidates and send them over
    // wont get called unless SDP has been exchanged
    localPeerConnection.onicecandidate = function(event) {
        if (event.candidate) {
            //!!! send ice candidate over via signalling channel
            trace("Sending candidate");
            signallingServer.sendICECandidate(event.candidate);
        }
    }

    // when stream is added to connection, put it in video src
    localPeerConnection.onaddstream = function(data) {
        remoteVideo.src = window.URL.createObjectURL(data.stream);
    }

}

function errorHandler(error) {
    console.error('Something went wrong!');
    console.error(error);
}

function trace(text) {
    console.info(text);
}

这是信令服务器:

function trace(text){
    console.info(text);
}

// Connects to signalling server with given room and IP
// has methods to exchange SDP and ICE candidates

var SignallingServer = function(room, socketServer){
    this.room = room;
    this.socket = io.connect(socketServer);
    this.socket.on('full', function (room){
      trace('Room ' + room + ' is full');
      this.onRoomFull(room);
    }.bind(this));

    this.socket.on('empty', function (room){
      this.isInitiator = true;
      trace('Room ' + room + ' is empty');
    });

    this.socket.on('join', function (room){
      trace('Making request to join room ' + room);
    });

    this.socket.on('joined', function (room, numClients){
      trace('New user has joined ' + room);
      trace('Room has ' + numClients + ' clients');
      //ask host to initiate sdp transfer
      this.onGuestJoined();
    }.bind(this));

    this.socket.on('sdp received', function(sdp){
        trace('Received SDP ');
        trace(sdp);
        this.onReceiveSdp(sdp);
    }.bind(this));

    this.socket.on('ice candidate received', function(candidate){
        trace('Received ICE candidate ');
        trace(candidate);
        this.onReceiveICECandidate(candidate);
    }.bind(this));

    this.socket.on('log', function (array){
      console.log.apply(console, array);
    });
}

SignallingServer.prototype = {
    connect: function(){
        if (this.room !== '') {
          trace('Joining room ' + this.room);
          this.socket.emit('create or join', this.room);
        }
    },
    close: function(){
        trace('Disconnecting')
        this.socket.disconnect();
    },
    sendSDP: function(sdp){
        trace('sending sdp')
        this.socket.emit('sdp', {
            room: this.room,
            sdp: sdp
        });
    },
    sendICECandidate: function(candidate){
        trace('sending ice candidate');
        this.socket.emit('ice candidate', {
            room: this.room,
            candidate: candidate
        });
    },
    onReceiveSdp: function(sdp){
        trace('Placeholder function: Received SDP')
    },
    onGuestJoined: function(){
        trace('Placeholder function: Guest joined room')
    },
    onReceiveICECandidate: function(candidate){
        trace('Placeholder function: Received ICE candidate')
    },
    onRoomFull: function(room){
        trace('Placeholder function: Room is full!');
    }
}

window.SignallingServer = SignallingServer;

最后是HTML(也可以解释一下LIVERELOAD.JS是什么?):

<!doctype html>
<!--[if lt IE 7]>
<html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="">
  <![endif]-->
  <!--[if IE 7]>
  <html class="no-js lt-ie9 lt-ie8" lang="">
    <![endif]-->
    <!--[if IE 8]>
    <html class="no-js lt-ie9" lang="">
      <![endif]-->
      <!--[if gt IE 8]>
      <!-->
      <html class="no-js" lang="">
        <!--<![endif]-->
<head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <link rel="stylesheet" href="css/bootstrap.min.css">
        <style>
            body {
                padding-top: 50px;
                padding-bottom: 20px;
            }
        </style>
        <link rel="stylesheet" href="css/bootstrap-theme.min.css">
        <link rel="stylesheet" href="css/main.css">

        <script src="js/vendor/modernizr-2.8.3-respond-1.4.2.min.js"></script>
</head>
<body>
        <!--[if lt IE 8]>
        <p class="browserupgrade">
          You are using an <strong>outdated</strong>
          browser. Please
          <a href="https://browsehappy.com/">upgrade your browser</a>
          to improve your experience.
        </p>
        <![endif]-->
        <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
          <div class="container">
            <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false">
              <span class="sr-only">Toggle navigation</span>
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
            </button>
              <a class="navbar-brand" href="#">WebRTC Video Chat</a>
            </div>
            <div id="navbar" class="navbar-collapse collapse">
              <!-- chatroom name form -->
              <form class="navbar-form navbar-right form-inline">
                <div class="form-group">
                  <input class="form-control" type="text" id="room-name" placeholder="Room name"/>
                </div>
                <button class="btn btn-primary" id="btn-video-start">Start</button>
                <button class="btn btn-default"  id="btn-video-join">Join</button>
                <button class="btn btn-default"  disabled id="btn-video-stop">Stop</button>
              </form>
            </div>

            <!--/.navbar-collapse --> </div>

        </nav>

        <div class="container main">
          <div class="row videos">
            <div class="remote-video">
              <video width="280" height="250" autoplay id="remote-video"></video>
            </div>
            <div class="local-video">
              <video width="280" height="250" autoplay id="local-video" muted></video>
            </div>
          </div>
        </div>
      </div>
      <!-- /container -->
      <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
      <script>window.jQuery || document.write('<script src="js/vendor/jquery-1.11.2.min.js"><\/script>')</script>

    <script src="js/vendor/bootstrap.min.js"></script>
    <script src="js/vendor/socket.io.js"></script>

    <script src="js/main.js"></script>
    <script src="js/signalling.js"></script>

    <script src="//localhost:9010/livereload.js"></script>

</body>
  </html>

0 个答案:

没有答案