Từ Chrome 120, một tuỳ chọn unsanitized
mới sẽ xuất hiện trong Bảng nhớ tạm không đồng bộ
API. Tuỳ chọn này có thể hữu ích trong các trường hợp đặc biệt với HTML, khi bạn cần
dán nội dung của bảng nhớ tạm giống với nội dung khi được sao chép.
Tức là không có bất kỳ bước dọn dẹp trung gian nào mà các trình duyệt thường sử dụng—và
vì lý do chính đáng—hãy đăng ký. Hãy tìm hiểu cách sử dụng chúng trong hướng dẫn này.
Khi làm việc với API Bảng nhớ tạm không đồng bộ, trong phần lớn trường hợp, nhà phát triển không cần lo lắng về tính toàn vẹn của nội dung trên bảng nhớ tạm và có thể giả định rằng những gì chúng viết vào bảng nhớ tạm (bản sao) tương tự với nội dung mà họ sẽ nhận được khi đọc dữ liệu từ bảng nhớ tạm (dán).
Điều này chắc chắn đúng với văn bản. Hãy thử dán mã sau vào Công cụ cho nhà phát triển
Console, sau đó lấy nét lại trang ngay lập tức. (Cần có setTimeout()
để bạn có đủ thời gian để tập trung vào trang, đây là một yêu cầu của
API Bảng nhớ tạm.) Như bạn thấy, dữ liệu đầu vào chính xác giống với dữ liệu đầu ra.
setTimeout(async () => {
const input = 'Hello';
await navigator.clipboard.writeText(input);
const output = await navigator.clipboard.readText();
console.log(input, output, input === output);
// Logs "Hello Hello true".
}, 3000);
Hình ảnh sẽ hơi khác một chút. Để ngăn chặn những điều gọi là tấn công bằng bom nén, trình duyệt mã hoá lại hình ảnh như PNG, nhưng hình ảnh đầu vào và đầu ra trực quan giống nhau, pixel trên pixel.
setTimeout(async () => {
const dataURL =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=';
const input = await fetch(dataURL).then((response) => response.blob());
await navigator.clipboard.write([
new ClipboardItem({
[input.type]: input,
}),
]);
const [clipboardItem] = await navigator.clipboard.read();
const output = await clipboardItem.getType(input.type);
console.log(input.size, output.size, input.type === output.type);
// Logs "68 161 true".
}, 3000);
Tuy nhiên, điều gì sẽ xảy ra với văn bản HTML? Như bạn có thể đã đoán, với HTML,
tình hình lại khác nhau. Ở đây, trình duyệt dọn dẹp mã HTML để ngăn chặn trang web không hợp lệ
những thứ khác xảy ra, chẳng hạn như bằng cách tách thẻ <script>
khỏi HTML
mã (và các mã khác như <meta>
, <head>
và <style>
) và bằng cách cùng dòng CSS.
Hãy xem xét ví dụ sau đây và thử trong Bảng điều khiển công cụ cho nhà phát triển. Bạn sẽ
lưu ý rằng đầu ra khác biệt khá đáng kể so với đầu vào.
setTimeout(async () => {
const input = `<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="ProgId" content="Excel.Sheet" />
<meta name="Generator" content="Microsoft Excel 15" />
<style>
body {
font-family: HK Grotesk;
background-color: var(--color-bg);
}
</style>
</head>
<body>
<div>hello</div>
</body>
</html>`;
const inputBlob = new Blob([input], { type: 'text/html' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': inputBlob,
}),
]);
const [clipboardItem] = await navigator.clipboard.read();
const outputBlob = await clipboardItem.getType('text/html');
const output = await outputBlob.text();
console.log(input, output);
}, 3000);
Dọn dẹp HTML thường là một điểm tốt. Bạn không muốn tiết lộ bản thân vào các vấn đề bảo mật bằng cách cho phép HTML không được dọn dẹp trong phần lớn các trường hợp. Có là các tình huống mà trong đó nhà phát triển biết chính xác họ đang làm gì và trong đó tính toàn vẹn của HTML đầu vào và đầu ra rất quan trọng đối với việc hiển thị hoạt động của ứng dụng. Trong những trường hợp như vậy, bạn có hai lựa chọn:
- Nếu bạn kiểm soát cả thao tác sao chép và dán, ví dụ: nếu bạn sao chép từ bên trong ứng dụng để sau đó dán vào ứng dụng, bạn nên sử dụng Các định dạng tuỳ chỉnh trên web cho API Bảng nhớ tạm không đồng bộ. Hãy dừng đọc ở đây và xem bài viết được liên kết.
- Nếu bạn chỉ kiểm soát việc dán trong ứng dụng chứ không kiểm soát việc sao chép,
có thể là do thao tác sao chép diễn ra trong một ứng dụng gốc không hỗ trợ
trên web, bạn nên sử dụng tùy chọn
unsanitized
, tức là được giải thích trong phần còn lại của bài viết này.
Quy trình dọn dẹp bao gồm xoá thẻ script
, kiểu cùng dòng và
đảm bảo HTML được định dạng đúng. Danh sách này không đầy đủ và nhiều
có thể được bổ sung trong tương lai.
Sao chép và dán HTML chưa được dọn dẹp
Khi bạn write()
(sao chép) HTML vào bảng nhớ tạm bằng API Bảng nhớ tạm không đồng bộ,
trình duyệt sẽ đảm bảo trình duyệt được định dạng đúng bằng cách chạy trình duyệt qua trình phân tích cú pháp DOM
và chuyển đổi tuần tự chuỗi HTML thu được, nhưng quy trình dọn dẹp không diễn ra
bước này. Bạn không cần phải làm gì cả. Khi bạn read()
HTML đặt trên
bảng nhớ tạm của một ứng dụng khác và ứng dụng web của bạn đang chọn nhận
nội dung có độ trung thực đầy đủ và cần bạn dọn dẹp trong mã của riêng mình,
bạn có thể truyền một đối tượng tuỳ chọn đến phương thức read()
bằng một thuộc tính
unsanitized
và giá trị là ['text/html']
. Riêng biệt, giao diện sẽ có dạng như sau:
navigator.clipboard.read({ unsanitized: ['text/html'] })
. Mã mẫu sau đây
bên dưới gần giống với hình ảnh hiển thị trước đó, nhưng lần này là với unsanitized
. Khi bạn dùng thử trong Bảng điều khiển công cụ cho nhà phát triển, bạn sẽ thấy rằng đầu vào và
thì kết quả sẽ giống nhau.
setTimeout(async () => {
const input = `<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="ProgId" content="Excel.Sheet" />
<meta name="Generator" content="Microsoft Excel 15" />
<style>
body {
font-family: HK Grotesk;
background-color: var(--color-bg);
}
</style>
</head>
<body>
<div>hello</div>
</body>
</html>`;
const inputBlob = new Blob([input], { type: 'text/html' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': inputBlob,
}),
]);
const [clipboardItem] = await navigator.clipboard.read({
unsanitized: ['text/html'],
});
const outputBlob = await clipboardItem.getType('text/html');
const output = await outputBlob.text();
console.log(input, output);
}, 3000);
Hỗ trợ trình duyệt và phát hiện tính năng
Không có cách trực tiếp nào để kiểm tra xem tính năng này có được hỗ trợ hay không, vì vậy
dựa trên việc quan sát hành vi. Do đó, ví dụ sau
dựa vào việc phát hiện thực tế là liệu thẻ <style>
có còn tồn tại hay không, điều này
biểu thị hỗ trợ, hoặc đang hiển thị cùng dòng, biểu thị việc không hỗ trợ. Lưu ý rằng
để tính năng này hoạt động, trang cần phải có được bảng nhớ tạm
quyền.
const supportsUnsanitized = async () => {
const input = `<style>p{color:red}</style><p>a`;
const inputBlob = new Blob([input], { type: 'text/html' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': inputBlob,
}),
]);
const [clipboardItem] = await navigator.clipboard.read({
unsanitized: ['text/html],
});
const outputBlob = await clipboardItem.getType('text/html');
const output = await outputBlob.text();
return /<style>/.test(output);
};
Bản minh hoạ
Để xem tuỳ chọn unsanitized
trong thực tế, hãy xem
bản minh hoạ về Glitch và xem bản minh hoạ
mã nguồn.
Kết luận
Như đã nêu trong phần giới thiệu, hầu hết các nhà phát triển sẽ không bao giờ phải lo lắng về
dọn dẹp bảng nhớ tạm và có thể hoạt động với các lựa chọn dọn dẹp mặc định
do trình duyệt thực hiện. Trong một số ít trường hợp mà nhà phát triển cần quan tâm,
Đã tồn tại lựa chọn unsanitized
.
Đường liên kết hữu ích
Xác nhận
Bài viết này do Anupam Snigdha xem xét và Rachel Andrew. API đã được chỉ định và do nhóm Microsoft Edge triển khai.