前端

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Document</title>
  7. </head>
  8. <body>
  9. <input type="file" id="file">
  10. </body>
  11. </html>
  12. <script>
  13. document.getElementById('file').addEventListener('change', async (e) => {
  14. const file = e.target.files[0];
  15. // 获取文件名
  16. const file_name = file.name.split('.')[0]
  17. let cur = 0;
  18. let size = 1024 * 1024;
  19. const fileChunks = [];
  20. while (cur < file.size) {
  21. fileChunks.push({
  22. file: file.slice(cur, cur + size)
  23. })
  24. cur += size;
  25. }
  26. // 转成请求数组 里面每个都是formData
  27. const requestList = fileChunks
  28. .map(({ file }, index) => {
  29. const formData = new FormData();
  30. formData.append('chunk', file);
  31. // 根据名称加下标格式发送 图片-1
  32. formData.append('file_name', `${file_name}-${index}`)
  33. return { formData }
  34. })
  35. .map(async ({ formData }) => request({
  36. url: "http://localhost:3000",
  37. data: formData
  38. })
  39. )
  40. // 并发发送
  41. await Promise.all(requestList)
  42. // console.log(requestList);
  43. await mergeRequest()
  44. })
  45. // 封装请求
  46. function request({
  47. url,
  48. method = "POST",
  49. data,
  50. header = {},
  51. requestList, // 上传文件列表
  52. }) {
  53. return new Promise(resolve => {
  54. const xhr = new XMLHttpRequest(); // ajax对象
  55. // 请求
  56. xhr.open(method, url)
  57. // 设置请求头
  58. Object.keys(header).forEach(key => {
  59. xhr.setRequestHeader(key, header[key])
  60. });
  61. // 发送数据
  62. xhr.send(data)
  63. xhr.onload = e => {
  64. resolve({
  65. data: e.target.response
  66. })
  67. }
  68. })
  69. }
  70. // 上传成功 合并切片
  71. const mergeRequest = async () => {
  72. await request({
  73. url: "http://localhost:3000/merge",
  74. header: {
  75. "content-type": "application/json"
  76. }
  77. })
  78. alert('ok')
  79. }
  80. </script>

后端

  1. const http = require('http');
  2. const path = require('path');
  3. // 处理表单
  4. const multiparty = require('multiparty')
  5. const server = http.createServer();
  6. const fse = require('fs-extra')
  7. // 要存放切片的地址
  8. const UPLOAD_URL = path.resolve(__dirname, 'target');
  9. server.on('request', async (req, res) => {
  10. res.setHeader('Access-Control-Allow-Origin', "*")
  11. res.setHeader('Access-Control-Allow-Method', "*")
  12. // res.end('ok')
  13. if (req.url === '/') {
  14. // 获取文件/名称;
  15. // 获取POST传过来的表单数据
  16. const multipart = new multiparty.Form();
  17. multipart.parse(req, async (err, fields, files) => {
  18. if (err) {
  19. return;
  20. }
  21. // 获取文件块
  22. const [chunk] = files.chunk;
  23. // 获取文件名称
  24. const [filename] = fields.file_name;
  25. // 切片后的名称
  26. const dir_name = filename.split('-')[0];
  27. // 文件名称地址
  28. const chunkDir = path.resolve(UPLOAD_URL, dir_name)
  29. // 如果这个地址不存在 就创建一个吧
  30. if(!fse.existsSync(chunkDir)){
  31. await fse.mkdirs(chunkDir)
  32. }
  33. // 切片后的文件放到指定文件中夹
  34. await fse.move(chunk.path,`${chunkDir}/${filename}`)
  35. console.log(chunkDir,filename);
  36. })
  37. }else if(req.url === '/merge'){
  38. // 把server/app.js里面合并的代码拿过来就可以
  39. res.end('合并成功')
  40. }
  41. })
  42. server.listen(3000, () => console.log('http://localhost:3000'))