tampermonkey 上传 Blob 文件到其他服务器,application/octet-stream 版

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

例如,我想将 https://www.sunzhongwei.com 网页中下载到的 Excel 文件,上传到其他服务器。这里以 http://localhost:5000 为本地测试环境。

tampermonkey 中是否可以使用 fetch / jQuery ajax

还是必须使用 GM_xmlhttpRequest ?

测试了一下,用 fetch 确实不行,必须使用 GM_xmlhttpRequest 。

以下是使用 fetch 的报错信息,估计使用 jquery ajax 也是同样的结果。

Access to fetch at 'http://localhost:5000/' from origin 'https://www.sunzhongwei.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

POST http://localhost:5000/ net::ERR_FAILED

Uncaught (in promise) TypeError: Failed to fetch

如果是同一个域名,就可以使用 fetch 了。

官方文档对 GM_xmlhttpRequest 的说明

https://wiki.greasespot.net/GM.xmlHttpRequest

This method performs a similar function to the standard XMLHttpRequest object, but allows these requests to cross the same origin policy boundaries.

也就是说使用这个函数才能绕过 cross the same origin policy 的限制。

URL is not a part of the @connect list

在向本地服务 http://localhost:5000 提交数据时,报错:

URL is not a part of the @connect list

看起来是没有添加域名白名单。注意,不需要加端口号,如果加了端口号,同样会报这个错误。

正确的设置如下:

// @connect localhost

指定 Excel 文件的下载格式

GM_xmlhttpRequest 的相关参数:

  • 请求参数 responseType: one of arraybuffer, blob, json
  • 返回值 response: the response data as object if details.responseType was set

arraybuffer 与 blob 的区别

Blob,是英文 Binary Large Object (二进制大型对象)的缩写。

Blob 对象表示一个二进制文件的数据内容,通常用来读写文件,比如一个图片文件的内容就可以通过 Blob 对象读写。 所以下载的 Excel 文件,就需要用 Blob 格式来存储。到上传的时候,再原封不动地传到新的服务器上。

与 ArrayBuffer 区别:

  • Blob 用于操作二进制文件
  • ArrayBuffer 用于操作内存。没太看懂,感觉是以数组的形式打印二进制流。

Blob 上传

GM_xmlhttpRequest 的 binary 参数,支持数据二进制模式。

binary send the data string in binary mode

参考:

https://www.tampermonkey.net/documentation.php#GM_getResourceText

这里的 binary 是用来设置参数 data 的类型,所以只能设置为 true / false。

可行的 js 代码

GM_xmlhttpRequest ( {
  method:     "POST",
  url:        "https://www.sunzhongwei.com/some-excel",
  data:       data,
  responseType: "blob",		// 获取 response 为 blob 类型
  headers:    {
    "Content-Type": "application/x-www-form-urlencoded"
  },
  onload:     function (response) {
	console.log ("got response");
	GM_xmlhttpRequest ( {
		method:     "POST",
		url:        "http://localhost:5000",
		data:       response.response,
		binary:     true,		// 设置 data 以二进制形式上传
		headers:    {},
		onload:     function (response) {
			console.log (response.responseText);
		}
	});
  }
});

Python 如何获取传递来的二进制数据

以 flask 为例:

# env FLASK_APP=server.py flask run

from flask import Flask, escape, request

app = Flask(__name__)


@app.route('/', methods=['GET', 'POST'])
def hello():
    data = request.get_data()

    with open("/mnt/d/test_a.xls", "wb") as f:
        f.write(data)

    return "OK"

打开文件,果然是原始的 Excel。测试成功。

Java 如何获取传递来的二进制数据

参考 tampermonkey 上传 Blob 文件到其他服务器,multipart/form-data 版 里的实现。

感悟

读官方文档,很多时候就能理出实现思路,比 Google 结果还靠谱。

参考

  • https://stackoverflow.com/questions/19393744/use-gm-xmlhttprequest-to-post-data-on-chrome

关于作者 🌱

我是来自山东烟台的一名开发者,有敢兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式