FormData textarea 在发送 POST 时放置 \r(回车 return)

FormData textarea puts \r (carriage return) when sent with POST

为什么 FormData 在换行符前插入回车符 returns?

当我用 FormData 发送 post 请求时,它使用 CRLF 行结尾,即使 textarea 的值根本没有回车 returns。这使我的字符长度验证意外失败。

下面的示例代码显示了文本区域字符串值、FormData 中的数据和将要提交的编码数据之间的区别。 JSON.stringify()用于转义控制字符。

document.getElementById('HistoryValue').textContent = JSON.stringify(document.forms.CRLFSample.history.value);
const fd = new FormData(document.forms.CRLFSample);
document.getElementById('FormData').textContent = JSON.stringify(fd.get('history'));
new Response(fd).text().then(text =>
document.getElementById('POSTData').textContent = JSON.stringify(text));
#CRLFSample {
  width: 90%;
}
<form id="CRLFSample" method="POST">
  <textarea name="history">
    line 1
    line 2
  </textarea>
</form>
<dl>
<dt>Textarea</dt><dd id="HistoryValue"></dd>
<dt>FormData</dt><dd id="FormData"></dd>
<dt>POST data</dt><dd id="POSTData"></dd>
</dl>

以上已在 macOS 10.14 & 12 和 Android 10 上的 Firefox 92-94 和 Chrome 95 中进行了测试。注意“Textarea”显示“ \n” 用于换行,但是“POSTData” 有“\r\n”。 “FormData”显示不同的结果主要取决于浏览器,大多数版本的 FireFox 仅显示“\n”,大多数版本的 Chrome 显示“\r\n”。

以下由原提问者编辑

没想到我有这么多评论。感谢您的关注,请允许我为没有遵守网站指南而道歉。我将尝试详细说明以最好地帮助您重现错误并了解发生了什么。

我在 mac Catalina 10.15.7 上测试了这个,我的浏览器是 chrome 版本 95.0.4638.69(官方构建)(x86_64)。

下面是我尝试使用 formdata 验证字符长度并分别获取 textarea 的值。

let formData = new FormData(document.getElementById('form'));
let historyEl = document.getElementById('id_history');
console.log(formData.get('history').length, formData.get('history').includes('\r\n'));
console.log(historyEl.value.length, historyEl.value.includes('r\n'));
<form id="form" method="POST">
<textarea class="materialize-textarea" cols="40" name="history" id="id_history" rows="10">    Lorem Ipsum is simply dummy text of the printing and typesetting 
industry. 
Lorem Ipsum has been the industry's standard dummy text ever since 
the 1500s, 
when an unknown printer took a galley of type and scrambled it to 
make a type 
specimen book. It has survived not only five centuries, but also 
the leap into electronic 
typesetting, remaining essentially unchanged. It was popularised in 
the 190
.</textarea>
</form>

正如您在 运行 代码片段中看到的,history 的表单数据长度显示的长度与文本区域元素值的长度不同。

本来我是从Window用户那里收到textarea的值,我以为只是OS的问题。但是当我检查它时,甚至在我的 OS 中也会发生这种情况,尤其是在提交表单数据时。

有人可能会问我是否可以检查 textarea 值的长度,但我尽量避免这种情况,因为检查 formdata 是前端验证的重点。

我的母语不是英语,我的字符长度验证是针对其他非拉丁语言的,但有些东西阻止我在代码片段中 posting 非拉丁语言。但是由于 console 分别产生不同的长度,我相信无论如何你都会对其他字符有所了解。

您的文本区域内有换行符。我可以想到两种方法来避免这个问题。我相信还有其他几种可能性。

在这种情况下,您可以使用 js 替换功能收集数据和 remove/replace \n \r 。像这样:

const text = fd.get('history')
console.log('out1:',text)
console.log('out2:', text.replace(/(\r\n|\n|\r)/gm, ""));

或者您向文本区域添加一个事件侦听器,它可以识别 return 已输入并立即将其删除。

document.querySelector('textarea[name=history]').onkeydown = function( e ) {
  if (e.keyCode == 13 && !e.shiftKey)
  {      
      e.preventDefault();
      console.log('your code to remove immediately the line break/return')
  }    
}

根据 MDN,FormData uses the "multipart/form-data" format, specified by RFC 2388, section 3 其中指出:

The media-type multipart/form-data follows the rules of all multipart MIME data streams as outlined in RFC 2046.

RFC § 4.1.1,关于行结尾的部分,指出:

The canonical form of any MIME "text" subtype MUST always represent a line break as a CRLF sequence.

这就是为什么在发布时行结尾被编码为 CRLF 的原因。从这里不清楚的是行尾是否应该在 FormData 的条目中编码为 CRLF(例如 formData.get('history') 的结果所示)。

提到了spec for FormData makes no mention of encoding line endings when adding an entry or value. The only processing of a value when being added is for Blob (i.e. binary) and File objects. No processing of the value by FormData.get()。对此的严格解读是 Chrome 的行为(编码值存储在 FormData 中)是非标准的。但是,直接存储值意味着将使用浏览器的内部(可能是平台的)行结束编码,这可能会有所不同。

Fetch standard designates Response as being responsible for handling the multipart/form-data encoding; specifically, extracting FormData is supposed to use the "multipart/form-data" encoding algorithm.