我们在做Web开发的时候,在MVC中当前端通过Ajax提交数据到后端时,当数据的值中带有HTML标签时,可以是出于安全性方面,在后端的Controller的Action方法中是不会接收到这个Ajax请求的 (路由到相应Action方法之前已出错,通过error属性回调中的xhr.responseText可以得到如下的错误信息 )。
解决方法:可以在前端提交数据时先将带有HTML标签的数据用encodeURIComponent或escape(用encodeURI某些情况还是不能解决此问题)或Base64,比如btoa函数(需要注意:btoa不支持中文,需要先进行转换字节编码处理)编码,提交后在后端进行HttpUtility.UrlDecode或Base64(比如Convert.FromBase64String函数)解码再处理。Load数据到页面的时候无需处理。
一. 不一定可行的方法:用encodeURI编码 (测试案例)
用encodeURI编码,在测试的时候在遇到Workaround值为以下数据时,依然出现潜在安全错误无法提交,改用escape或encodeURIComponent()编码时则可以解决通过,(但需注意,escape已从W3C标准中废弃)
“<div>
<div>
<div>
<div>
<div>
<div>?Actual Issue: replication issue in the SLT system ?</div>
</div>
</div>
</div>
</div>
</div>
<div><br />
<div><span><strong>Actual Action T</strong></span><span><strong>ak</strong></span><span><strong>en:</strong></span><span>?ZMRFTRANS table in HANA database was dropped and reloaded from ECC, the reload job was load balanced and it's priority set to 1</span></div>
</div>”
二. 可行方法:
1. 用encodeURIComponent或escape方法对提交的值进行URI编码
前端提交数据:
后端Action方法:
这里说明下为什么前端用encodeURI编码为什么有不可行的情况:
由于encodeURI会排除对Url请求路径包含的字符进行编码,不像encodeURIComponent连Url中的协议和路径、参数分隔符【:/?&】都进行编码,因此encodeURI更像是浏览器地址栏编码转换所采用的行为,而针对开放给客户输入并传递给后端处理的数据为了防止客户输入还特殊分隔符字符,应该采用encodeURIComponent更适合。【详见本人另一篇博文:前后端中Url编码方法的一点小区别(encodeURI与HttpUtility.UrlEncodeUnicode、encodeURIComponent与HttpUtility.UrlEncode)-CSDN博客】
2. 可行方法2:用btoa方法对提交的值进行Base64编码:
由于btoa不支持“非单字节”字符,直接用btoa编码中文会出错,需先对中英文字符都统一转换为“单字节”字符处理(以下提供MND官方文档的转换方法):
If you need to encode Unicode text as ASCII using
btoa()
, one option is to convert the string such that each 16-bit unit occupies only one byte. For example://Base64编码中文时的转换处理方法: // convert a Unicode string to a string in which each 16-bit unit occupies only one byte function toBinary(string) { const codeUnits = new Uint16Array(string.length); for (let i = 0; i < codeUnits.length; i++) { codeUnits[i] = string.charCodeAt(i); } return String.fromCharCode(...new Uint8Array(codeUnits.buffer)); } // a string that contains characters occupying > 1 byte const myString = "☸☹☺☻☼☾☿"; const converted = toBinary(myString); const encoded = btoa(converted); console.log(encoded); // OCY5JjomOyY8Jj4mPyY=
If you do this, of course you'll have to reverse the conversion on the decoded string:
//Base64解码中文时的转换处理方法: function fromBinary(binary) { const bytes = new Uint8Array(binary.length); for (let i = 0; i < bytes.length; i++) { bytes[i] = binary.charCodeAt(i); } return String.fromCharCode(...new Uint16Array(bytes.buffer)); } const decoded = atob(encoded); const original = fromBinary(decoded); console.log(original);
前端提交数据:
后端Action方法:
题外篇:
以下是网上结合“URI编码”来解决“Base64不能直接将中文编码”的问题:
function utf8_to_b64(str) {
return window.btoa(unescape(encodeURIComponent(str)));
}
function b64_to_utf8(str) {
return decodeURIComponent(escape(window.atob(str)));
}