• php eayswoole node axios crypto-js 实现大文件分片上传复盘


    不啰嗦  直接上步骤

    步骤1.开发环境配置

    项目需要node.js 做前端支撑    官网下载地址:

    http://nodejs.cn/download/

    根据自己需要下载对应的版本,我下载的是windows系统64位的版本。

    包下载好后  进行安装,安装步骤在此省略...

    测试是否安装成功

    如果是window  按住键盘Win+R    输入cmd   在终端里面输入

    1. node -v
    2. npm-v

    如果安装成功会出现安装的node   npm   的软件版本号,否则为安装失败。如下图

    因为一些原因 npm 下载包巨慢    你懂得,所以我们这里选用淘宝镜像  打开终端   运行如下命令:

    npm install -g cnpm --registry=https://registry.npm.taobao.org

    安装好后  运行命令:

    1. cnpm -v
    2. cnpm@9.2.0 (C:\Users\King\AppData\Roaming\npm\node_modules\cnpm\lib\parse_argv.js)
    3. npm@9.8.1 (C:\Users\King\AppData\Roaming\npm\node_modules\cnpm\node_modules\npm\index.js)
    4. node@18.17.0 (D:\Program Files\node\node.exe)
    5. npminstall@7.11.1 (C:\Users\King\AppData\Roaming\npm\node_modules\cnpm\node_modules\npminstall\lib\index.js)
    6. prefix=C:\Users\King\AppData\Roaming\npm
    7. win32 x64 10.0.22621
    8. registry=https://registry.npmmirror.com

    步骤2.构想分片上传逻辑,编写逻辑代码(核心)

    基本思路:

    1)前端侧  :前端上传文件,根据分片大小,自动计算出整个文件的分片数量,以及分片二进制文件,以及整个文件的md5值,以及分片文件md5值,传与后端,后端处理完后,根据上传分片的进度以及后端返回状态,判断整个文件是否传输完毕,完毕后,前端展示完成进度。结束整个分片上传逻辑。

    2)后端PHP侧:后端接收前端传过来的数据,包括文件名,文件md5,分片信息,然后将分片文件信息存储到redis  有序集合中,其中key为整个文件的md5 ,待所有分片文件都上传完后,根据顺序,然后将文件整合存储,然后完成整个文件分片上传逻辑。

    下面我们来编写相关代码 :

    前置条件  我们已经安装了此环境   环境如下:

    运行环境版本
    Linuxcentos  7.7.1908
    PHP 7.4.19
    redis6.2.1
    swoole扩展4.8.13
    eayswoole3.5.1

     首先我们需要使用到redis  部分代码如下:

    首先配置redis 相关信息  此处我们将配置文件放在根目录下Config 目录 Redis.php中  代码如下:

    1. [root@web1 easyswoole]# cd Config
    2. ll
    3. [root@web1 Config]# ll
    4. 总用量 28
    5. -rw-r--r-- 1 root root 8725 9月 23 19:09 Common.php
    6. -rw-r--r-- 1 root root 1450 9月 4 21:21 Iam.php
    7. -rw-r--r-- 1 root root 3027 8月 29 18:47 Mimes.php
    8. -rw-r--r-- 1 root root 1795 9月 4 19:21 Mysql.php
    9. -rw-r--r-- 1 root root 948 9月 23 17:50 Redis.php
    10. [root@web1 Config]# vim Redis.php
    11. return [
    12. 'redis' => [
    13. # 默认redis 配置
    14. 'REDIS' => [
    15. 'host' => '127.0.0.1',
    16. 'port' => '6390',
    17. 'auth' => '123456',
    18. 'db' => '1',
    19. 'serialize' => 0
    20. ],
    21. # token存储redis,用来设置接口权限
    22. 'REDIS_LOCAL' => [
    23. 'host' => '127.0.0.1',
    24. 'port' => '6390',
    25. 'auth' => '123456',
    26. 'db' => 5,
    27. 'serialize' => 0
    28. ],
    29. ]
    30. ];

    配置上传目录  后续Upload.php 控制器需要读取  Config/Common.php 代码如下:

    1. use EasySwoole\EasySwoole\Config;
    2. defined('BASEPATH') or define('BASEPATH', dirname(__FILE__) . '/../..');
    3. defined('WEB_IP') or define('WEB_IP', '192.168.1.1');
    4. return [
    5. // 此处省略其他配置信息 .....
    6. 'WEB_IP' => WEB_IP,
    7. 'WEB_PATH' => BASEPATH,
    8. 'UPLOAD' => [
    9. 'tmp_dir' => '/uploads_tmp/',//分片文件缓存目录
    10. 'upload_dir' => '/uploads/',//文件现在目录
    11. ],
    12. // 此处省略其他配置信息 .....
    13. ];

    接下来需要定义连接池  直接上代码   

    1. cd App/Pool 
    2. touch RedisPool.php
    1. /**
    2. * redis连接池配置处理
    3. */
    4. namespace App\Pool;
    5. use EasySwoole\Pool\Config;
    6. use EasySwoole\Redis\Config\RedisConfig;
    7. use EasySwoole\Redis\Redis;
    8. class RedisPool extends \EasySwoole\Pool\AbstractPool {
    9. protected $redis_config;
    10. public function __construct(Config $conf, RedisConfig $redis_config) {
    11. parent::__construct($conf);
    12. $this->redis_config = $redis_config;
    13. }
    14. protected function createObject() {
    15. return new Redis($this->redis_config);
    16. }
    17. }

    接下来,在入口文件EasySwooleEvent.php 注册redis 连接池

    1. namespace EasySwoole\EasySwoole;
    2. use App\Pool\RedisPool;
    3. use EasySwoole\Redis\Config\RedisConfig;
    4. class EasySwooleEvent implements Event {
    5. public static function mainServerCreate(EventRegister $register) {
    6. //其他逻辑 此处省略....
    7. //注册redis
    8. self::initRedis();
    9. //连接池热启动
    10. $register->add($register::onWorkerStart, function (\swoole_server $server, int $workerId) {
    11. if ($server->taskworker == false) {
    12. //每个worker进程都预创建连接
    13. $redis_arr = Config::getInstance()->getConf('redis');
    14. foreach ($redis_arr as $redis_name => $redis_conf) {
    15. \EasySwoole\Pool\Manager::getInstance()->get(strtolower($redis_name))->keepMin(10);
    16. //print_r(\EasySwoole\Pool\Manager::getInstance()->get(strtolower($redis_name))->status());
    17. }
    18. }
    19. });
    20. //其他逻辑 此处省略....
    21. }
    22. /**
    23. * 注册redis连接池
    24. */
    25. public static function initRedis() {
    26. // 注册redis连接池
    27. $redis_arr = Config::getInstance()->getConf('redis');
    28. foreach ($redis_arr as $redis_name => $conf) {
    29. $config = new \EasySwoole\Pool\Config();
    30. $config->setMinObjectNum(8);
    31. $config->setMaxObjectNum(200);
    32. $config->setGetObjectTimeout(3.0);
    33. $redis_config = new RedisConfig($conf);
    34. //注册连接池管理对象
    35. \EasySwoole\Pool\Manager::getInstance()->register(new RedisPool($config, $redis_config), strtolower($redis_name));
    36. }
    37. }
    38. }

     接下来  新增相关路由信息

    1. /*
    2. * 路由
    3. */
    4. namespace App\HttpController;
    5. use EasySwoole\EasySwoole\Config;
    6. use EasySwoole\Http\AbstractInterface\AbstractRouter;
    7. use EasySwoole\Http\Request;
    8. use EasySwoole\Http\Response;
    9. use FastRoute\RouteCollector;
    10. class Router extends AbstractRouter
    11. {
    12. function initialize(RouteCollector $routeCollector)
    13. {
    14. $routeCollector->addGroup('/api/common', function (RouteCollector $router) {
    15. $router->post('/upload_file', '/Api/Upload/uploadFile'); //分片上传文件
    16. $router->post('/slice_upload_check', '/Api/Upload/checkFile'); //分片上传文件检测
    17. });
    18. }
    19. }

     Upload.php 相关控制器   代码如下:

    1. /**
    2. * 文件上传(支持分片上传)
    3. */
    4. namespace App\HttpController\Api;
    5. use EasySwoole\Http\AbstractInterface\Controller;
    6. use EasySwoole\EasySwoole\Config;
    7. use EasySwoole\EasySwooleEvent;
    8. use EasySwoole\RedisPool\Redis;
    9. use EasySwoole\Http\Message\Stream;
    10. class Upload extends Controller
    11. {
    12. /**
    13. * Notes: 存储文件到本地
    14. */
    15. public function saveFileToLocalAction()
    16. {
    17. // $request = $this->request()->getRequestParam();
    18. $file = $this->request()->getUploadedFile('file');//上传的文件
    19. if (!$file) {
    20. return $this->returnMsg( [],50000,'上传出错请重试,请上传文件');
    21. }
    22. $tmp_file_name = $file->getClientFilename();
    23. $conf = Config::getInstance()->getConf();
    24. $dir = $conf["WEB_PATH"] . $conf['UPLOAD']['upload_dir'];
    25. if (!file_exists($dir)) {
    26. mkdir($dir, 0777);
    27. }
    28. $file_ext = uniqid();
    29. $suf_exp_arr = explode(".", $tmp_file_name);
    30. $file_name = $suf_exp_arr[0];
    31. #$move_to = $dir.$tmp_file_name;
    32. $move_to = $dir . $file_name . '_' . $file_ext . '.' . $suf_exp_arr[count($suf_exp_arr) - 1];
    33. if (file_exists($move_to)) {
    34. return $this->returnMsg( [],1,'已上传同名文件,请修改后再上传!');
    35. }
    36. if (!move_uploaded_file($file->getTempName(), $move_to)) {
    37. return $this->returnMsg( [],1,'上传失败,请稍后再试!');
    38. }
    39. $file_url = "http://" . $conf['WEB_IP'] . $conf['UPLOAD']['upload_dir'] . $file_name . '_' . $file_ext . '.' . $suf_exp_arr[count($suf_exp_arr) - 1];
    40. $return['file_url'] = $file_url;
    41. $return['img_url'] = $file_url;
    42. $return['file_name'] = $file_name . '_' . $file_ext . '.' . $suf_exp_arr[count($suf_exp_arr) - 1];
    43. return $this->returnMsg($return,0, "success");
    44. }
    45. /***
    46. * 文件检查
    47. * @return bool
    48. */
    49. public function checkFile()
    50. {
    51. $request = $this->request()->getRequestParam();
    52. $suf_exp_arr = explode(".", $request['file_name']);
    53. $suf = $suf_exp_arr[count($suf_exp_arr) - 1];
    54. $can_upload_arr = [
    55. 'zip',
    56. '3G2',
    57. '3GP',
    58. '3GP2',
    59. '3GPP',
    60. 'AMV',
    61. 'ASF',
    62. 'AVI',
    63. 'BIK',
    64. 'DIVX',
    65. 'DRC',
    66. 'DV',
    67. 'DVR-MS',
    68. 'EVO',
    69. 'F4V',
    70. 'FLV',
    71. 'GVI',
    72. 'GXF',
    73. 'M1V',
    74. 'M2T',
    75. 'M2TS',
    76. 'M2V',
    77. 'M4V',
    78. 'MKV',
    79. 'MOV',
    80. 'MP2V',
    81. 'MP4',
    82. 'MP4V',
    83. 'MPA',
    84. 'MPEG',
    85. 'MPEG1',
    86. 'MPEG2',
    87. 'MPEG4',
    88. 'MPG',
    89. 'MPV2',
    90. 'MTS',
    91. 'MTV',
    92. 'MXF',
    93. 'NSV',
    94. 'NUV',
    95. 'REC',
    96. 'RM',
    97. 'RMVB',
    98. 'RPL',
    99. 'THP',
    100. 'TP',
    101. 'TS',
    102. 'TTS',
    103. 'VOB',
    104. 'VRO',
    105. 'WMV',
    106. 'WTV',
    107. 'XESC',
    108. 'XMP',
    109. 'OGG',
    110. 'SWF',
    111. 'WEBM',
    112. 'GIF',
    113. '264',
    114. '601',
    115. '692',
    116. '800',
    117. '801',
    118. 'av',
    119. 'avx',
    120. 'dat',
    121. 'dav',
    122. 'djl',
    123. 'dvr',
    124. 'g64',
    125. 'h3crd',
    126. 'h64',
    127. 'h264',
    128. 'jfv',
    129. 'jmv',
    130. 'kyd',
    131. 'lvf',
    132. 'mpk',
    133. 'nsf',
    134. 'nv4',
    135. 'ps',
    136. 'sdv',
    137. 'sv5',
    138. 'tm4',
    139. ];
    140. if (!in_array(strtoupper($suf), $can_upload_arr) && !in_array(strtolower($suf), $can_upload_arr)) {
    141. return $this->returnMsg([], 30000, '请上传正确格式的文件');
    142. }
    143. //判断是否包含特殊字符
    144. if (strpos($suf_exp_arr[0], ',') !== false) {
    145. return $this->returnMsg([], 30000, '文件名不能包含英文逗号');
    146. }
    147. if (strpos($suf_exp_arr[0], ',') !== false) {
    148. return $this->returnMsg([], 30000, '文件名不能包含中文逗号');
    149. }
    150. $redis_key = $request['file_md5'] ?? '';
    151. $file_chunk_md5 = $request['file_chunk_md5'] ?? '';
    152. $status = \EasySwoole\Pool\Manager::getInstance()->get('redis')->invoke(function (\EasySwoole\Redis\Redis $redis) use ($redis_key, $file_chunk_md5) {
    153. $all_files = $redis->zRange($redis_key, 0, -1);
    154. if (in_array($file_chunk_md5, $all_files)) {
    155. $status = 1;
    156. } else {
    157. $status = 0;
    158. }
    159. return $status;
    160. });
    161. return $this->returnMsg([], $status);
    162. }
    163. /***
    164. * 文件上传
    165. */
    166. public function uploadFile()
    167. {
    168. $request = $this->request()->getRequestParam();
    169. $all_chunk = $request['chunks'];//总分片数
    170. $now_chunk = $request['cur_chunk'];//当前分片
    171. //$original_filename = $request['original_filename']; //原始文件名
    172. $file = $this->request()->getUploadedFile('file_chunk');//上传的文件
    173. if (!$file) {
    174. $json = [
    175. 'status' => 1,
    176. 'message' => '上传出错请重试'
    177. ];
    178. $this->response()->write(json_encode($json));
    179. return null;
    180. }
    181. $conf = Config::getInstance()->getConf();
    182. $dir = $conf["WEB_PATH"] . $conf['UPLOAD']['upload_dir'];
    183. $tmp_dir = $conf["WEB_PATH"] . $conf['UPLOAD']['tmp_dir'];//分片数据暂存文件夹
    184. if (!file_exists($dir)) {
    185. mkdir($dir, 0777);
    186. }
    187. if (!file_exists($tmp_dir)) {
    188. mkdir($tmp_dir, 0777);
    189. }
    190. $suf_exp_arr = explode(".", $request['file_name']);
    191. $suf = $suf_exp_arr[count($suf_exp_arr) - 1];
    192. if (move_uploaded_file($file->getTempName(), $tmp_dir . $request['file_chunk_md5'])) {
    193. //使用redis的有序集合存储文件名称用于合并
    194. $redis_key = $request['file_md5'];
    195. $file_status = \EasySwoole\Pool\Manager::getInstance()->get('redis')->invoke(function (\EasySwoole\Redis\Redis $redis) use ($redis_key, $request, $tmp_dir, $dir, $now_chunk, $all_chunk, $suf, $suf_exp_arr) {
    196. $redis->expire($redis_key, 7200); //2小时后过期
    197. $redis->zAdd($redis_key, $request['cur_chunk'] + 1, $tmp_dir . $request['file_chunk_md5']);
    198. if ($now_chunk == $all_chunk) {
    199. //文件合并
    200. $all_files = $redis->zRange($redis_key, 0, -1);
    201. if ($all_files && is_array($all_files)) {
    202. //创建要合并的最终文件资源
    203. $final_file = $dir . $request['file_md5'] . '.' . $suf;
    204. $final_file_handler = fopen($final_file, 'wb');
    205. foreach ($all_files as $k => $v) {
    206. $frag_file_handler = fopen($v, 'rb');
    207. $frag_file_content = fread($frag_file_handler, filesize($v));
    208. fwrite($final_file_handler, $frag_file_content);
    209. unset($frag_file_content);
    210. fclose($frag_file_handler); //关闭分片文件资源
    211. unlink($v); //删除已经合并的分片文件
    212. }
    213. $redis->zRemRangeByRank($redis_key, 0, -1);
    214. $save_path = $dir . "/" . date('Ymd', time());
    215. if (!file_exists($save_path)) {
    216. mkdir($save_path, 0777);
    217. }
    218. $new_file = $save_path . '/' . $request['file_md5'] . '.' . $suf;
    219. $status = rename($final_file, $new_file);
    220. return 'end';
    221. }
    222. } else {
    223. return 'ing';
    224. }
    225. });
    226. if (!in_array($file_status, ['end', 'ing'])) {
    227. $json = [
    228. 'status' => 1,
    229. 'message' => '上传出错请重试,重命名失败'
    230. ];
    231. } else {
    232. $json = [
    233. 'status' => 0,
    234. 'message' => 'success',
    235. 'time' => time(),
    236. //'file_url' => "http://" . $conf["WEB_IP"] . $conf['UPLOAD']['upload_dir'] . $request['file_md5'] . '.' . $suf,//文件链接,
    237. 'file_url' => "http://" . $conf["WEB_IP"] . $conf['UPLOAD']['upload_dir'] . '/' . date('Ymd', time()) . '/' . $request['file_md5'] . '.' . $suf,//文件链接,
    238. 'data' => [],
    239. 'file_status' => $file_status,
    240. ];
    241. }
    242. } else {
    243. $json = [
    244. 'status' => 1,
    245. 'message' => '上传出错请重试'
    246. ];
    247. }
    248. $this->response()->write(json_encode($json));
    249. }
    250. /**
    251. * @name: 返回值处理
    252. * @msg:
    253. * @param {array} $data
    254. * @param {int} $status
    255. * @param {string} $message
    256. * @param {array} $other
    257. * @param {int} $statusCode
    258. * @return {*}
    259. */
    260. public function returnMsg(array $data = [], int $status = 0, string $message = 'success', array $other = [], int $statusCode = 200)
    261. {
    262. $return = [
    263. 'status' => $status,
    264. 'message' => $message,
    265. 'data' => $data,
    266. ];
    267. if ($other) {
    268. foreach ($other as $k => $v) {
    269. $return[$k] = $v;
    270. }
    271. }
    272. $this->response()->withHeader('Content-type', 'application/json;charset=utf-8')
    273. ->withStatus($statusCode)
    274. ->write(json_encode($return));
    275. $this->response()->end();
    276. return false;
    277. }
    278. }

    步骤3.后端测试好后,我们需要编写前端页面   

    前面已经说过  我们需要node npm 前端环境,如果已经安装好了  请忽略

    1)我们在任意一个目录下  打开终端cmd   然后运行命令  安装vue 脚手架:

    npm install -g @vue/cli

    2)创建一个新的Vue.js项目:

    npm create vue@latest

    一路按一下回车键

    如下图:

    3)进入项目目录:

    进入创建的Vue.js项目目录:

    cd vue-project

    运行

    npm install 

    4)安装axios 和 crypto-js 

    cnpm install axios

    cnpm install crypto-js

     5) 创建vue 实例

    在Vue项目的入口文件中(通常是 src/main.js),创建Vue实例并将Vue组件添加到实例中。如下图:

    6)实现上传  

    在Vue项目的入口文件中  src/App.vue  编写如下代码:

    1. <template>
    2. <div>
    3. <input type="file" ref="fileInput" @change="handleFileChange" />
    4. <button @click="uploadFile">上传button>
    5. <div v-if="uploadProgress > 0 && !uploadComplete">
    6. 上传进度: {{ uploadProgress }}%
    7. div>
    8. <div v-if="uploadComplete">上传完成div>
    9. div>
    10. template>
    11. <script>
    12. import axios from "axios";
    13. import CryptoJS from "crypto-js";
    14. export default {
    15. data() {
    16. return {
    17. file: null,
    18. chunkSize: 1024 * 1024, // 分片大小(1MB)
    19. currentChunk: 1, // 当前分片
    20. totalChunks: 0, // 总分片数
    21. fileMD5: "", // 文件的MD5值
    22. uploadProgress: 0, // 上传进度
    23. uploadComplete: false, // 上传是否完成
    24. };
    25. },
    26. methods: {
    27. handleFileChange(event) {
    28. // 重置上传状态
    29. this.uploadProgress = 0;
    30. this.uploadComplete = false;
    31. this.fileMD5 = "";
    32. this.file = event.target.files[0];
    33. this.totalChunks = Math.ceil(this.file.size / this.chunkSize);
    34. // 计算整个文件的MD5值
    35. const fileReader = new FileReader();
    36. fileReader.onload = () => {
    37. const fileData = fileReader.result;
    38. const wordArray = CryptoJS.lib.WordArray.create(fileData);
    39. this.fileMD5 = CryptoJS.MD5(wordArray).toString(CryptoJS.enc.Hex);
    40. console.log(this.fileMD5);
    41. };
    42. fileReader.readAsArrayBuffer(this.file);
    43. },
    44. async uploadFile() {
    45. if (!this.fileMD5) {
    46. console.error("文件MD5值为空");
    47. return;
    48. }
    49. // 并发处理每个分片文件
    50. const promises = [];
    51. for (let i = 1; i <= this.totalChunks; i++) {
    52. const chunkMD5 = await this.calculateChunkMD5(i);
    53. // 发起检查分片状态的请求
    54. const checkFormData = new FormData();
    55. checkFormData.append("file_name", this.file.name);
    56. checkFormData.append("file_md5", this.fileMD5);
    57. checkFormData.append("file_chunk_md5", chunkMD5);
    58. checkFormData.append("chunks", this.totalChunks);
    59. checkFormData.append("cur_chunk", i);
    60. promises.push(
    61. axios.post("/api/SPAP1/api/common/slice_upload_check", checkFormData).then((checkResponse) => {
    62. if (checkResponse.data.status !== 0) {
    63. alert(checkResponse.data.message);
    64. console.error("分片状态检查失败,请上传正确格式的文件");
    65. throw new Error("分片状态检查失败");
    66. }
    67. // 发起分片上传请求
    68. const startByte = (i - 1) * this.chunkSize;
    69. const endByte = Math.min(i * this.chunkSize, this.file.size);
    70. const chunk = this.file.slice(startByte, endByte);
    71. const uploadFormData = new FormData();
    72. uploadFormData.append("file_name", this.file.name);
    73. uploadFormData.append("file_md5", this.fileMD5);
    74. uploadFormData.append("file_chunk_md5", chunkMD5);
    75. uploadFormData.append("chunks", this.totalChunks);
    76. uploadFormData.append("cur_chunk", i);
    77. uploadFormData.append("file_chunk", chunk);
    78. return axios.post("/api/SPAP1/api/common/upload_file", uploadFormData, {
    79. onUploadProgress: (progressEvent) => {
    80. // 计算并更新上传进度
    81. const chunkUploaded = Math.round((progressEvent.loaded / progressEvent.total) * 100);
    82. this.uploadProgress = ((i - 1) / this.totalChunks) * 100 + (chunkUploaded / this.totalChunks);
    83. },
    84. }).then((uploadResponse) => {
    85. // 检查上传请求的响应
    86. if (uploadResponse.data.status !== 0) {
    87. alert(uploadResponse.data.message);
    88. console.error("上传请求失败,请上传正确格式的文件");
    89. throw new Error("上传请求失败");
    90. }
    91. // 如果文件状态为 "end",标记上传完成
    92. if (uploadResponse.data.file_status == "end") {
    93. this.uploadComplete = true;
    94. }
    95. });
    96. })
    97. );
    98. }
    99. try {
    100. await Promise.all(promises);
    101. if (this.uploadComplete) {
    102. alert("上传完成");
    103. console.log("上传完成");
    104. }
    105. } catch (error) {
    106. console.error("上传失败", error);
    107. }
    108. },
    109. calculateChunkMD5(chunkNumber) {
    110. return new Promise((resolve) => {
    111. const startByte = (chunkNumber - 1) * this.chunkSize;
    112. const endByte = Math.min(chunkNumber * this.chunkSize, this.file.size);
    113. const chunk = this.file.slice(startByte, endByte);
    114. const reader = new FileReader();
    115. reader.onload = (e) => {
    116. const arrayBuffer = e.target.result;
    117. const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer);
    118. const md5 = CryptoJS.MD5(wordArray).toString(CryptoJS.enc.Hex);
    119. resolve(md5);
    120. };
    121. reader.readAsArrayBuffer(chunk);
    122. });
    123. },
    124. },
    125. };
    126. script>

    7)考虑到上面的axios 发送接口会与前端报跨域报错   故此这里采用axios 代理模式  进行处理

    怎么解决跨域呢 

    在最外面的vite.config.js 文件中,加入server 这个参数  

    1. import { fileURLToPath, URL } from 'node:url'
    2. import { defineConfig } from 'vite'
    3. import vue from '@vitejs/plugin-vue'
    4. // https://vitejs.dev/config/
    5. export default defineConfig({
    6. plugins: [
    7. vue(),
    8. ],
    9. resolve: {
    10. alias: {
    11. '@': fileURLToPath(new URL('./src', import.meta.url))
    12. }
    13. },
    14. server: {
    15. hmr: { overlay: false }, // 禁用或配置 HMR 连接 设置 server.hmr.overlay 为 false 可以禁用服务器错误遮罩层
    16. // 服务配置
    17. port: 8080, // 类型: number 指定服务器端口;
    18. open: false, // 类型: boolean | string在服务器启动时自动在浏览器中打开应用程序;
    19. cors: true, // 类型: boolean | CorsOptions 为开发服务器配置 CORS。默认启用并允许任何源
    20. proxy: {
    21. '/api': {
    22. target: 'http://192.168.31.128:86', // Your backend server URL
    23. changeOrigin: true,
    24. pathRewrite: {
    25. '^/api': '', // Remove the '/api' prefix when forwarding the request
    26. },
    27. },
    28. }
    29. }
    30. })

    其中port 为前端页面端口   target 为后端接口地址   其他可以不变。

    8)调试运行

    在命令行运行调试命令:

    npm run dev

    9) 打开页面

    上传一个正常的文件 

    Nice 基本上整个文件分片上传就完成了 

  • 相关阅读:
    分布式版本控制工具 Git 的使用方式
    千兆以太网
    面试经验分享 | 驻场安全服务工程师面试
    全流量分析应用运行和访问情况
    闭包和装饰器
    理解Go中的数据类型
    centos安装redis教程
    Vue中v-on的基础用法、参数传递和修饰符
    (论文阅读32/100)Flowing convnets for human pose estimation in videos
    2023高教杯数学建模1:ABC题目+初步想法
  • 原文地址:https://blog.csdn.net/u013416034/article/details/133268179