Skip to content
导航栏

小心字节处理

字节处理

在 yao 中使用 js 处理字节数组时需要小心.

这个脚本不正常,如果在 js 脚本中读取了字节数组,并把字节数组作为 json 对象的属性返回时,将得不到你想要的结果,比如这里读取的图片内容,在 API 中输出时会显示一系列的数组,而不是字节码。

js
function Download() {
  let fs = new FS('system');

  const buf = fs.ReadFileBuffer('/upload/1/20231115/微信图片.png');
  //
  return {
    content: buf,
    type: 'image/png',
  };
}

这个脚本正常,可以直接返回字节数组,没有包含在对象中。

js
function Download() {
  let fs = new FS('system');

  const buf = fs.ReadFileBuffer(
    '/upload/1/20231115/微信图片_20220601141654.png',
  );
  return buf;
}

问题在原因在于,在 yao 中把 js 对象转换成 go 对象时,使用的是 js 的 json.marshal 与 go 的 jsoniter.Unmarshal。这个转换过程中,js 的字节 uint32 数组会转换成 float64 的数组。最后导致数据结构发生变化。

/gou/runtime/v8/bridge/bridge.go

go
func goValueParse(value *v8go.Value, v interface{}) (interface{}, error) {

	data, err := value.MarshalJSON()
	if err != nil {
		return nil, err
	}

	ptr := &v
    // 字节数组类型发生变化。
	err = jsoniter.Unmarshal(data, ptr)
	if err != nil {
		fmt.Printf("---\n%s\n---\n", data)
		return nil, err
	}

	return *ptr, nil
}

替代方案

使用 flow,来操作文件的下载读取。

json
{
  "label": "下载文件",
  "version": "1.0.0",
  "description": "下载文件",
  "nodes": [
    {
      "name": "filename",
      "process": "scripts.system.file.getFileName",
      "args": ["{{$in.0}}"]
    },
    {
      "name": "下载文件",
      "process": "fs.system.Download",
      "args": ["{{$res.filename}}"]
    }
  ],
  "output": "{{$res.下载文件}}"
}

总结

避免在 js 脚本中与 golang 之间进行大量的字节转换操作,比如读取转换文件。针对于类似的场景处理方案最好是使用 golang 的程序进行处理,避免使用脚本进行转换。同时 bytes 在转换过程也会消耗大量的内存,转换过程中也是按字节进行赋值处理。