繁体   English   中英

如何将HTTP请求升级到Websocket(高速公路和Twisted Web)

[英]How to Upgrade HTTP Request to Websocket (Autobahn & Twisted Web )

让您大致了解我如何使用Twisted Web和Autobahn Websockets:我的UI当前发送初始HTTP GET请求,并在标头中将其升级为websocket。 阅读Twisted Web中的内容后,连接需要从HTTP切换到Websocket协议,以来回传递数据。 请注意,此websocket升级在同一port 8000

有谁知道我可以执行我要做什么? 非常感谢。

编辑:为工作示例更新的代码。 您可以在此处找到它: POST请求中的有效载荷被切断(扭曲的网络)

这是我使用Twisted Web的代码:

class HttpResource(resource.Resource):
    isLeaf = 1

    def __init__(self):
        self.children = {}
        self.ws_port = None

    print 'resource invoked'
    def render_GET(self, request):

        print 'render invoked'
        if request.getHeader('Sec-WebSocket-Key'):
            # Processing the Key as per RFC 6455
            key = request.getHeader('Sec-WebSocket-Key')
            h = hashlib.sha1(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
            request.setHeader('Sec-WebSocket-Accept', base64.b64encode(h.digest()))

            # setting response headers
            request.setHeader('Upgrade', 'websocket')
            request.setHeader('Connection', 'Upgrade')
            request.setResponseCode(101)
            return ''
        else:
            log("Regular HTTP GET request.")
            return "<html><body style='margin: 0; overflow: hidden;'><iframe style='width: 100%; height: 100%; border: none;' src='http://tsa-graphiql.herokuapp.com/'></iframe></body></html>"

    def render_POST(self,request):
        log("POST request")
        request.setResponseCode(200)

    def handle_single_query(self, queryData):
        log("Handle single query data.")
        return


class HttpWsChannel(http.HTTPChannel):

    def dataReceived(self, data):
        log('Data received:\n{}'.format(data))
        if data.startswith('GET'):
            # This will invoke the render method of resource provided
            http.HTTPChannel.dataReceived(self, data)
        if data.startswith('POST'):
            http.HTTPChannel.dataReceived(self, data)
        else:
            """
            Pass binary data to websocket class.
            """
            ws_protocol = self.site.ws_factory.protocol(self.site.ws_factory.connection_subscriptions)
            log(ws_protocol)
            #just echo for now
            # self.transport.write(data)


class HttpFactory(Site):
    """
    Factory which takes care of tracking which protocol
    instances or request instances are responsible for which
    named response channels, so incoming messages can be
    routed appropriately.
    """

    def __init__(self, resource):
        http.HTTPFactory.__init__(self)
        self.resource = resource
        self.ws_factory = WsProtocolFactory("ws://127.0.0.1:8000")
        self.ws_factory.protocol = WsProtocol

    def buildProtocol(self, addr):
        try:
            channel = HttpWsChannel()
            channel.requestFactory = self.requestFactory
            channel.site = self
            return channel
        except Exception as e:
            log("Could not build protocol: {}".format(e))

site = HttpFactory(HttpResource())

if __name__ == '__main__':
    reactor.listenTCP(8000, site)
    reactor.run()

编辑7/8/2017:这是我在下面尝试的新代码。 通过onMessage方法成功接收到websocket消息。 但是,HTTP请求不起作用。 我在GET请求中遇到的当前错误是:

<html>
  <head><title>404 - No Such Resource</title></head>
  <body>
    <h1>No Such Resource</h1>
    <p>No such child resource.</p>
  </body>
</html>

Python代码

from twisted.web.server import (
    Site,
)
from twisted.internet import reactor
from twisted.web.resource import (
    Resource,
)
from autobahn.twisted.websocket import (
    WebSocketServerProtocol,
    WebSocketServerFactory,
)
from autobahn.twisted.resource import (
    WebSocketResource,
)


class WebSocketProtocol(WebSocketServerProtocol):

    def onConnect(self, request):
        print("WebSocket connection request: {}".format(request))

    def onMessage(self, payload, isBinary):
        print("onMessage: {}".format(payload))


if __name__ == '__main__':

    factory = WebSocketServerFactory()
    factory.protocol = WebSocketProtocol
    resource = WebSocketResource(factory)

    root = Resource()
    root.putChild(b"ws", resource)

    site = Site(root)
    reactor.listenTCP(8000, site)

    reactor.run()

使用WebSocketResource揭露一个WebSocketServerFactory作为一部分Site

from twisted.web.server import (
    Site,
)
from twisted.web.resource import (
    Resource,
)
from autobahn.twisted.websocket import (
    WebSocketServerProtocol,
    WebSocketServerFactory,
)
from autobahn.twisted.resource import (
    WebSocketResource,
)

class YourAppProtocol(WebSocketServerProtocol):
    def onConnect(self, request):
        ...

    ...

def main():
    factory = WebSocketRendezvousFactory()
    factory.protocol = YourAppProtocol
    resource = WebSocketResource(factory)
    root = Resource()
    root.putChild(b"some-path-segment", resource)
    root.putChild(...)
    site = Site(root)
    reactor.listenTCP(8080, site)
    reactor.run()

请求主体被截断的问题可能是因为您的升级协议实现存在错误。 没有在dataReceived级别应用帧,因此您不能期望像startswith("GET")这样的检查是可靠的。

使用WebSocketResourceSite可为您提供来自Twisted Web和Autobahn的正确HTTP解析代码,同时还允许您将WebSocket与特定的URL进行对话,并与其他URL进行常规的HTTP对话。

因此,在Google上阅读了一些内容之后,我发现了这个网站,该网站说明了如何通过Autobahn Twisted将HTTP连接升级到websocket连接:通过Autobahn Twisted 读取和设置请求标头

我能够开始工作的代码如下所示!

from twisted.web.server import (
    Site,
)
from twisted.internet import reactor
from twisted.web.resource import (
    Resource,
)
from autobahn.twisted.websocket import (
    WebSocketServerProtocol,
    WebSocketServerFactory,
)
from autobahn.twisted.resource import (
    WebSocketResource,
)


class HttpResource(Resource):
    isLeaf = True

    def render_GET(self, request):
    return "<html><body style='margin: 0; overflow: hidden;'><iframe style='width: 100%; height: 100%; border: none;' src='http://tsa-graphiql.herokuapp.com/'></iframe></body></html>"


class WebSocketProtocol(WebSocketServerProtocol):

    def onConnect(self, request):
        custom_header = {}

        if request.headers['sec-websocket-key']:
            custom_header['sec-websocket-protocol'] = 'graphql-ws'
        return (None, custom_header)

    def onMessage(self, payload, isBinary):
        print("onMessage: {}".format(payload))


if __name__ == '__main__':

    factory = WebSocketServerFactory()
    factory.protocol = WebSocketProtocol
    resource = WebSocketResource(factory)

    root = Resource()
    root.putChild("", HttpResource())
    root.putChild(b"ws", ws_resource)

    site = Site(root)
    reactor.listenTCP(8000, site)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM