Python 如何将HTTP请求升级到Websocket(Autobahn&Twisted Web)
为了让您了解我试图通过Twisted Web和Autobahn websocket实现的目标:我的UI当前发送一个初始HTTP GET请求,并在标题中升级到websocket。在Twisted Web中读取数据后,连接需要从HTTP切换到websocket协议,以便来回传递数据。请注意,此websocket升级发生在同一端口上,Python 如何将HTTP请求升级到Websocket(Autobahn&Twisted Web),python,websocket,twisted,autobahn,twisted.web,Python,Websocket,Twisted,Autobahn,Twisted.web,为了让您了解我试图通过Twisted Web和Autobahn websocket实现的目标:我的UI当前发送一个初始HTTP GET请求,并在标题中升级到websocket。在Twisted Web中读取数据后,连接需要从HTTP切换到websocket协议,以便来回传递数据。请注意,此websocket升级发生在同一端口上,端口8000 有人知道我如何实现我要做的事情吗?非常感谢你 编辑:工作示例的更新代码。你可以在这里找到它: 以下是我使用Twisted Web的代码: class Htt
端口8000
有人知道我如何实现我要做的事情吗?非常感谢你
编辑:工作示例的更新代码。你可以在这里找到它:
以下是我使用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()
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
作为站点的一部分
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”)
这样的检查是可靠的
使用WebSocketResource
和Site
可以为您提供来自Twisted Web和Autobahn的正确HTTP解析代码,同时还允许您对特定URL使用WebSocket,对其他URL使用常规HTTP。使用WebSocketResource
将WebSocketServerFactory
作为站点的一部分公开
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”)
这样的检查是可靠的
使用WebSocketResource
和Site
可以为您提供来自Twisted Web和Autobahn的正确HTTP解析代码,同时还允许您将WebSocket与特定URL和常规HTTP与其他URL进行对话。因此,在谷歌上阅读一点内容后,我发现这个网站解释了如何通过Autobahn Twisted将HTTP连接升级到websocket连接:
我能够开始工作的代码如下所示
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)
从twisted.web.server导入(
地点
)
从twisted.internet导入
从twisted.web.resource导入(
资源
)
从autobahn.twisted.websocket导入(
WebSocketServerProtocol,
WebSocketServerFactory,
)
从autobahn.twisted.resource导入(
WebSocketResource,
)
类HttpResource(资源):
isLeaf=True
def render_GET(自我,请求):
返回“”
类WebSocketProtocol(WebSocketServerProtocol):
def onConnect(自我、请求):
自定义_头={}
if request.headers['sec-websocket-key']:
自定义_头['sec-websocket-protocol']='graphql-ws'
返回(无,自定义标题)
def onMessage(self、payload、isBinary):
打印(“onMessage:{}”。格式(有效负载))
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
factory=WebSocketServerFactory()
factory.protocol=WebSocketProtocol
资源=WebSocketResource(工厂)
根=资源()
root.putChild(“,HttpResource())
root.putChild(b“ws”,ws\u资源)
站点=站点(根)
反应堆列表CP(8000,现场)
所以在谷歌上读了一点之后,我发现了一个网站,它解释了如何通过Autobahn Twisted将HTTP连接升级到websocket连接:
我能够开始工作的代码如下所示
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)
从twisted.web.server导入(
地点
)
从twisted.internet导入
从twisted.web.resource导入(
资源
)
从autobahn.twisted.websocket导入(
WebSocketServerProtocol,
WebSocketServerFactory,
)
从autobahn.twisted.resource导入(
WebSocketResource,
)
类HttpResource(资源):
isLeaf=True
def render_GET(自我,请求):
返回“”
类WebSocketProtocol(WebSocketServerProtocol):
def onConnect(自我、请求):
自定义_头={}
if request.headers['sec-websocket-key']:
自定义_头['sec-websocket-protocol']='graphql-ws'
返回(无,自定义标题)
def onMessage(self、payload、isBinary):
打印(“onMessage:{}”。格式(有效负载))
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
factory=WebSocketServerFactory()
factory.protocol=WebSocketProtocol
资源=WebSocketResource(工厂)
根=资源()
root.putChild(“,HttpResource())
root.putChild(b“ws”,ws\u资源)
站点=站点(根)
反应堆列表CP(8000,现场)
我认为这段代码没有说明如何在与HTTP相同的端口上使用autobahn websocket。我以前实现过这段代码,但它不是我想要的。我相信我可能有一个使用Twisted web Library的工作示例。我用一个工作示例的链接更新了描述,但遇到了一个请求被中断的问题。继续深入研究这个问题@jean-paul Calderonet谢谢!我尝试了你的例子,我能够收到websocket消息。但是,当执行get请求时,我得到一个404,声明没有这样的资源-找不到这样的子资源。我必须用render\u get方法显式定义资源类吗?另外,我是否必须指定getChild方法如何正确路由websocket请求?顺便说一下,我正在用一个REST客户机进行测试。再次感谢!一个404当得到什么?我不认为这段代码显示了如何使用高速公路websocket在同一端口作为HTTP。我以前实现过这段代码,但它不是我想要的。我相信我可能有一个使用Twisted web Library的工作示例。我用一个工作示例的链接更新了描述,但遇到了一个请求被中断的问题。继续深入研究这个问题@jean-paul Calderonet谢谢!我尝试了你的例子,我能够收到websocket消息。但是,当执行get请求时,我得到一个404,声明没有这样的资源-没有找到这样的子资源。我必须显式吗