为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

梵蒂冈之花 2022-09-23 21:56:44

我向拒绝内容长度超过特定限制的请求的服务器发布(包括文件)。我想在执行注定要被拒绝的请求之前验证我的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.sycdn.imooc.com/632dbb380001cce305810510.jpg

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

http://img2.sycdn.imooc.com/632dbb43000131d906540198.jpg

查看完整描述

3 回答

?
饮歌长啸

TA贡献0条经验 获得超2个赞

下面是一个异步版本,它首先将表单数据转换为 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和野生动物园中不起作用

all doe,将表单数据替换为多填充版本(如 https://github.com/jimmywarting/FormData)可能有助于您将表单数据直接(同步)转换为 blob,而无需使用提取 API(使用 )。也就是说,如果您需要更广泛的浏览器支持formData._blob()


查看完整回答
反对 回复 5天前
?
泛舟湖上清波郎朗

TA贡献1481条经验 获得超3个赞

我仍然不知道是否有可能计算出确切的大小,但您至少可以尝试估计它:


/**

 * 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;

}


查看完整回答
反对 回复 5天前
?
阿波罗的战车

TA贡献1521条经验 获得超6个赞

一种方法可能是 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

}


查看完整回答
反对 回复 5天前
  • 3 回答
  • 0 关注
  • 11 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信