Ramda 处理请求响应

76 阅读1分钟

目标

调接口传 FormData,返回的 Blob 转 url 用 <a> 下载。

FormData

  • Object -> [Key, Value][] -> FormData
  • R.reduce() 擅长数组百变
    • reducer() 使累加值,即 FormData 实例添加键值对,再返回累加值
    • initialValue 为新创建的 FormData 实例
  • 为确保每次调用 toFormData() 都会创建新的 FormData 实例,这次就用了 R.constructN(0, FormData)

reducer() 最初这么写

(formData, pair) => (formData.append(...pair), formData);

后来经过一番演变

  • R.tap() 避免再写一次返回 formData
  • R.apply() 避免写 ...
  • R.bind() 改变 this 指向
/** (FormData, [Key, Value]) -> FormData */
const Append = (formData, pair) => R.tap(
  R.compose( R.apply(R.__, pair), R.bind(FormData.prototype.append) ),
  formData
);

/** Object -> FormData */
const toFormData = R.compose(
  R.converge( R.reduce(Append), [R.constructN(0, FormData), Object.entries] ),
  R.map(R.when( R.isNil, R.always('') ))
);

FormData 再变回 Object 也一样

console.log(
  Object.fromEntries( toFormData({ name: 'Tom' }) )
);
// { name: "Tom" }

文件名

调接口后,开发工具看 Response Headers,文件名在 Content-Disposition,用于 <a> download 赋值

fieldvalue
Access-Control-Allow-Origin*
Connectionclose
Content-Dispositionattachment; filename="20240506135858.zip"
Content-Length1992
Content-Typeapplication/zip
DateMon, 06 May 2024 05:58:58 GMT

方案一 R.slice()

/** string -> string -> number */
const StartAt = search => R.compose( R.add(search.length), R.indexOf(search) );

/** Headers -> string */
const Filename = R.compose(
  R.converge( R.slice(R.__, -1, R.__), [StartAt('filename="'), R.identity] ),
  R.prop('content-disposition'),
  Object.fromEntries
);

方案二 R.match()

/** Headers -> string */
const Filename = R.compose(
  R.head,
  R.match(/\d+\.zip/), // ["20240506135858.zip", "groups": undefined, "index": 22, "input": "attachment; filename=\"20240506135858.zip\""]
  R.prop('content-disposition'),
  Object.fromEntries
);

完整代码

fetch('/api/example', {
  headers: {
    accesstoken: /* accesstoken */,
  },
  method: 'POST',
  body: toFormData(/* Object */),
})
.then(R.invoker(0, 'blob'))
.then(blob => {
  const url = URL.createObjectURL(blob);
  const aElem = document.createElement('a');
  aElem.href = url;
  aElem.download = Filename(response.headers);
  aElem.click();
  URL.revokeObjectURL(url);
});