你有在上传文件下载文件踩过坑吗?

上传

上传文件的需求很常见,但还是很容易踩坑,特别是对于之前没用做过类似需求的小伙伴。

  • 首先文件上传请求的参数传递方式通常使用 multipart/form-data 格式。这是一种专门用于在 HTTP 请求中传递二进制文件数据的标准方法。
 fetch('/upload', {
    method: 'POST',
    headers: {
      'Content-Type': 'multipart/form-data',
    },
    body: JSON.stringify(data),
  })
    .then(response => response.json())
    .then(data => {
      console.log('Response from server:', data);
    })
    .catch(error => {
      console.error('Error:', error);
    });
// axios
axios.post(url, formData, {
  headers: {
    'Content-Type': 'multipart/form-data', // 设置请求头
  },
})
  .then(response => {
    console.log('Response from server:', response.data);
    // 处理成功响应
  })
  .catch(error => {
    console.error('Error:', error);
    // 处理错误
  });
  • 获取文件内容,表单提交时和其他字段信息一起上传
    1. 传统的html
<input type="file" id="fileInput">
<button onclick="readFile()">Read Filebutton>
function readFile() {
  const fileInput = document.getElementById('fileInput');
  const file = fileInput.files[0]; // 获取选择的文件

  if (file) {
    const reader = new FileReader();
    reader.onload = function (event) {
      const fileContent = event.target.result;
      // 在这里处理文件内容
      console.log('File content:', fileContent);
      // 在此可以将文件内容与其他信息一起提交到后端
      // 使用 fetch 或其他 AJAX 方法将数据发送到后端
    };
    reader.readAsText(file); // 使用文本格式读取文件
  } else {
    console.log('No file selected.');
  }
}

  1. 基于ant design
    我这里些了多个显示文件的格式。在实际的需求中可以参考使用
import React, { useState } from "react";
import { Input, Tag, Upload } from "antd";
import { DeleteOutlined, FolderOpenOutlined } from "@ant-design/icons";
import _ from "lodash";

import "./style.less";
const UploadCom = () => {
  const [fileList, setFileList] = useState<any>([]);

  const renderList = () => {
    return (
      <div className="tagWrapper">
        {_.map(fileList, (file: any) => {
          return (
            <Tag
              key={file.uid}
              className="tag"
              closable
              onClose={() => {
                setFileList((pre: any) =>
                  _.filter(pre, (p) => p?.uid !== file.uid)
                );
              }}
            >
              <span className="tagText">{file?.name}</span>
            </Tag>
          );
        })}
      </div>
    );
  };
  return (
    <div className="uploadWrapper">
      <div>
        <p>tag形式上传多个文件:</p>
        <Upload
          fileList={[]}
          multiple={true}
          showUploadList={false}
          beforeUpload={(file) => {
            setFileList((pre: any) => [...pre, file]);
            // 如果是在表单里统一提交。这里需要return false
            return false;
          }}
        >
          {/* 文件样式展示多个tag */}
          {renderList()}
        </Upload>
      </div>

      <div style={{ margin: "20px 0" }}>
        <p>上传单个文件输入框类型:</p>
        <Upload
          fileList={[]}
          multiple={true}
          showUploadList={false}
          beforeUpload={(file) => {
            setFileList((pre: any) => [...pre, file]);
            // 如果是在表单里统一提交。这里需要return false
            return false;
          }}
        >
          {/* 单个文件显示文件名 */}
          <Input
            placeholder="请选择文件"
            value={fileList?.[0]?.name}
            prefix={
              <FolderOpenOutlined style={{ color: "rgba(0,0,0,0.65)" }} />
            }
          />
        </Upload>
      </div>

      <div>
        <p>列表形式:</p>
        {_.map(fileList, (file) => {
          return (
            <div className="file-list-item">
              <div> {file.name}</div>
              <DeleteOutlined
                onClick={() => {
                  setFileList((pre: any) =>
                    _.filter(pre, (p) => p?.uid !== file.uid)
                  );
                }}
              />
            </div>
          );
        })}
      </div>
    </div>
  );
};
export default UploadCom;

style:

.uploadWrapper{
  padding: 24px;
  .tagWrapper{
    display: flex;
    align-items: center;
    width: 300px;
    height: 32px;
    border: 1px solid #d9d9d9;
    padding: 0 12px;

    .tag{
      width: 80px;
      display: flex;
      align-items: center;
    
      .tagText{
        width: 50px;
        display: inline-block;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
      }
    }
  }
  .file-list-item{
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 300px;
  }
}

下载

  • 下载文件就需要指定响应文件格式responseType为blob二进制文件流,否则很可能打不开文件,说文件内容被损坏。
  • 创建一个 Blob 对象,并将其转换为下载链接
import axios from 'axios';

const url = '/download'; // 下载文件的后端端点

axios.get(url, {
  responseType: 'blob', // 指定响应类型为二进制数据(Blob)
})
  .then(response => {
    const blob = new Blob([response.data]{ type: 'text/plain' }); // 文本文档为例
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'filename.ext'; // 设置下载的文件名
    a.style.display = 'none';
    document.body.appendChild(a);
    a.click();
    window.URL.revokeObjectURL(url);
  })
  .catch(error => {
    console.error('Error:', error);
    // 处理下载失败
  });

其他文件类型

在创建 Blob 对象时,根据文件类型指定 type 参数的值。

  1. JSON 文件

    • application/json:用于表示 JSON 数据。
    • 示例:
      const jsonBlob = new Blob([jsonData], { type: 'application/json' });
      
  2. ZIP 文件

    • application/zip:用于表示 ZIP 压缩文件。
    • 示例:
      const zipBlob = new Blob([zipData], { type: 'application/zip' });
      
  3. Excel 文件

    • 对于旧版的 Excel 文件(.xls):application/vnd.ms-excel
    • 对于新版的 Excel 文件(.xlsx):application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
    • 示例:
      const excelBlob = new Blob([excelData], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
      
  4. Word 文件

    • 对于旧版的 Word 文件(.doc):application/msword
    • 对于新版的 Word 文件(.docx):application/vnd.openxmlformats-officedocument.wordprocessingml.document
    • 示例:
      const wordBlob = new Blob([wordData], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
      

本文总结的只是个人经验,如有问题,不吝指教。

你可能感兴趣的:(okhttp,前端,上传文件,下载文件)