Vue3中通过 input 标签 发送文件/图片给后端

Posted 大号密码忘了

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue3中通过 input 标签 发送文件/图片给后端相关的知识,希望对你有一定的参考价值。

一;设置 input 标签 

<input type="file" ref="fileInput" @change="handleFileChange"/>

1.将 input 标签的 type 属性设置为 file 。

使用 type="file" 的 <input> 元素使得用户可以选择一个或多个元素以提交表单的方式上传到服务器上,或者通过 javascript 的 File API 对文件进行操作。

2.绑定 ref 绑定并获取该标签的DOM节点。

type="file" 的 <input> 元素身上存在一个 files 属性,其中包含了所有已选择的文件,其值是一个伪数组。

3.绑定事件,处理文件/图片上传的后续逻辑。

二;通过 FormData 实例对象处理 二进制 文件/图片(以下代码展示上传一张图片)。

// 上传之前要处理一下文件 因为文件是二进制的,要利用 FormData 实例对象进行处理
const formData = new FormData();
// append方法把文件添加到 FormData实例对象中 第一个参数:文件名 第二个参数:要上传的文件
formData.append("smfile", files[0]);

三;获取 input 节点的 files 属性以及上传文件/图片的业务逻辑与请求发送都放在了 input 事件回调函数中进行。

由于是发送二进制数据,所以发送请求时头部字段 Content - type 要设置成 multipart / form-data

// input 发生改变时触发的回调函数 --- 验证上传的文件是否合法,然后处理文件并发送请求
    const handleFileChange = (e: Event) => 
      const currentTarget = e.target as htmlInputElement;
      if (currentTarget.files) 
        // 将input身上的files对象转换为数组类型
        const files = Array.from(currentTarget.files);
        // 如果有上传限制,则对文件进行判断
        if (props.beforeUpload) 
          // 调用判断文件是否合法的函数---由父组件自定义设置
          const result = props.beforeUpload(files[0]);
          // 如果不合法就直接返回出去
          if (!result) return;
        
        // 上传的文件符合要求
        // 上传成功之前,把上传文件状态改为 loading
        fileStatus.value = "loading";
        // 上传之前要处理一下文件 因为文件是二进制的,要利用 FormData 实例对象进行处理
        const formData = new FormData();
        // append方法把文件添加到 FormData实例对象中 第一个参数:文件名 第二个参数:要上传的文件
        formData.append("smfile", files[0]);
        // 发送异步请求上传文件
        // 因为发送的二进制格式文件 所以要额外设置请求头
        axios
          .post('yes/api/v2/upload', formData, 
            headers: 
              "Content-Type": "multipart/form-data",
              "Authorization":"CiKs2eatBnpdzNJ58T",
            ,
          )
          .then((res) => 
            // 图片上传成功
            if(res.data.code == 'success') 
              // 存储成功的返回结果
              uploadedData.value = res.data.data.url;
            else 
              uploadedData.value = res.data.images;
            
            // 请求发送成功 修改上传文件状态
            fileStatus.value = "success";
            // 把获取到的图片url传给父组件
            context.emit('getImageUrl',uploadedData.value);
          )
          .catch((e) => 
            console.log('图床上传',e);
            fileStatus.value = "error";
          )
          .finally(() => 
            if (fileInput.value) 
              fileInput.value.value = "";
            
          );
      
    ;

在 c++ 中通过套接字(发送函数)发送图片,但不接收完整(Windows)!

【中文标题】在 c++ 中通过套接字(发送函数)发送图片,但不接收完整(Windows)!【英文标题】:Send Picture by socket (send func) in c++ , but do not recive complete(Windows)! 【发布时间】:2013-09-29 18:33:15 【问题描述】:

我正在从客户端向服务器发送数据,但是图片接收不完整。

客户代码:

FILE *fr = fopen(tmppicsend, "rb");
char* buffer;
buffer = (char*) malloc(sizeof(char)*size);
fread(buffer, size, 1, fr);
send_len_pic = send( m_socket_pic, buffer, size, 0 );
recv( m_socket_pic, rec_end_check, 32, 0 );
fclose(fr);
free(buffer);

服务器代码:

FILE *fw = fopen(fname, "wb");
char* buffer;
buffer = (char*) malloc(sizeof(char)*size);
int rec_len = recv( current_client, buffer, size, 0 );
buffer[size]='\0';
fwrite(buffer, size, 1, fw);
size -= size;
free(buffer);
fclose(fw);

配置套接字:

WSADATA wsaData_pic;
SOCKET m_socket_pic;
SOCKET m_backup_pic;
sockaddr_in con_pic;

 // Initialize Winsock.
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData_pic );
if ( iResult != NO_ERROR )
    //printf("Error at WSAStartup()\n");

// Create a socket.
m_socket_pic = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

if ( m_socket_pic == INVALID_SOCKET ) 
    //printf( "Error at socket(): %ld\n", WSAGetLastError() );
    //WSACleanup();


m_backup_pic = m_socket_pic;

// Connect to a server.
con_pic.sin_family = AF_INET;
con_pic.sin_addr.s_addr = inet_addr( ip );
con_pic.sin_port = htons( 2200 );

if ( connect( m_backup_pic, (SOCKADDR*) &con_pic, sizeof(con_pic) ) == SOCKET_ERROR) 
    //printf( "Failed to connect.\n" );
    //WSACleanup();
else
   
    m_socket_pic=m_backup_pic;




当我比较这些图片时,我看到序列号数据包中有错误(数据包没有定期接收)。 图片(来自客户端和服务器的图片)大小相同。 我想发送JPEG图片。

请帮帮我,坦克们。

【问题讨论】:

buffer[size]='\0'; 既不必要(这是二进制数据)又未定义,因为它在分配的内存之外建立索引。这意味着您的服务器程序无效。 我在这里发表了评论,但问题仍然存在。 你如何观察“序列号”?你在看IP数据包吗?如果您知道,您是否知道 IP 数据包不一定按顺序到达,而是由 TCP 层正确组装?你从服务器上哪里得到size?我认为您需要发布更多周边代码。 我认为操作系统观察序列号数据包。 我将图片文件的大小发送到服务器。当我在服务器中收到图片并比较大小图片文件(在客户端和服务器中)图片大小相同。 【参考方案1】:

我有很多次尝试回答。

这个问题的最佳答案是:

将客户端与服务器同步以发送流。

因为 recv() 函数比 send() 函数慢,客户端发送的数据量是服务器能够接收的。


客户代码:

char* bufferCMP;
bufferCMP = (char*)malloc(sizeof(char) * size);
p_file = fopen(tmppicsend,"rb");
fread(bufferCMP, 1, size , p_file);
fclose(p_file);


int chunkcount = size / DEFAULT_BUFLEN;
int lastchunksize = size - (chunkcount * DEFAULT_BUFLEN);
int fileoffset=0;

//Sending Actual Chunks
while (chunkcount > 0)

    iResult = send( m_socket_pic, bufferCMP + (fileoffset * DEFAULT_BUFLEN) , DEFAULT_BUFLEN , 0 );
    fileoffset++;
    chunkcount--;

    if (iResult != DEFAULT_BUFLEN)
    
        //printf("Sending Buffer size <> Default buffer length  ::: %d\n",WSAGetLastError());
    
    else
    
        //printf("Sending Buffer size = %d \n", iResult);
    


//Sending last Chunk
iResult = send( m_socket_pic, bufferCMP + (fileoffset * DEFAULT_BUFLEN) , lastchunksize , 0 );

服务器代码:

int FileCounter=0;
bool flg=true;
char * fileComplete;
char * filesizeBuffer;

FILE *temp;

int iResult;

int receiveBuffer = 0;
int desiredRecBuffer = size ;
//int desiredRecBuffer = DEFAULT_BUFLEN ; 
fileComplete = (char*) malloc (sizeof(char)* size );
while (desiredRecBuffer > 0)

    iResult = recv( current_client, fileComplete + receiveBuffer , desiredRecBuffer , 0 );
    //iResult = recv( ClientSocket, fileComplete + receiveBuffer , fileSize , 0 );

    if (iResult < 1)
    
        //printf("Reveive Buffer Error  %d \n", WSAGetLastError());
    
    else
    
        receiveBuffer += iResult;
        desiredRecBuffer = size - receiveBuffer ;
        //printf("Reveived Data size :  %d \n", iResult);
    


FILE *File = fopen(fname, "wb");
fwrite(fileComplete,1, size , File);
//flg = true;
free(fileComplete);
fclose(File);

【讨论】:

这里没有“将客户端与服务器同步以发送流”。最后,在一个月前的另一个答案中已经指出之后,正确处理recv() 返回的计数。声称'recv() 函数比send() 函数慢的说法是没有道理的。这个想法开始没有意义。你要回答多少次自己的问题?【参考方案2】:

谢谢大家,

问题是,通过套接字发送大文件。

我测试了很多方法,但没有回答问题。

众所周知,我应该使用循环发送拆分数据。

最好的分割大小是512或1500,很大的问题是在recv()函数中,这个函数比send()函数慢很多。当我在循环块中使用Sleep(1000)时,减少了损坏照片的数量。

【讨论】:

问题是您假设recv() 填充了缓冲区。在网络代码中添加睡眠实际上是在浪费时间。【参考方案3】:

客户端代码

    /*
     * Send size of the file first.
     */

    n = sizeof(filesize);
    r = send(m_socket_pic, &filesize, n);
    if (r != n) 
        printf("error sending %d bytes\n", n);
           

    /*
     * Now send the file.
     */

    n = filesize;
    while (n > 0) 
        r = send(m_socket_pic, buffer, n, 0);
        buffer += r;
        n -= r;    
           

服务器代码

    /*
     * Recv size of the file first.
     */

    n = sizeof(filesize);
    r = recv(current_client, &filefsize, n);
    if (r != n) 
        printf("error receiving %d bytes\n", n);
    

    /*
     * Now recv the file.
     */

    n = filesize;
    while (n > 0) 
        r = recv(current_client, buffer, n, 0);
        buffer += r;
        n -= r;
    

【讨论】:

我用过这个方法,但是还是有很多破照片!!,当我在while中使用“Sleep”时,我有一个更好的答案。 这段代码也有同样的问题。它假定recv() 填充了缓冲区。【参考方案4】:

您是否尝试过将图像缓冲区转换为 base64,将其发送到代码的接收器部分,然后对其进行 un-base 和 malloc?

上面的方式是我们的截图程序的工作方式(用于远程管理),它就像一个魅力..

【讨论】:

我看不出有任何理由将二进制数据转换为 base64 编码的字符串表示形式。网络协议应该可以很好地处理二进制数据,而转换增加了程序的复杂性,需要更多的内存用于额外的缓冲区,更多的网络带宽,因为 base64 编码的版本比纯二进制形式的大小更大,并且 CPU 更多转换的时间。但是,如果其他一切都失败了 - 至少可以尝试测试它是否也会失败:)【参考方案5】:

您如何知道要在服务器端接收的数据大小?您应该在服务器和客户端之间建立某种协议(由您自己定义)。最简单的方法是首先发送保存图片大小的 uint64_t(8 字节),然后发送数据本身。然后在服务器读取这些前 8 个字节之后 - 它会知道需要多少数据。然后您只需重复 recv() 调用,直到您获得客户端发送的所有数据。最好在服务器端使用select() 等待下一个数据部分可用。顺便说一句,如果您尝试发送的图片足够大(并且在大多数情况下是真的),它会通过 tcp 或 udp 连接部分发送,而不是一大块。而且它是不可预测的(硬件决定它)有多大的碎片或它们将被发送多少。所以你绝对应该准备好反复调用 recv() 来接收客户端发送到服务器的所有数据。

【讨论】:

感谢您的回答,但我正在做所有这些事情。我认为问题出在 Recv() 函数中,因为此函数非常慢。 在调用 recv() 之前是否使用了 select()?我在您发布的代码示例中看不到它。【参考方案6】:

我认为原因是您发送的数据大小, 因为当你通过网络发送大数据包时,底层会将这个大数据包分成小数据包,然后通过网络发送这些数据包。

所以当你收到这些数据包时,这些数据包的顺序可能会改变, 这就是为什么您收到相同大小的数据,但图像不正确。

我会给你一个快速的解决方案,你可以试试,

将文件分成小数组,假设每个数组为 1024 字节,首先发送这些数组的计数,然后开始发送第一个数组(1024 字节),然后等待对方确认,重复直到您发送所有数据。

您可以在不确认的情况下执行此操作,但在每次发送之间留出一段时间。

【讨论】:

这个方法我用过,还是有问题!! 这是 TCP。协议负责重新组装和重新排序。您的回答仅对 UDP 有意义。 -1【参考方案7】:

你犯了常见的错误。您不能假设 recv() 填充缓冲区。您必须循环直到获得所需的所有数据,并且必须使用 recv() 返回的计数值。

【讨论】:

我已经实现了这个方法但是没有回答问题!! 客户端代码:FILE *fr = fopen(tmppicsend, "rb"); while(size > 0) char buffer_s_p[1024]; if(size>1024) fread(buffer_s_p, 1024, 1, fr); send_len_pic+=send(m_socket_pic, buffer_s_p, 1024, 0);大小-= 1024; else fread(buffer_s_p, size, 1, fr); buffer_s_p[大小]='\0'; send_len_pic+=send(m_socket_pic,buffer_s_p,大小,0);大小 -= 大小; fclose(fr); @M.Rezaei 请,问题出在您的服务器代码中的recv(),而不是您的客户端代码中的send()... @M.Rezaei 您在上面的评论中发布的代码没有实现这个答案。但是,您已经在 34 年 10 月 22 日的回答中完全实现了这一点,并且根据您自己的声明,它确实解决了问题。

以上是关于Vue3中通过 input 标签 发送文件/图片给后端的主要内容,如果未能解决你的问题,请参考以下文章

MVC中通过jquery实现图片预览上传,并对文件类型大小进行判断(极简)

如何在vue3中通过点击按钮异步加载组件

在 iOS 中通过 GCDAsyncsocket 读取 xml 文件

在 c++ 中通过套接字(发送函数)发送图片,但不接收完整(Windows)!

如何在 Android 中通过电子邮件发送图片,预览但未附加..?

在 vue3 中通过 props 传递的组件