swooletw / laravel-swoole

High performance HTTP server based on Swoole. Speed up your Laravel or Lumen applications.
MIT License
4.04k stars 390 forks source link

WebSocket client got redundant number in message event data #459

Open ft525 opened 3 years ago

ft525 commented 3 years ago
  1. Please provide your PHP and Swoole version. (php -v and php --ri swoole) PHP Version 7.3.16 swoole 4.5.7

  2. Please provide your Laravel/Lumen version. laravel v5.5.48

  3. Which release version of this package are you using? swooletw/laravel-swoole v2.6.68

  4. What did you do? If possible, provide a recipe for reproducing the error.

    // Server
    Websocket::on('connect', function ($websocket, Request $request) {
    // called while socket on connect
    $websocket->emit('message', 'Welcome ~');
    });
// Client
var ws = new WebSocket("ws://example.com");
ws.onmessage = function (event) {
    console.log(event);
};
  1. What did you expect to see? The correct format of response. ex. json、array

  2. What did you see instead?

    /*
    There is a redundant number in event data.
    Is it normal?
    */
    MessageEvent {isTrusted: true, data: "0{"sid":"NWZkOWIxMWFiNjg3NQ==","upgrades":[],"pingInterval":25000,"pingTimeout":60000}", ...}
    MessageEvent {isTrusted: true, data: "40", ...}
    MessageEvent {isTrusted: true, data: "42["message","Welcome ~"]", ...}
Arkanius commented 3 years ago

Well, I never see this before 👀

Have you tried with newer versions of Laravel?

ft525 commented 3 years ago

Well, I never see this before 👀

Have you tried with newer versions of Laravel?

Not yet, but I'll try when I'm free.

Arkanius commented 3 years ago

Thanks for your help!

ft525 commented 3 years ago

Thanks for your help!

I tried, still the same. These are I installed version

PHP Version 7.3.12 Swoole Version 4.5.10 Laravel Version 8.20.1

swooletw/laravel-swoole v2.6.68

solaz3 commented 3 years ago

you should use a client with a socket.io implemention, socket.io-client, as the ws server is compatible with socket.io 2.x by default

ft525 commented 3 years ago

you should use a client with a socket.io implemention, socket.io-client, as the ws server is compatible with socket.io 2.x by default

OK, I'll try it later.

ft525 commented 3 years ago

you should use a client with a socket.io implemention, socket.io-client, as the ws server is compatible with socket.io 2.x by default

I tried and blocked by CORS policy. I don't know how to set swoole WebSocket CORS setting. : (

Arkanius commented 3 years ago

Try to run a nginx server in front of your swoole. Take a look at this exemple.

You should avoid use the header() funcion of php directly when using swoole because it's just ignored by swoole as mentioned here

Arkanius commented 3 years ago

Are you using a socket.io client as said before?

ft525 commented 3 years ago

I tried all I can do. middleware、nginx、your example all failed. : (

solaz3 commented 3 years ago

I tried all I can do. middleware、nginx、your example all failed. : (

Hi, @ft525 there are several ways to resolve cors problems, you can either use a package called laravel-cors or add clips in nginx which is more effective, here is the full example:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}
server {
    listen 80;
    server_name your.domain.com;
    root /path/to/laravel/public;
    index index.php;

    location = /index.php {
        # Ensure that there is no such file named "not_exists"
        # in your "public" directory.
        try_files /not_exists @swoole;
    }

    # any php files must not be accessed
    #location ~* \.php$ {
    #    return 404;
    #}
    location / {
        try_files $uri $uri/ @swoole;
    }

    location @swoole {
        # cors begin
        add_header Access-Control-Allow-Origin $http_origin always; 
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS always;
        add_header Access-Control-Allow-Credentials true always;
        add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,x-auth-token always;
        add_header Access-Control-Max-Age 1728000 always;

        # preflight request return 204
        if ($request_method = OPTIONS) {
                return 204;
        }
        # end of cors

        set $suffix "";

        if ($uri = /index.php) {
            set $suffix ?$query_string;
        }

        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        # IF https
        # proxy_set_header HTTPS "on";

        proxy_pass http://127.0.0.1:1215$suffix;
    }
}
solaz3 commented 3 years ago

Additional, here is a online socket.io client tool for debugging.

Arkanius commented 3 years ago

As @solaz3 said, you should inject the headers directly in your nginx before getting them in your code

ft525 commented 3 years ago

OK, I tried. It does work. But I can't receive message event and custom event. I just saw "Connected." msg.

// server
Websocket::on('connect', function ($websocket, Request $request) {
    // called while socket on connect
    $websocket->emit('hello', 'Hello ~');
    $websocket->emit('message', 'Welcome ~');
});
/*
    client (socket.io v2.4)

    // Docs
    https://socket.io/docs/v2/client-api/#socket-on-eventName-callback
*/
socket.on("connect", function () {
    console.log("Connected.");
});

socket.on("message", function (msg) {
    console.log("On message.", msg);
});

socket.on("hello", function (arg) {
    console.log("On hello.", arg);
});
solaz3 commented 3 years ago

add a disconnect event to socket to check if disconnected immediately after connected. Or use socket.io client tool which is simple and powerful.

ft525 commented 3 years ago

It is still connected till I disconnect it. I'll try socket.io client tool when I am free. thx~

ft525 commented 3 years ago

I found the problem. When I added the option (see below), It did work correctly Summary

  1. It should use socket.io client v2.x
  2. Connection options should add "transports" setting
// client
socket = new io("ws://xxx", {
    transports: ["websocket"],  // default is ["polling", "websocket"]
});
TORYOI commented 1 year ago

It should use socket.io client v2.x, otherwise fail. You can see the message prompt

// client
socket.on('connect_error', (error: string) => {
  console.error(error);
});