前言
某次在客户内网传输数据的时候,防火墙拦截了SSH的数据包,导致没法使用scp
命令传输文件,tcp协议和http协议也只放开了指定端口,因此想了个用http传输的“曲线救国”方案。
假设要从192.168.1.23传输到192.168.2.34,因防火墙限制,只能从1.23访问2.34,不能从2.34访问1.23,且1.23只能访问2.34的12345端口,也不能使用基于ssh的文件传输。
在2.34创建一个api,监听12345端口,处理http的post请求和get请求,实现文件上传和文件下载功能。
基于gin框架,编译成二进制文件,丢到服务器就能运行,无需处理依赖问题。
示例代码
package main import ( "fmt" "log" "net/http" "flag" "strconv" "github.com/gin-gonic/gin" ) func main() { upload := flag.String("u","./","-u 指定文件上传目录") download := flag.String("d","./","-d 指定文件下载目录") port := flag.Int("p",12345,"-p 指定监听端口号") size := flag.Int64("s", 100, "-s 指定请求体文件大小, 单位: MB") flag.Parse() r := gin.Default() r.Static("/download", *download) // 为 multipart forms 设置文件大小限制, 默认是32MB // 此处为左移位运算符, << 20 表示1MiB,8 << 20就是8MiB r.MaxMultipartMemory = *size << 20 // 8 MiB r.POST("/upload", func(c *gin.Context) { // 单文件 file, _ := c.FormFile("file") log.Println(file.Filename) // 上传文件至指定的完整文件路径 dst := *upload + file.Filename c.SaveUploadedFile(file, dst) c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) }) listenAddr := "0.0.0.0:" + strconv.Itoa(*port) r.Run(listenAddr) }
示例使用
# 在192.168.2.34先运行,设置请求体限制大小为1G ./appname -s 1000 # 上传当前目录下的test.tar.gz curl -X POST 'http://192.168.2.34:12345/upload' -H "Content-Type: multipart/form-data" -F "file=@./test.tar.gz" # 在其它能访问到192.168.2.34的服务器下载 curl -O http://192.168.2.34:12345/download/test.tar.gz