[英]Spring Stomp over Websocket: Stream large files
My SockJs client in webpage, sends message with a frame size of 16K.我在网页中的 SockJs 客户端发送帧大小为 16K 的消息。 The message size limit is what determines the max size of the file that I can transfer.
消息大小限制决定了我可以传输的文件的最大大小。
Below is what I found in the doc.以下是我在文档中找到的内容。
/**
* Configure the maximum size for an incoming sub-protocol message.
* For example a STOMP message may be received as multiple WebSocket messages
* or multiple HTTP POST requests when SockJS fallback options are in use.
*
* <p>In theory a WebSocket message can be almost unlimited in size.
* In practice WebSocket servers impose limits on incoming message size.
* STOMP clients for example tend to split large messages around 16K
* boundaries. Therefore a server must be able to buffer partial content
* and decode when enough data is received. Use this property to configure
* the max size of the buffer to use.
*
* <p>The default value is 64K (i.e. 64 * 1024).
*
* <p><strong>NOTE</strong> that the current version 1.2 of the STOMP spec
* does not specifically discuss how to send STOMP messages over WebSocket.
* Version 2 of the spec will but in the mean time existing client libraries
* have already established a practice that servers must handle.
*/
public WebSocketTransportRegistration setMessageSizeLimit(int messageSizeLimit) {
this.messageSizeLimit = messageSizeLimit;
return this;
}
MY QUESTION: Can I setup a partial messaging so that a file is transferred part by part and is not getting transferred as a single message as it is been done now?我的问题:我可以设置部分消息传递,以便文件逐部分传输,而不是像现在那样作为单个消息传输吗?
Update: Still looking for a solution with partial messaging Meanwhile using HTTP now for large messages (which is file uploads/downloads in my application).更新:仍在寻找具有部分消息传递的解决方案 同时现在使用 HTTP 处理大消息(这是我的应用程序中的文件上传/下载)。
Can I setup a partial messaging so that a file is transferred part by part and is not getting transferred as a single message as it is been done now?
我可以设置部分消息传递,以便文件逐部分传输,而不是像现在那样作为单个消息传输吗?
Yes.是的。 Here is the relevant Config from my Spring boot experimental project - basically
UploadWSHandler
is registered and WebSocketTransportRegistration.setMessageSizeLimit
is set.这是我的 Spring boot 实验项目中的相关配置 - 基本上
UploadWSHandler
已注册并设置了WebSocketTransportRegistration.setMessageSizeLimit
。
@Configuration
@EnableWebSocket
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new UploadWSHandler(), "/binary");
}
@Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.setMessageSizeLimit(50 * 1024 * 1024);
}
}
The UploadWShandler is as follows. UploadWShandler 如下所示。 Sorry too much code here - Key points
抱歉这里代码太多 - 关键点
supportsPartialMessage
which returns true. supportsPartialMessage
返回 true 的PartialMessage。handleBinaryMessage
will be called multiple times with partial message so we need to assemble the bytes. handleBinaryMessage
将使用部分消息多次调用,因此我们需要组装字节。 So afterConnectionEstablished
establishes an identity using the websocket URL query.afterConnectionEstablished
使用 websocket URL 查询建立一个身份。 But you don't have to use this mechanism.webSocket.send(files[0])
only once ie I am not slicing the file blob object on the javascript side.webSocket.send(files[0])
一次,即我没有在 javascript 端切片文件 blob 对象。 (side point: I want to use plain websocket on client side - no stomp/socks) message.isLast()
last messagemessage.isLast()
最后一条消息FileUploadInFlight
but you don't have to do this and can stream somewhere else as you go.FileUploadInFlight
在内存中累积这些字节,但您不必这样做,并且可以随时在其他地方流式传输。public class UploadWSHandler extends BinaryWebSocketHandler {
Map<WebSocketSession, FileUploadInFlight> sessionToFileMap = new WeakHashMap<>();
@Override
public boolean supportsPartialMessages() {
return true;
}
@Override
protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
ByteBuffer payload = message.getPayload();
FileUploadInFlight inflightUpload = sessionToFileMap.get(session);
if (inflightUpload == null) {
throw new IllegalStateException("This is not expected");
}
inflightUpload.append(payload);
if (message.isLast()) {
Path basePath = Paths.get(".", "uploads", UUID.randomUUID().toString());
Files.createDirectories(basePath);
FileChannel channel = new FileOutputStream(
Paths.get(basePath.toString() ,inflightUpload.name).toFile(), false).getChannel();
channel.write(ByteBuffer.wrap(inflightUpload.bos.toByteArray()));
channel.close();
session.sendMessage(new TextMessage("UPLOAD "+inflightUpload.name));
session.close();
sessionToFileMap.remove(session);
}
String response = "Upload Chunk: size "+ payload.array().length;
System.out.println(response);
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessionToFileMap.put(session, new FileUploadInFlight(session));
}
static class FileUploadInFlight {
String name;
String uniqueUploadId;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
/**
* Fragile constructor - beware not prod ready
* @param session
*/
FileUploadInFlight(WebSocketSession session) {
String query = session.getUri().getQuery();
String uploadSessionIdBase64 = query.split("=")[1];
String uploadSessionId = new String(Base64Utils.decodeUrlSafe(uploadSessionIdBase64.getBytes()));
System.out.println(uploadSessionId);
List<String> sessionIdentifiers = Splitter.on("\\").splitToList(uploadSessionId);
String uniqueUploadId = session.getRemoteAddress().toString()+sessionIdentifiers.get(0);
String fileName = sessionIdentifiers.get(1);
this.name = fileName;
this.uniqueUploadId = uniqueUploadId;
}
public void append(ByteBuffer byteBuffer) throws IOException{
bos.write(byteBuffer.array());
}
}
}
BTW a working project is also sprint-boot-with-websocked-chunking-assembly-and-fetch in with-websocked-chunking-assembly-and-fetch
branch顺便说一句,一个工作项目也是sprint-boot-with-websocked-chunking-assembly-and-fetch in
with-websocked-chunking-assembly-and-fetch
分支
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.