如何在脚本中验证多部分表单数据的内容长度?

我向拒绝内容长度超过特定限制的请求的服务器发布(包括文件)。我想在执行注定要被拒绝的请求之前验证我的JavaScript客户端(浏览器)中的内容长度。如何获取 () 编码对象的内容长度?FormDatamultipart/form-dataFormData


const formData = new FormData();

formData.append('text', text);

formData.append('file', file);

if (getContentLength(formData) > limit) {

    alert('Content length limit is exceeded');

} else {

    fetch(url, { method: 'POST', body: formData });

}

编辑:感谢您的回答,@Indgalante。仅使用字符串和文件并不能计算正确的内容长度。lengthsize


function getContentLength(formData) {

  const formDataEntries = [...formData.entries()]


  const contentLength = formDataEntries.reduce((acc, [key, value]) => {

    if (typeof value === 'string') return acc + value.length

    if (typeof value === 'object') return acc + value.size


    return acc

  }, 0)


  return contentLength

}


const formData = new FormData();

formData.append('text', 'foo');

alert(`calculated content-length is ${getContentLength(formData)}`);

fetch('https://httpbin.org/post', { method: 'POST', body: formData });


您不认为表单数据已在请求中编码。因此,添加了 i.a. 边界。示例中计算的内容长度为 3,但在我的 Chrome 浏览器中应为 138

http://img3.mukewang.com/632dbb380001cce305810510.jpg

和 172 在我的火狐浏览器.我不确定其他浏览器的行为方式。

http://img2.mukewang.com/632dbb43000131d906540198.jpg

梵蒂冈之花
浏览 92回答 3
3回答

饮歌长啸

下面是一个异步版本,它首先将表单数据转换为 Blob。从中可以检索要发送到服务器的实际大小。因此,您不会发布表单数据,而是发送生成的 blob。async function test() {  // Create some dummy data  const fd = new FormData()  fd.set('a', 'b')  // acquire an actual raw bytes as blob of what the request would send  const res = new Response(fd)  const blob = await res.blob()  blob.text && (    console.log('what the actual body looks like'),     console.log(await blob.text())  )  // can't use own blob's type since spec lowercase the blob.type  // so we get the actual content type  const type = res.headers.get('content-type')  // the acutal content-length size that's going to be used  console.log('content-length before sending', blob.size)  // verify  const testRes = await fetch('https://httpbin.org/post', {     method: 'POST',    body: blob, // now send the blob instead of formdata    headers: { // use the real type (and not the default lowercased blob type)      'content-type': type    }  })  const json = await testRes.json()  const headers = new Headers(json.headers)  console.log('form that got posted:', JSON.stringify(json.form))  console.log('content-length that was sent', headers.get('content-length'))}但是,这在IE和野生动物园中不起作用IE没有抓取(但无论如何它已经死了)野生动物园有这个错误。https://bugs.webkit.org/show_bug.cgi?id=161190https://bugs.webkit.org/show_bug.cgi?id=212858https://bugs.webkit.org/show_bug.cgi?id=171581all doe,将表单数据替换为多填充版本(如 https://github.com/jimmywarting/FormData)可能有助于您将表单数据直接(同步)转换为 blob,而无需使用提取 API(使用 )。也就是说,如果您需要更广泛的浏览器支持formData._blob()

泛舟湖上清波郎朗

我仍然不知道是否有可能计算出确切的大小,但您至少可以尝试估计它:/** * Estimate the content length of (multipart/form-data) encoded form data * object (sent in HTTP POST requests). * We do not know if you can get the actual content length. * Hence, it is estimated by this function. * As soon as {@link https://stackoverflow.com/q/62281752/1065654 this} * question is answered (correctly), the correct calculation should be used. * * @param formData */function estimateContentLength(formData: FormData) {    // Seems to be 44 in WebKit browsers (e.g. Chrome, Safari, etc.),    // but varies at least in Firefox.    const baseLength = 50; // estimated max value    // Seems to be 87 in WebKit browsers (e.g. Chrome, Safari, etc.),    // but varies at least in Firefox.    const separatorLength = 115; // estimated max value    let length = baseLength;    const entries = formData.entries();    for (const [key, value] of entries) {        length += key.length + separatorLength;        if (typeof value === 'object') {            length += value.size;        } else {            length += String(value).length;        }    }    return length;}

阿波罗的战车

一种方法可能是 FormData.entries(),因此您可以循环访问所有数据并获取最终的内容长度。我们还需要一个 over 数组,或者您可以使用 将 返回的迭代器转换为正确的数组。spread operatorArray.from().entries()下面的代码示例,我没有用文件测试它,但让我知道你是否有任何边缘情况与这个。function getContentLength(formData) {  const formDataEntries = [...formData.entries()]  const contentLength = formDataEntries.reduce((acc, [key, value]) => {    if (typeof value === 'string') return acc + value.length    if (typeof value === 'object') return acc + value.size    return acc  }, 0)  return contentLength}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript