tampermonkey 上传 Blob 文件到其他服务器,multipart/form-data 版

文章目录

    application/octet-stream 版本的缺陷:

    • 无法增加多余参数。例如,我想顺便传递用户名,就没法增加字段了
    • 搜了半天没找到 Spring Boot 读取 application/octet-stream 的实现。。。

    所以干脆想尝试 multipart/form-data 版。

    Java Spring Boot 如何获取 application/octet-stream 二进制数据

    {
        "timestamp": "Feb 1, 2021, 03:18:55 PM",
        "status": 415,
        "error": "Unsupported Media Type",
        "message": "Content type 'application/octet-stream' not supported",
        "trace": "org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported...,
        "path": "xxx"
    }
    

    https://stackoverflow.com/questions/50395010/spring-postman-content-type-application-octet-stream-not-supported

    改成 form data 并传参 file, 这样可以额外增加用户标识的参数。

    content type: application/octet-stream 与 multipart/form-data 的区别

    https://stackoverflow.com/questions/29347234/multipart-form-data-vs-application-octet-stream

    multipart/form-data 可以传递多个参数,看起来扩展性更好一些。

    跟这个的区别呢?

    “Content-Type”: “application/x-www-form-urlencoded”

    https://stackoverflow.com/questions/4007969/application-x-www-form-urlencoded-or-multipart-form-data

    Summary; if you have binary (non-alphanumeric) data (or a significantly sized payload) to transmit,
    use multipart/form-data. Otherwise, use application/x-www-form-urlencoded

    form data 版的 js 实现

    GM_xmlhttpRequest ( {
      method:     "POST",
      url:        "https://www.sunzhongwei.com/some-excel",
      data:       data,
      responseType: "blob",
      headers:    {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      onload:     function (response) {
        console.log ("got response");
        var formData = new FormData();
        formData.append("username", "sunzhongwei.com");
        formData.append("myfile", response.response, "a.xls");
        GM_xmlhttpRequest ( {
          method:     "POST",
          url:        "http://localhost:5000",
          data:       formData,
          /*
          binary: 		true,
          headers:    {
            "Content-Type": "multipart/form-data"
          },
          */
          onload:     function (response) {
            console.log (response.responseText);
          }
        });
      }
    });
    

    注意,一定要注释掉自己设置的 headers,否则 python 后台会读取不到 form 数据。非常诡异。

    我猜测,tampermonkey 识别 data 类型为 FormData 时,会自动设置 content type。但为啥不能自己设置就非常迷了。

    python flask 的 form data 文件读取

    # env FLASK_APP=server.py FLASK_DEBUG=1 flask run
    
    from flask import Flask, escape, request
    
    app = Flask(__name__)
    
    
    @app.route('/', methods=['GET', 'POST'])
    def hello():
        #data = request.get_data()
        print("11111111111")
        print(request.form)
        print("22222222222")
        print(request.files)
        data = request.files["myfile"]
        data.save("/mnt/d/test_a_2.xls")
    
        return "OK"
    

    一些调试输出:

    11111111111
    ImmutableMultiDict([('username', 'sunzhongwei.com')])
    22222222222
    ImmutableMultiDict([('myfile', <FileStorage: 'a.xls' ('binary/octet-stream')>)])
    

    可以看到,虽然 content type 为 multipart/form-data,但是具体字段可以是 binary/octet-stream。

    java Spring Boot 获取 form data 中的文件

    @ResponseBody
    @PostMapping(path = "/test_upload_blob")
    public String uploadBlob(@RequestParam("myfile") MultipartFile file) throws IOException {
        file.transferTo(new File("D:/aaaaa.xls"));
        return "OK, from Spring Boot";
    }
    

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式