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

如何在JavaScript中验证多部分表单数据的内容长度?,javascript,multipartform-data,form-data,content-length,http-content-length,Javascript,Multipartform Data,Form Data,Content Length,Http Content Length,我将FormData(包括文件)发布到拒绝内容长度超过特定限制的请求的服务器。在执行注定要被拒绝的请求之前,我想验证JavaScript客户端(浏览器)中的内容长度。如何获取(multipart/form data)编码的FormData对象的内容长度 const formData = new FormData(); formData.append('text', text); formData.append('file', file); if (getContentLength(formDat

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

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。仅使用字符串的
长度
和文件的
大小
不能计算正确的内容长度

函数getContentLength(formData){ const formDataEntries=[…formData.entries()] const contentLength=formDataEntries.reduce((acc,[key,value])=>{ if(typeof value==='string')返回acc+value.length if(typeof value==='object')返回acc+value.size 返回acc }, 0) 返回内容长度 } const formData=new formData(); append('text','foo'); 警报(`计算的内容长度为${getContentLength(formData)}`); 取('https://httpbin.org/post“,{method:'POST',body:formData})一种方法可以是这样,您可以迭代所有数据并获得最终的内容长度。 我们还需要数组上的
扩展运算符
,或者您可以使用
array.from()
.entries()
返回的迭代器转换为正确的数组

下面的代码示例,我并没有用文件测试它,但请告诉我您是否有任何与此有关的edge案例

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
}

我仍然不知道是否有可能计算出确切的尺寸,但你至少可以尝试估算一下:

/**
 * 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转换为Blob。您可以从中检索要发送到服务器的实际大小

因此,与其发布formdata,不如发送生成的blob

async函数测试(){
//创建一些虚拟数据
const fd=new FormData()
fd.set('a','b')
//获取一个实际的原始字节作为请求将发送的内容的blob
const res=新响应(fd)
const blob=wait res.blob()
blob.text&&(
console.log('实际主体的外观'),
console.log(等待blob.text())
)
//无法使用自己的blob类型,因为spec将blob.type小写
//所以我们得到了实际的内容类型
const type=res.headers.get('content-type')
//将要使用的实际内容长度大小
console.log('发送前的内容长度',blob.size)
//核实
const testRes=等待获取('https://httpbin.org/post', { 
方法:“POST”,
body:blob,//现在发送blob而不是formdata
头:{//使用实类型(而不是默认的小写blob类型)
“内容类型”:类型
}
})
const json=await testRes.json()
const headers=新的头(json.headers)
log('发布的表单:',JSON.stringify(JSON.form))
console.log('content-length that sent',headers.get('content-length'))
}

测试()这不考虑边界的大小。你解决了这个问题吗?在狩猎旅行中,我面临着一个相关的问题。我使用了我在回答中所描述的估计,我认为这有点过分,估计也足够好。