使用 java websocket API 和 Javascript 上传文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21769470/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
File upload using java websocket API and Javascript
提问by parn
I'm studying websocket and have done chat program with websocket/json. But I'm stuck at file uploading ATM. Any advice & answer would be thankful.
我正在学习 websocket 并且已经使用 websocket/json 完成了聊天程序。但我被困在文件上传 ATM 上。任何建议和答案将不胜感激。
Server side:
服务器端:
package websocket;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/receive/fileserver")
public class FileServer {
@OnOpen
public void open(Session session, EndpointConfig conf) {
System.out.println("chat ws server open");
}
@OnMessage
public void processUpload(ByteBuffer msg, boolean last, Session session) {
System.out.println("Binary message");
FileOutputStream fos = null;
File file = new File("D:/download/tmp.txt");
try {
fos = new FileOutputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
byte readdata = (byte) -999;
while(readdata!=-1) {
readdata=msg.get();
try {
fos.write(readdata);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@OnMessage
public void message(Session session, String msg) {
System.out.println("got msg: " + msg + msg.length());
}
@OnClose
public void close(Session session, CloseReason reason) {
System.out.println("socket closed: "+ reason.getReasonPhrase());
}
@OnError
public void error(Session session, Throwable t) {
t.printStackTrace();
}
}
Client:
客户:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Chat</title>
<script type="text/javascript" src="/MyHomePage/jquery-2.0.3.min.js"></script>
</head>
<body>
<h2>File Upload</h2>
Select file
<input type="file" id="filename" />
<br>
<input type="button" value="Connect" onclick="connectChatServer()" />
<br>
<input type="button" value="Upload" onclick="sendFile()" />
<script>
var ws;
function connectChatServer() {
ws = new WebSocket(
"ws://localhost:8080/MyHomePage/receive/fileserver");
ws.binaryType = "arraybuffer";
ws.onopen = function() {
alert("Connected.")
};
ws.onmessage = function(evt) {
alert(evt.msg);
};
ws.onclose = function() {
alert("Connection is closed...");
};
ws.onerror = function(e) {
alert(e.msg);
}
}
function sendFile() {
var file = document.getElementById('filename').files[0];
var reader = new FileReader();
var rawData = new ArrayBuffer();
reader.loadend = function() {
}
reader.onload = function(e) {
rawData = e.target.result;
ws.send(rawData);
alert("the File has been transferred.")
}
reader.readAsBinaryString(file);
}
</script>
</body>
</html>
server side closed reason message is as below
服务器端关闭原因消息如下
socket closed: The decoded text message was too big for the output buffer and the endpoint does not support partial messages
套接字关闭:解码的文本消息对于输出缓冲区来说太大,并且端点不支持部分消息
Q1: It seems that it is finding text processing method instead of binary processing method according to the closed reason, how can I fix this?
Q1:好像是按照关闭的原因找文本处理方法而不是二进制处理方法,怎么解决?
Q2: Should I change data type to Blob to transfer file on javascript side? Then how?
Q2:我应该将数据类型更改为 Blob 以在 javascript 端传输文件吗?那怎么办?
extra Q: May anyone link example source(es) of websocket file transferring(java websocket or javascript either/both)?
额外问:任何人都可以链接 websocket 文件传输的示例源(java websocket 或 javascript 之一/两者)?
Thanks for reading :)
谢谢阅读 :)
回答by parn
After some researches and tries, I found out that 'reader.readAsBinaryString(file);' was a cause of Question 1. Changing it into 'reader.readAsArrayBuffer(file);' my first problem has been solved.
经过一些研究和尝试,我发现'reader.readAsBinaryString(file);' 是问题 1 的原因。将其更改为 'reader.readAsArrayBuffer(file);' 我的第一个问题已经解决了。
In addition, since websocket transfers a file as several partial data automatically, I changed source as below. This works!only when the file size is not so big. :/
另外,由于 websocket 自动将文件传输为多个部分数据,因此我将源更改如下。这有效!仅当文件大小不是那么大时。:/
Changed server side source:
更改了服务器端源:
package websocket;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/receive/fileserver")
public class FileServer {
static File uploadedFile = null;
static String fileName = null;
static FileOutputStream fos = null;
final static String filePath="d:/download/";
@OnOpen
public void open(Session session, EndpointConfig conf) {
System.out.println("chat ws server open");
}
@OnMessage
public void processUpload(ByteBuffer msg, boolean last, Session session) {
System.out.println("Binary Data");
while(msg.hasRemaining()) {
try {
fos.write(msg.get());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@OnMessage
public void message(Session session, String msg) {
System.out.println("got msg: " + msg);
if(!msg.equals("end")) {
fileName=msg.substring(msg.indexOf(':')+1);
uploadedFile = new File(filePath+fileName);
try {
fos = new FileOutputStream(uploadedFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}else {
try {
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@OnClose
public void close(Session session, CloseReason reason) {
System.out.println("socket closed: "+ reason.getReasonPhrase());
}
@OnError
public void error(Session session, Throwable t) {
t.printStackTrace();
}
}
Browser(Client) side:
浏览器(客户端)端:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Chat</title>
<script type="text/javascript" src="/MyHomePage/jquery-2.0.3.min.js"></script>
</head>
<body>
<h2>File Upload</h2>
Select file
<input type="file" id="filename" />
<br>
<input type="button" value="Connect" onclick="connectChatServer()" />
<br>
<input type="button" value="Upload" onclick="sendFile()" />
<script>
var ws;
function connectChatServer() {
ws = new WebSocket(
"ws://localhost:8080/MyHomePage/receive/fileserver");
ws.binaryType = "arraybuffer";
ws.onopen = function() {
alert("Connected.")
};
ws.onmessage = function(evt) {
alert(evt.msg);
};
ws.onclose = function() {
alert("Connection is closed...");
};
ws.onerror = function(e) {
alert(e.msg);
}
}
function sendFile() {
var file = document.getElementById('filename').files[0];
ws.send('filename:'+file.name);
var reader = new FileReader();
var rawData = new ArrayBuffer();
//alert(file.name);
reader.loadend = function() {
}
reader.onload = function(e) {
rawData = e.target.result;
ws.send(rawData);
alert("the File has been transferred.")
ws.send('end');
}
reader.readAsArrayBuffer(file);
}
</script>
</body>
</html>
Still I cannot figure out how to transfer larger size file. (I'm suspecting auto-timeout and/or buffer size). Any advice plz?
我仍然不知道如何传输更大的文件。(我怀疑自动超时和/或缓冲区大小)。有什么建议吗?
回答by Konga Raju
In My case its working to upload large files without any browser crash or socket close.
在我的情况下,它可以在没有任何浏览器崩溃或套接字关闭的情况下上传大文件。
Please follow the following steps to work it.
请按照以下步骤操作。
- Use web workers to slice the large files
- send the chunks to server using Websocket from main thread
- construct file on server side based on blob or chunk information.
- maintain unique id for each file while uploading files to server so that server can recognize to which file append
- In server side initially place it in temp folder with unique id after completion move it to the exact folder.
- 使用网络工作者对大文件进行切片
- 从主线程使用 Websocket 将块发送到服务器
- 根据 blob 或块信息在服务器端构建文件。
- 在将文件上传到服务器时为每个文件维护唯一的 id,以便服务器可以识别附加到哪个文件
- 在服务器端,最初将它放在具有唯一 ID 的临时文件夹中,完成后将其移动到确切的文件夹。
You can through this articleto get an idea about the complete work flow, its working with Websocket.
您可以通过本文了解完整的工作流程,以及它与 Websocket 的协同工作。