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

更新日期: 2021-01-30 阅读次数: 3463 字数: 431 分类: Tampermonkey

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 聊聊, 查看更多联系方式