vue3和gin框架实现简单的断点续传

news2025/3/6 3:20:00

vue3和gin框架实现简单的断点续传

前端代码

Test.vue

<template>
  <div>
    <input
      type="file"
      ref="uploadRef"
      @change="upload"
      multiple
    />
    <template
      v-for="item in fileList"
      :key="item.key"
    >
      <br>
      <button @click="changeStauts(item.key)">{{item.name}}{{ item.status ? '暂停':'开始' }} {{ ((1 - item.requestFn.length / item.total)*100).toFixed(0) }}%</button>
    </template>
  </div>
</template>
<script setup>
import { reactive } from "vue";
import axios from "axios";
import "./spark-md5.min.js";
// 触发上传 (1)
function upload() {
  let files = event.target.files;
  for (let i = 0; i < files.length; i++) {
    setFileBuffer(files[i], i);
  }
}
let fileList = reactive([]);
// 创建切片相关信息 (2)
function setFileBuffer(file, i) {
  const reader = new FileReader();
  reader.onload = async () => {
    let key = await setChunkHash(reader.result);
    fileList.push({
      total: 0,
      status: true,
      name: file.name,
      requestFn: [],
      key: key,
      hashList: [],
    });
    setChunk(reader.result, 0, key);
  };
  reader.readAsArrayBuffer(file);
}
function arrayBufferToBlob(arrayBuffer) {
  return new Blob([arrayBuffer]);
}
let fileSize = 10 * 1024 * 1024; // 1M
// 为每个切片封装ajax请求
function setChunk(fileBuffer, i = 0, key) {
  let index = i + fileSize;
  let isEnd = false;
  if (index > fileBuffer.byteLength) {
    index = fileBuffer.byteLength;
    isEnd = true;
  }
  // 根据key,获取当前文件处于fileList中的下标
  const keyIndex = fileList.findIndex((item) => item.key == key);
  // 封装每个切片
  fileList[keyIndex].requestFn.push(() => {
    return new Promise(async (reslove, reject) => {
      let formData = new FormData();
      let content = fileBuffer.slice(i, index);
      formData.append("file", arrayBufferToBlob(content));
      formData.append("key", key);
      const chunkHash = await setChunkHash(fileBuffer.slice(i, index));
      formData.append("hash", chunkHash);
      fileList[keyIndex].hashList.push(chunkHash);
      formData.append("file_size", index - i);
      await apiUploadFile(formData); // apiUploadFile 为上传接口
      fileList[keyIndex].requestFn.splice(0, 1);
      reslove(true);
    });
  });
  // 判断当前文件的切片是否已经全部封装
  if (isEnd) {
    fileList[keyIndex].total = fileList[keyIndex].requestFn.length;
    startUpload(key);
    return;
  } else {
    setChunk(fileBuffer, index, key);
  }
}
// 开始上传(步骤3)
async function startUpload(key) {
  const keyIndex = fileList.findIndex((item) => item.key == key);
  await fileList[keyIndex].requestFn[0]();
  if (fileList[keyIndex].requestFn.length > 0) {
    if (fileList[keyIndex].status) {
      startUpload(key);
    }
  } else {
    // 上传完毕,请求合并文件
    const { data } = await mergeFile({
      chunkFiles: fileList[keyIndex].hashList,
      key: key,
      fileName: fileList[keyIndex].name,
    });
  }
}
// 暂停或者继续
function changeStauts(key) {
  const keyIndex = fileList.findIndex((item) => item.key == key);
  fileList[keyIndex].status = !fileList[keyIndex].status;
  if (fileList[keyIndex].status) {
    startUpload(key);
  }
}

// 计算hash值
function setChunkHash(chunk) {
  return new Promise((reslove, reject) => {
    const spark = new SparkMD5.ArrayBuffer();
    spark.append(chunk);
    reslove(spark.end());
  });
}

// 模拟上传
function apiUploadFile(formData) {
  return new Promise((reslove, reject) => {
    axios
      .post("http://127.0.0.1:8888/api/upload", formData, {
        headers: {
          "Content-Type": "multipart/form-data",
        },
      })
      .then((result) => {
        reslove(true);
      })
      .catch((err) => {});
  });
}
// 模拟合并文件
function mergeFile(formData) {
  return new Promise((reslove, reject) => {
    axios
      .post("http://127.0.0.1:8888/api/merge", formData, {
        headers: {
          "Content-Type": "application/json",
        },
      })
      .then((result) => {
        reslove(true);
      })
      .catch((err) => {});
  });
}
</script>

spark-md5.min.js

(function(factory){if(typeof exports==="object"){module.exports=factory()}else if(typeof define==="function"&&define.amd){define(factory)}else{var glob;try{glob=window}catch(e){glob=self}glob.SparkMD5=factory()}})(function(undefined){"use strict";var add32=function(a,b){return a+b&4294967295},hex_chr=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];function cmn(q,a,b,x,s,t){a=add32(add32(a,q),add32(x,t));return add32(a<<s|a>>>32-s,b)}function md5cycle(x,k){var a=x[0],b=x[1],c=x[2],d=x[3];a+=(b&c|~b&d)+k[0]-680876936|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[1]-389564586|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[2]+606105819|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[3]-1044525330|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[4]-176418897|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[5]+1200080426|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[6]-1473231341|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[7]-45705983|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[8]+1770035416|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[9]-1958414417|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[10]-42063|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[11]-1990404162|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[12]+1804603682|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[13]-40341101|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[14]-1502002290|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[15]+1236535329|0;b=(b<<22|b>>>10)+c|0;a+=(b&d|c&~d)+k[1]-165796510|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[6]-1069501632|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[11]+643717713|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[0]-373897302|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[5]-701558691|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[10]+38016083|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[15]-660478335|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[4]-405537848|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[9]+568446438|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[14]-1019803690|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[3]-187363961|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[8]+1163531501|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[13]-1444681467|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[2]-51403784|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[7]+1735328473|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[12]-1926607734|0;b=(b<<20|b>>>12)+c|0;a+=(b^c^d)+k[5]-378558|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[8]-2022574463|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[11]+1839030562|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[14]-35309556|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[1]-1530992060|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[4]+1272893353|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[7]-155497632|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[10]-1094730640|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[13]+681279174|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[0]-358537222|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[3]-722521979|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[6]+76029189|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[9]-640364487|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[12]-421815835|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[15]+530742520|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[2]-995338651|0;b=(b<<23|b>>>9)+c|0;a+=(c^(b|~d))+k[0]-198630844|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[7]+1126891415|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[14]-1416354905|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[5]-57434055|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[12]+1700485571|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[3]-1894986606|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[10]-1051523|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[1]-2054922799|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[8]+1873313359|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[15]-30611744|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[6]-1560198380|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[13]+1309151649|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[4]-145523070|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[11]-1120210379|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[2]+718787259|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[9]-343485551|0;b=(b<<21|b>>>11)+c|0;x[0]=a+x[0]|0;x[1]=b+x[1]|0;x[2]=c+x[2]|0;x[3]=d+x[3]|0}function md5blk(s){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=s.charCodeAt(i)+(s.charCodeAt(i+1)<<8)+(s.charCodeAt(i+2)<<16)+(s.charCodeAt(i+3)<<24)}return md5blks}function md5blk_array(a){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=a[i]+(a[i+1]<<8)+(a[i+2]<<16)+(a[i+3]<<24)}return md5blks}function md51(s){var n=s.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk(s.substring(i-64,i)))}s=s.substring(i-64);length=s.length;tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(i=0;i<length;i+=1){tail[i>>2]|=s.charCodeAt(i)<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state}function md51_array(a){var n=a.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk_array(a.subarray(i-64,i)))}a=i-64<n?a.subarray(i-64):new Uint8Array(0);length=a.length;tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(i=0;i<length;i+=1){tail[i>>2]|=a[i]<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state}function rhex(n){var s="",j;for(j=0;j<4;j+=1){s+=hex_chr[n>>j*8+4&15]+hex_chr[n>>j*8&15]}return s}function hex(x){var i;for(i=0;i<x.length;i+=1){x[i]=rhex(x[i])}return x.join("")}if(hex(md51("hello"))!=="5d41402abc4b2a76b9719d911017c592"){add32=function(x,y){var lsw=(x&65535)+(y&65535),msw=(x>>16)+(y>>16)+(lsw>>16);return msw<<16|lsw&65535}}if(typeof ArrayBuffer!=="undefined"&&!ArrayBuffer.prototype.slice){(function(){function clamp(val,length){val=val|0||0;if(val<0){return Math.max(val+length,0)}return Math.min(val,length)}ArrayBuffer.prototype.slice=function(from,to){var length=this.byteLength,begin=clamp(from,length),end=length,num,target,targetArray,sourceArray;if(to!==undefined){end=clamp(to,length)}if(begin>end){return new ArrayBuffer(0)}num=end-begin;target=new ArrayBuffer(num);targetArray=new Uint8Array(target);sourceArray=new Uint8Array(this,begin,num);targetArray.set(sourceArray);return target}})()}function toUtf8(str){if(/[\u0080-\uFFFF]/.test(str)){str=unescape(encodeURIComponent(str))}return str}function utf8Str2ArrayBuffer(str,returnUInt8Array){var length=str.length,buff=new ArrayBuffer(length),arr=new Uint8Array(buff),i;for(i=0;i<length;i+=1){arr[i]=str.charCodeAt(i)}return returnUInt8Array?arr:buff}function arrayBuffer2Utf8Str(buff){return String.fromCharCode.apply(null,new Uint8Array(buff))}function concatenateArrayBuffers(first,second,returnUInt8Array){var result=new Uint8Array(first.byteLength+second.byteLength);result.set(new Uint8Array(first));result.set(new Uint8Array(second),first.byteLength);return returnUInt8Array?result:result.buffer}function hexToBinaryString(hex){var bytes=[],length=hex.length,x;for(x=0;x<length-1;x+=2){bytes.push(parseInt(hex.substr(x,2),16))}return String.fromCharCode.apply(String,bytes)}function SparkMD5(){this.reset()}SparkMD5.prototype.append=function(str){this.appendBinary(toUtf8(str));return this};SparkMD5.prototype.appendBinary=function(contents){this._buff+=contents;this._length+=contents.length;var length=this._buff.length,i;for(i=64;i<=length;i+=64){md5cycle(this._hash,md5blk(this._buff.substring(i-64,i)))}this._buff=this._buff.substring(i-64);return this};SparkMD5.prototype.end=function(raw){var buff=this._buff,length=buff.length,i,tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],ret;for(i=0;i<length;i+=1){tail[i>>2]|=buff.charCodeAt(i)<<(i%4<<3)}this._finish(tail,length);ret=hex(this._hash);if(raw){ret=hexToBinaryString(ret)}this.reset();return ret};SparkMD5.prototype.reset=function(){this._buff="";this._length=0;this._hash=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.prototype.getState=function(){return{buff:this._buff,length:this._length,hash:this._hash.slice()}};SparkMD5.prototype.setState=function(state){this._buff=state.buff;this._length=state.length;this._hash=state.hash;return this};SparkMD5.prototype.destroy=function(){delete this._hash;delete this._buff;delete this._length};SparkMD5.prototype._finish=function(tail,length){var i=length,tmp,lo,hi;tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(this._hash,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=this._length*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(this._hash,tail)};SparkMD5.hash=function(str,raw){return SparkMD5.hashBinary(toUtf8(str),raw)};SparkMD5.hashBinary=function(content,raw){var hash=md51(content),ret=hex(hash);return raw?hexToBinaryString(ret):ret};SparkMD5.ArrayBuffer=function(){this.reset()};SparkMD5.ArrayBuffer.prototype.append=function(arr){var buff=concatenateArrayBuffers(this._buff.buffer,arr,true),length=buff.length,i;this._length+=arr.byteLength;for(i=64;i<=length;i+=64){md5cycle(this._hash,md5blk_array(buff.subarray(i-64,i)))}this._buff=i-64<length?new Uint8Array(buff.buffer.slice(i-64)):new Uint8Array(0);return this};SparkMD5.ArrayBuffer.prototype.end=function(raw){var buff=this._buff,length=buff.length,tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],i,ret;for(i=0;i<length;i+=1){tail[i>>2]|=buff[i]<<(i%4<<3)}this._finish(tail,length);ret=hex(this._hash);if(raw){ret=hexToBinaryString(ret)}this.reset();return ret};SparkMD5.ArrayBuffer.prototype.reset=function(){this._buff=new Uint8Array(0);this._length=0;this._hash=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.ArrayBuffer.prototype.getState=function(){var state=SparkMD5.prototype.getState.call(this);state.buff=arrayBuffer2Utf8Str(state.buff);return state};SparkMD5.ArrayBuffer.prototype.setState=function(state){state.buff=utf8Str2ArrayBuffer(state.buff,true);return SparkMD5.prototype.setState.call(this,state)};SparkMD5.ArrayBuffer.prototype.destroy=SparkMD5.prototype.destroy;SparkMD5.ArrayBuffer.prototype._finish=SparkMD5.prototype._finish;SparkMD5.ArrayBuffer.hash=function(arr,raw){var hash=md51_array(new Uint8Array(arr)),ret=hex(hash);return raw?hexToBinaryString(ret):ret};return SparkMD5});

后端代码

package main

import (
	"io"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
)

type MergeInfo struct {
	Key        string   `json:"key"`
	FileName   string   `json:"fileName"`
	ChunkFiles []string `json:"chunkFiles"`
}

func main() {
	r := gin.Default()
	//跨域
	r.Use(Cors())
	r.POST("/api/upload", handleFileUpload)
	r.POST("/api/merge", handleMergeFile)
	r.Run(":8888")
}
func PathExists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}
func handleFileUpload(c *gin.Context) {
	file, _, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "无法读取上传文件",
		})
		return
	}
	defer file.Close()

	// 获取上传文件的唯一标识
	key := c.PostForm("key")
	// 获取切片哈希值
	hash := c.PostForm("hash")
	//获取文件大小
	file_sizeStr := c.PostForm("file_size")
	file_size, err := strconv.ParseInt(file_sizeStr, 10, 64)
	// 保存上传的切片到临时目录
	uploadPath := "./temp/" + key
	if err := os.MkdirAll(uploadPath, 0755); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "无法创建上传目录",
		})
		return
	}

	chunkFileName := filepath.Join(uploadPath, hash)
	var out *os.File
	if !PathExists(chunkFileName) {
		out, err = os.Create(chunkFileName)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": "无法创建切片文件",
			})
			return
		}

	} else {
		// 获取文件大小(以字节为单位)
		fileInfo, _ := os.Stat(chunkFileName)
		fileSize := fileInfo.Size()
		if fileSize == file_size {
			c.JSON(http.StatusOK, gin.H{
				"message": "缓存",
			})
			return
		}
		out, err = os.Open(chunkFileName)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": "无法打开切片文件",
			})
			return
		}

	}
	defer out.Close()
	// 获取文件信息

	// 将切片流复制到切片文件
	_, err = io.Copy(out, file)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "无法写入切片文件",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message": "切片上传成功",
	})

}

func handleMergeFile(c *gin.Context) {
	var mergeInfo MergeInfo
	if err := c.BindJSON(&mergeInfo); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "参数有误",
		})
		return
	}
	// 获取临时目录下的所有切片文件
	uploadPath := "./temp/" + mergeInfo.Key

	// 创建目标文件并合并切片
	mergeFileName := filepath.Join("./uploads/", mergeInfo.FileName)
	mergeFile, err := os.Create(mergeFileName)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "无法创建合并文件",
		})
		return
	}
	defer mergeFile.Close()
	for _, chunkFile := range mergeInfo.ChunkFiles {
		chunk, err := os.Open(path.Join(uploadPath, chunkFile))
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": "无法打开切片文件",
			})
			return
		}

		_, err = io.Copy(mergeFile, chunk)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": "无法合并切片文件",
			})
			return
		}
		chunk.Close()
	}
	err = os.RemoveAll(uploadPath)

	c.JSON(http.StatusOK, gin.H{
		"message": "文件合并成功",
		"file":    mergeFileName,
	})
}

//跨域
func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method               // 请求方法
		origin := c.Request.Header.Get("Origin") // 请求头部

		var headerKeys []string // 声明请求头keys
		for k := range c.Request.Header {
			headerKeys = append(headerKeys, k)
		}
		headerStr := strings.Join(headerKeys, ", ")
		if headerStr == "" {
			headerStr = "access-control-allow-origin, access-control-allow-headers"
		}
		if origin != "" {
			c.Header("Access-Control-Allow-Origin", origin)                                    // 这是允许访问所有域
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE") // 服务器支持的所有跨域请求的方法,为了避免浏览次请求的多次'预检'请求
			//  header的类型
			c.Header("Access-Control-Allow-Headers", "*")
			//              允许跨域设置                                                                                                      可以返回其他子段
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") // 跨域关键设置 让浏览器可以解析
			c.Header("Access-Control-Max-Age", "172800")                                                                                                                                                           // 缓存请求信息 单位为秒
			c.Header("Access-Control-Allow-Credentials", "true")                                                                                                                                                   //  跨域请求是否需要带cookie信息 默认设置为true
			c.Set("content-type", "application/json")                                                                                                                                                              // 设置返回格式是json
		}

		// 放行所有OPTIONS方法
		if method == "OPTIONS" {
			c.JSON(http.StatusOK, "Options Request!")
		}
		// 处理请求
		c.Next() //  处理请求
	}
}

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/762599.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三步数据转报表,奥威BI-金蝶云星空SaaS版给你极速数据分析体验

根据经验&#xff0c;要部署一套大数据分析软件&#xff0c;至少也要准备环境、下载安装配置软件、配置数据源&#xff0c;有些完全从零开始入手的还面临着分析模型的搭建等难题。这些操作不说难度如此&#xff0c;光是耗时就不短&#xff0c;会给企业带来不小的成本压力。而奥…

读书笔记怎么写?《如何阅读一本书》读书笔记!

读书笔记有助于提高读书的效率&#xff0c;引发更多的思考。在阅读的过程中&#xff0c;读书笔记该怎么写&#xff1f;本文借助 boardmix在线白板&#xff0c;以《如何阅读一本书》为例&#xff0c;全面剖析如何做好读书笔记。 1.作者信息 《如何阅读一本书》是由莫提默J. …

【Maven】Maven下载,配置以及基本概念

文章目录 1. Maven简介2. Maven下载3. Maven环境配置4.Maven的基本概念4.1 仓库4.2 坐标4.3 仓库配置(修改IDEA默认Maven库) 1. Maven简介 Maven是一个Java项目管理工具和构建工具&#xff0c;用于管理项目的依赖关系、构建过程以及项目的部署。它是Apache软件基金会的开源项目…

ShardingSphere核心概念

&#x1f680; ShardingSphere &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&…

INDEMIND:视觉SLAM,助力服务机器人再进化

毋庸置疑&#xff0c;VSLAM将是推动机器人再次迭代的关键之一。 移动的“机器”还是机器人&#xff1f; 随着机器人的落地量持续增长&#xff0c;早期“忽略”的产品缺陷&#xff0c;正在引发越来越严重的负面影响。一方面&#xff0c;激光SLAM虽基于Cartographer算法不断演进…

吐血整理,接口测试到接口自动化集成总结,你不知道的都在这...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 后端接口都测试什…

mybatis-plus 支持不同数据源sql切换

mybatis-plus 支持不同数据源sql切换 本篇内容主要讲解的是mybatis-plus 支持不同数据源sql切换 直接上代码 1、结构代码 2、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactI…

mockserver实践:本地启动以命令行方式运行,实现挡板和转发

mockserver 官网学习地址 https://www.mock-server.com/#what-is-mockserver mockserver下载和启动 下载 官网下载jar包 https://www.mock-server.com/where/downloads.html 本次实践所用jar包 mockserver-netty-5.14.0-shaded.jar 本地启动 需要先准备好jave环境 1.普通…

5、WAMP配置虚拟主机

配置虚拟主机后可实现用域名的方式访问项目。 1、从WAMP图标&#xff0c;点击左键&#xff0c;进行虚拟主机管理&#xff0c;然后添加上虚拟主机名&#xff0c;即将来的浏览器的地址名&#xff0c;然后输入相应的文件夹。这种修改方式&#xff0c;直接自动修改了hosts文件。 2…

frp内网穿透工具实现局域网服务访问

frp工具实现内网穿透 frp主要作用是实现内网穿透&#xff0c;将内外网端口进行映射&#xff0c;这样如果我想访问局域网内的某项服务&#xff0c;那么我直接访问公网上相对应的映射端口即可。 frp安装配置较复杂&#xff0c;这里我们直接使用frp docker容器安装。所以如果主机…

第二十章:CANet:具有迭代细化和专注少样本学习的无类别分割网络

0.摘要 最近在语义分割方面的进展是由深度卷积神经网络和大规模标注图像数据集推动的。然而&#xff0c;像素级别的数据标注是繁琐和昂贵的。此外&#xff0c;训练好的模型只能在一组预定义的类别中进行预测。在本文中&#xff0c;我们提出了CANet&#xff0c;一种无类别偏见的…

Spark编程-使用SparkCore求TopN,Max_Min_Value

简介 使用SparkCore求top5值编程&#xff0c;最大最小值 求订单前五的TOP5值 数据 数据字段如下&#xff1a;orderid,userid,payment,productid 需求如下&#xff1a;从文本文件中读取数据&#xff0c;并计算出前5个payment(订单的付款金额)值 //字段 orderid,userid,payme…

Java读取INI文件详解及案例

引言&#xff1a; INI文件是一种常用的配置文件格式&#xff0c;它采用了键值对的形式存储配置信息。在Java编程中&#xff0c;读取和解析INI文件是一个常见的任务。本文将详细介绍如何使用Java读取INI文件&#xff0c;并提供一个案例演示。 ---------------文章目录---------…

给2023年还想要成为网络工程师的朋友的一份学习福利

2023的夏天再怎么热&#xff0c;网络工程师工作的机房也会让你瑟瑟发抖。 很久没有给粉丝们分享网络工程师学习资料了&#xff0c;如果你当下还在为成为网络工程师而学习&#xff0c;不妨顺手拿走这份网工资料包再出发&#xff0c;希望可以给大家的学习一些帮助。 网工光速入门…

快速数据处理:限定表格某些字段是否可见、只读

目录 1 前言 2 打开字段属性表进行修改 3 测试一下几个字段只读属性 1 前言 实际操作中&#xff0c;某些字段不需要显示出来&#xff0c;某些字段需要显示&#xff0c;但是不可修改。我们可以通过简单设置来实现这些。 2 打开字段属性表进行修改 从左下基础表格列表中&am…

Day55|392.判断子序列 、 115.不同的子序列

392.判断子序列 1.题目&#xff1a; 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;例如&#xff0c;"ace"是…

第五章内存系统(Cortex-M7 Processor)

目录 第五章内存系统 5.1关于内存系统 5.2&#xff08;Speculative&#xff09;推测性访问 5.2.1系统设计注意事项 5.3故障处理 5.3.1故障 5.3.2使用模型 5.4内存类型和内存系统行为 5.5AXIM接口 5.5.1AXI属性和事务 5.5.2用于AXIM接口访问的标识符 5.5.3AXI特权信息 5.…

Python案例分析|文本相似度比较分析

本案例通过设计和实现有关文本相似度比较的类Vector和Sketch&#xff0c;帮助大家进一步掌握设计Python类来解决实际问题的能力。 01、文本相似度比较概述 通过计算并比较文档的摘要可实现文本的相似度比较。 文档摘要的最简单形式可以使用文档中的k-grams&#xff08;k个连…

springboot第30集:springboot集合问题

Logstash Logstash 是开源的服务器端数据处理管道&#xff0c;能够同时从多个来源采集数据、格式化数据&#xff0c;然后将数据发送到es进行存储。 ElasticSearch Elasticsearch 是基于JSON的分布式搜索和分析引擎&#xff0c;是利用倒排索引实现的全文索引。 KibanaKibana 能够…

低代码项目实战第一弹!2人14天快速构建电商企业供应链管理平台(一)

一、前言&#xff1a;项目背景 项目情况&#xff1a;一家主要通过电商平台销售日用清洁用品的企业&#xff0c;淘宝垂直品类第一&#xff0c;销售模式包括自营和代理商两种模式&#xff0c;平时用旺店通ERP进行订单管理和财务结算。并且客户公司有小的开发团队&#xff0c;可以…