如何将HTTP请求升级到Websocket(Autobahn和Twisted Web)(How to Upgrade HTTP Request to Websocket (Autobahn & Twi

编程入门 行业动态 更新时间:2024-10-25 20:18:56
如何将HTTP请求升级到Websocket(Autobahn和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请求的有效负载是截止(扭曲的Web)

这是我使用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()

To give you an idea of what I am trying to accomplish with Twisted Web and Autobahn websockets: my UI currently sends an initial HTTP GET request with an upgrade to a websocket in the header. Upon reading that in Twisted Web, the connection needs to switch from HTTP to a websocket protocol to pass data back and forth. Note that this websocket upgrade happens on the same port, port 8000.

Does anyone know how I can implement what I am trying to do? Thank you so much.

EDIT: updated code for working example. You can find it here: Payload from POST Request is Cutoff (Twisted Web)

Here is my code using 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()

EDIT 7/8/2017: Here is the new code I am trying below. The websocket messages are received successfully via the onMessage method. However the HTTP requests are not working. The current error I am getting on a GET request is:

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

Python code

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将WebSocketResource公开为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")这样的检查是可靠的。

使用WebSocketResource和Site为您提供来自Twisted Web和Autobahn的正确HTTP解析代码,同时还允许您将WebSocket发送到特定URL并将常规HTTP发送给其他人。

So after reading a little bit on Google, I found this website that explains how to upgrade the HTTP connection to a websocket connection via Autobahn Twisted: Read and Set request headers via Autobahn Twisted.

The code that I was able to get to work is shown below!

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)

更多推荐

本文发布于:2023-08-03 19:04:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1396249.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:升级到   如何将   Websocket   Autobahn   HTTP

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!