Ошибка рукопожатия WebSocket (неверный запрос) в Opera 12

В настоящее время я начинаю работу над своей бакалаврской диссертацией и недавно начал «копаться» в использовании node.js и webSocket. Мой сервер webSocket работает без проблем при доступе в Firefox 15.0 и Chrome 21.0.1180.89 м. В Опере 12.02 похоже проблема с хендшейком клиент-сервер. Вот что пишет консоль ошибок Opera:

[31.08.2012 01:03:51] WebSockets - http://10.0.0.2/
Connection
WebSocket handshake failure, invalid response code '400'.

Забавно: я нигде не могу найти эту ошибку в сетевом журнале консоли Dragonfly. Все поля, которые запрашиваются при доступе к веб-сайту (index.html, client.js и т. д.), найдены и обслуживаются должным образом (код состояния HTTP 200 OK). Кроме того, единственными кодами состояния, которые возвращает мой сервер, являются 200, 404 и 500, так что это выглядит так, как будто это исходит из самого webSocket.

И да, webSocket IS включен в Opera... Я понятия не имею, в чем может быть проблема

Любая помощь могла бы быть полезна :)

РЕДАКТИРОВАТЬ: Пока это мой код, чтобы вы могли видеть, какие заголовки отправляет мой сервер и как я создаю соединения webSocket с моим client.js:

сервер.js:

// load required modules:
var http = require("http");
var WebSocketServer = require("websocket").server;
path = require("path");
url = require("url");
filesys = require("fs");

// declare listening port vars:
var httpListeningPort = 80;
var webSocketListeningPort = 80;

// create HTTP-server:
var httpSrv = http.createServer(function(request, response) {
    console.log((new Date()) + ":\tReceived request for " + request.url);
//  response.writeHead(200);
//  response.end();
    var myPath = url.parse(request.url).pathname;
    var fullPath = path.join(process.cwd(), myPath);
    if(myPath === "/") {
        fullPath += "index.html";
        console.log("Full path:\t" + fullPath);
        filesys.readFile(fullPath, "binary", function(err, file) {
            if(err) {
                response.writeHeader(500, {"Content-Type": "text/plain"});
                response.write(err + "\n");
                response.end();
            }
            else {
                response.writeHeader(200);
                response.write(file, "binary");
                response.end();
            }
        });
    }
    else {
        path.exists(fullPath, function(exists) {
        if(!exists) {
            response.writeHeader(404, {"Content-Type": "text/plain"});
            response.write("404 Not Found\n");
            response.end();
        }
        else {
            filesys.readFile(fullPath, "binary", function(err, file) {
                if(err) {
                    response.writeHeader(500, {"Content-Type": "text/plain"});
                    response.write(err + "\n");
                    response.end();
                }
                else {
                    response.writeHeader(200);
                    response.write(file, "binary");
                    response.end();
                }
            });
        }
        });
    }   
});
httpSrv.listen(httpListeningPort, function() {
    console.log((new Date()) + ":\tServer is now listening on port " + httpListeningPort);
});

// create webSocket server and tie it to the http server:
wsServer = new WebSocketServer({
    httpServer: httpSrv
});

function originChecker(origin) {
    if(origin) {
        console.log("Origin " + origin + " is allowed");
        return true;
    } else {
        console.log("origin is NOT allowed.");
        return false;
    }
}

// how to handle requests:
wsServer.on("request", function(request) {
    // check whether origin is allowed or not:
    if(originChecker(request.origin) === false) {
        request.reject();
        console.log((new Date()) + ":\tConnection request from origin " + request.origin + " rejected.");
        return;
    }

    // accept the connecteion request -> open the connection:
    var connection = request.accept(null, request.origin);
    console.log((new Date()) + ":\tConnection request from " + request.origin + " accepted.");

    // handle incoming messages from the clients:
    connection.on("message", function(message) {
        if(message.type === "utf8") {
            console.log((new Date()) + ":\tReceived message from " + request.origin + ":\nType: " + message.type + "\nLength: " + message.utf8Data.length + "\nMessage: " + message.utf8Data);
            // echo "Message received":
            connection.sendUTF(JSON.stringify( { type: "message", data: "Message received !" } ));
        } else {
            // send error message back to client:
            console.log((new Date()) + ":\tReceived message from " + request.origin + ":\nERROR:\tMessage is NOT UTF-8! it's " + message.type);
            connection.sendUTF(JSON.stringify( { type: "message", data: "ONLY UTF-8 accepted !" } ));
        }
    });

    // what to do when connection is closed:
    connection.on("close", function() {
        console.log((new Date()) + ":\tClient @" + connection.remoteAddress + " disconnected.");
    });
});

клиент.js:

function client() {

    if("WebSocket" in window) {
        alert("WebSocket is supported by your browser!");

        // try to connect to the webSocket server:
        var connection = null;
        connection = new WebSocket("ws://10.0.0.2:80");

        // things to do once the connection is opened:
        connection.onopen = function() {
            alert("INFO:\tConnection to server is OPEN");

            document.getElementById("msgInput").focus();
            document.getElementById("msgInput").disabled = false;
            document.getElementById("msgInput").value = "";

            document.getElementById("msgInput").onkeyup = function(key) {
                switch(key.keyCode) {
                    case 13:    if(document.getElementById("msgInput").value === "") { 
                                break;
                                }
                                var messageText = document.getElementById("msgInput").value;
                                document.getElementById("msgInput").disabled = true;
                                document.getElementById("msgInput").value = "";
                                document.getElementById("statusHeader").innerHTML = "Sending...";
                                connection.send(messageText);
                    break;
                    default: document.getElementById("statusHeader").innerHTML = "Press ENTER to send!";
                }
            };
        };

        connection.onerror = function(error) {
            document.body.style.backgroundColor = "#220000";
            document.body.style.color = "#aa0000";
            document.getElementById("statusHeader").innerHTML = "ERROR connecting to server -> OFFLINE";
            return;
        };

        connection.onmessage = function(message) {
            try {
                var json = JSON.parse(message.data);
            } catch (error) {
                alert("ERROR parsing message:\t" + error);
                return;
            }

            document.getElementById("statusHeader").innerHTML = json.data;
            document.getElementById("msgInput").disabled = false;
        };

        connection.onclose = function() {
            setTimeout(function() { 
            document.body.style.backgroundColor = "#808080";
            document.body.style.color = "#ffffff";
            document.getElementById("statusHeader").innerHTML = "OFFLINE";
            document.getElementById("msgInput").disabled = true;
            document.getElementById("msgInput").value = "OFFLINE";
            }, 5000);
            return;
        };
    } else {
        alert("WebSocket is NOT supported by your browser! Exiting now.");
        return;
    }   
};

person slagjoeyoco    schedule 30.08.2012    source источник
comment
Можете ли вы предоставить дополнительную информацию: какой сервер вы используете? Какой javascript вы используете для создания соединения? Какие заголовки возвращает ваш сервер в случае неудачного рукопожатия?   -  person simonc    schedule 31.08.2012
comment
Привет, simonc, я отредактировал свой вопрос и добавил исходный код моего серверного и клиентского скриптов. Как вы можете видеть, мой сервер atm пока специально не обрабатывает плохие рукопожатия - единственные заголовки, которые я отправляю, это 404, если URI запроса не найден, 500, если есть ошибка при открытии запрошенного файла (например, отсутствующие права доступа к файлу и т. д. ) и 200, если все пойдет хорошо. Мне просто кажется странным, что доступ к серверу работает плавно в Firefox и Chrome, но в Opera я получаю неверный запрос из-за сбоев рукопожатия, что не имеет для меня особого смысла. Что вы имеете в виду, с каким JS я использую?   -  person slagjoeyoco    schedule 31.08.2012
comment
Спасибо. Я только что заметил этот предыдущий вопрос SO, в котором утверждается, что Opera 12 поддерживает только старую, устаревшую версию веб-сокетов. Можете ли вы пока использовать другие браузеры и снова протестировать Opera, когда она будет обновлена?   -  person simonc    schedule 31.08.2012
comment
Я также видел этот вопрос, но он, похоже, описывал другую ошибку. Я не думал, что Opera поддерживает старую версию протокола. Но теперь я также обнаружил, что между более старыми версиями ebSockets и официальной версией RFC существует много проблем. Кроме того, когда уже ЕСТЬ RFC 6455... Я уж точно не буду работать над поддержкой устаревших версий :). Я в порядке, придерживаясь Firefox и Chrome на данный момент. Надеюсь, Opera будет поддерживать версию RFC в грядущем обновлении, и, насколько я слышал, IE 10 тоже будет. Спасибо за вашу помощь, я ценю это.   -  person slagjoeyoco    schedule 31.08.2012
comment
Есть ли способ пометить мой вопрос как РЕШЕННЫЙ или что-то в этом роде?   -  person slagjoeyoco    schedule 31.08.2012
comment
Пожалуйста, опубликуйте свой ответ ниже и примите его, поставив галочку слева.   -  person pimvdb    schedule 01.09.2012
comment
Я повторно опубликовал свой комментарий в качестве ответа. Как предложил pimvdb, вы можете принять его, щелкнув контур галочки слева от него.   -  person simonc    schedule 01.09.2012


Ответы (1)


Согласно недавнему вопросу, Opera 12 поддерживает более старую, несовместимую версию веб-сокеты. В этой версии (Hixie-76) в рукопожатии используется другой набор заголовков. Ваш сервер, по-видимому, не понимает их, что объясняет его ответ с ошибкой 400.

Если вы можете позволить себе подождать, пока Opera догонит вас, самым простым «решением» будет использование других браузеров для тестирования. Черновики протокола Hixie устарели, поэтому в конечном итоге Opera обязательно обновится до RFC 6455.

person simonc    schedule 31.08.2012