socketry / async-websocket

Asynchronous WebSocket client and server, supporting HTTP/1 and HTTP/2 for Ruby.
MIT License
166 stars 18 forks source link

Failed to negotiate connection: 400 #27

Closed googya closed 3 years ago

googya commented 3 years ago

Did i use a wrong way? i did not figure it out how to connect a endpoint

Async do |task|
    endpoint = Async::HTTP::Endpoint.parse(URL)

    Async::WebSocket::Client.connect(endpoint) do |connection|
        connection.write ["Hello World!", "ping"]

        while message = connection.read
            p message
        end
    end
end
 0.91s    error: Async::Task [oid=0x2a8] [pid=70589] [2020-10-22 22:49:22 +0900]
               |   Async::WebSocket::ProtocolError: Failed to negotiate connection: 400
               |   → /Users/kv/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/async-websocket-0.16.0/lib/async/websocket/client.rb:99 in `connect'
               |     /Users/kv/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/async-websocket-0.16.0/lib/async/websocket/client.rb:53 in `block in connect'
               |     /Users/kv/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/async-websocket-0.16.0/lib/async/websocket/client.rb:44 in `open'
               |     /Users/kv/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/async-websocket-0.16.0/lib/async/websocket/client.rb:52 in `connect'
               |     t.rb:14 in `block in <main>'
               |     /Users/kv/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/async-1.26.2/lib/async/task.rb:258 in `block in make_fiber'
googya commented 3 years ago

using iodine seems very easy :

require 'iodine'

class PriceClient
  def on_message(connection, message)
    puts "Received: #{message}"
  end

  def on_close(connection)
    puts "* Client closed."
    Iodine.stop
  end
end

Iodine.threads = 1
Iodine.connect url: "wss://stream.binance.com:9443/ws/btcusdt@bookTicker", handler: PriceClient.new, ping: 40
Iodine.start
ioquatix commented 3 years ago

It looks like they support HTTP/2 but they don't support WebSockets over HTTP/2.

You need to force the client to only use HTTP/1:

#!/usr/bin/env ruby

require 'async'
require 'async/http'
require 'async/websocket'

URL = "wss://stream.binance.com:9443/ws/btcusdt@bookTicker"

Async do |task|
    endpoint = Async::HTTP::Endpoint.parse(URL, alpn_protocols: Async::HTTP::Protocol::HTTP11.names)

    Async::WebSocket::Client.connect(endpoint) do |connection|
        while message = connection.read
            p message
        end
    end
end

The reason why Iodine works is because it only supports HTTP/1 AFAIK.