Запросы прокси Websocket в приложении Rails - PullRequest
2 голосов
/ 29 апреля 2020

У меня есть приложение rails и сервис Golang. Приложение Rails - это пользовательское приложение с пользовательским интерфейсом. Часть запросов от внешнего интерфейса направляется в службу golang для определенных функций. До сих пор у нас были только HTTP-запросы, поступающие из пользовательского интерфейса.

Теперь у нас есть функциональность websockets в пользовательском интерфейсе. Поэтому нам нужно направить эти запросы веб-сокетов в службу Golang через приложение Rails. В основном приложение Rails контролирует часть аутентификации / авторизации. Поэтому нам нужно направить запросы через приложение Rails.

Мы исследовали https://github.com/ncr/rack-proxy для маршрутизации запросов, но нам не удалось правильно направить запрос websocket. Мы попробовали следующий код, где запросы веб-сокетов принимаются на ws: // localhost: 3000 / ws / v1 / stat отправляются на ws: // localhost: 4000 / ws / v1 / stats с использованием следующего кода.

# frozen_string_literal: true
require 'rack-proxy'
module Proxy
  ENV['SERVICE_URL'] ||= 'http://guides.rubyonrails.org'
  class GoServiceProxy < Rack::Proxy
    def perform_request(env)
      request = Rack::Request.new(env)
      # use rack proxy for anything hitting our host app at /example_service
      # if request.path =~ %r{^/example_service}
      if request.path =~ %r{stats}
        backend = URI(ENV['SERVICE_URL'])
        # most backends required host set properly, but rack-proxy doesn't set this for you automatically
        # even when a backend host is passed in via the options
        env["HTTP_HOST"] = 'localhost:4000'
        # This is the only path that needs to be set currently on Rails 5 & greater
        #env['PATH_INFO'] = ENV['SERVICE_PATH'] || '/configuring.html'
        # don't send your sites cookies to target service, unless it is a trusted internal service that can parse all your cookies
        env['HTTP_COOKIE'] = ''
        super(env)
      else
        @app.call(env)
      end
    end
  end
end

Но когда я включаю ws: // localhost: 3000 / ws / v1 / stat , я получаю 101 ответ, но сообщения отправлены с go услуги не приходят. Следующий снимок экрана - ответ, который я получаю:

curl -v --request GET 'http://localhost:3000/ws/v1/stats' \
--header 'Content-Type: application/json' \
--header 'Upgrade: websocket' \
--header 'Connection: upgrade' \
--header 'Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==' \
--header 'Sec-Websocket-Version: 13'
Note: Unnecessary use of -X or --request, GET is already inferred.
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 3000 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /ws/v1/stats HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Type: application/json
> Upgrade: websocket
> Connection: upgrade
> Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
> Sec-Websocket-Version: 13
>
< HTTP/1.1 101 Switching Protocols
< sec-websocket-accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
< Cache-Control: no-cache
< X-Request-Id: 957758f9-d762-43d0-bffb-fdd72efbfbc1
< X-Runtime: 0.002848
<
* Empty reply from server
* Connection #0 to host localhost left intact
curl: (52) Empty reply from server

Есть ли какой-нибудь способ, которым мы можем прокси-запросы веб-сокетов через Rails Application?

...