ฉันสามารถใช้ตัวอักษรพิเศษ HTML ในจาวาสคริปต์ได้หรือไม่?


202

ฉันต้องการที่จะแสดงข้อความเป็น HTML โดยฟังก์ชั่นจาวาสคริปต์ ฉันจะหลีกเลี่ยงตัวอักษรพิเศษ html ใน JS ได้อย่างไร มี API หรือไม่


11
สิ่งนี้ไม่ซ้ำกันเนื่องจากคำถามนี้ไม่ได้ถามเกี่ยวกับ jQuery ผมสนใจเฉพาะในนี้เพราะผมไม่ได้ใช้ jQuery ...
lvella

4
เป็นไปได้ซ้ำของHtmlSpecialChars เทียบเท่าใน Javascript?
Bergi

คำตอบ:


331
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;")
         .replace(/'/g, "&#039;");
 }

11
ทำไม "& # 039;" และไม่ใช่ "& apos;" ?
sereda


2
ฉันคิดว่าการแสดงออกปกติในการreplace()โทรไม่จำเป็น สตริงอักขระเดี่ยวแบบเก่าธรรมดาจะทำได้เช่นกัน
jamix

22
@jamix คุณไม่สามารถทำการทดแทนทั่วโลกด้วยสตริงดิบในขณะที่เครื่องมือเบราว์เซอร์ที่ทันสมัยเพิ่มประสิทธิภาพการแสดงออกปกติธรรมดาที่ดีงาม
bjornd

5
มี API มาตรฐานหรือนี่เป็นวิธีเดียว?
นิลการ์

57

function escapeHtml(html){
  var text = document.createTextNode(html);
  var p = document.createElement('p');
  p.appendChild(text);
  return p.innerHTML;
}

// Escape while typing & print result
document.querySelector('input').addEventListener('input', e => {
  console.clear();
  console.log( escapeHtml(e.target.value) );
});
<input style='width:90%; padding:6px;' placeholder='&lt;b&gt;cool&lt;/b&gt;'>


ทำงานที่นี่ แต่ไม่ทำงานสำหรับฉันออฟไลน์ในเบราว์เซอร์

47

คุณสามารถใช้ฟังก์ชั่นของ jQuery.text()ฟังก์ชั่น

ตัวอย่างเช่น:

http://jsfiddle.net/9H6Ch/

จากเอกสาร jQuery เกี่ยวกับ.text()ฟังก์ชัน:

เราจำเป็นต้องทราบว่าวิธีนี้จะหนีจากสตริงที่จัดให้ตามที่จำเป็นเพื่อให้สามารถแสดงผลได้อย่างถูกต้องใน HTML หากต้องการทำเช่นนั้นจะเรียกเมธอด DOM .createTextNode () ไม่ตีความสตริงเป็น HTML

jQuery Documentation เวอร์ชันก่อนหน้านี้ใช้คำนี้ ( เน้นการเพิ่ม ):

เราจำเป็นต้องทราบว่าวิธีนี้จะหนีจากสตริงที่จัดให้ตามที่จำเป็นเพื่อให้สามารถแสดงผลได้อย่างถูกต้องใน HTML หากต้องการทำเช่นนั้นจะเรียกใช้เมธอด DOM .createTextNode () ซึ่งจะแทนที่อักขระพิเศษด้วยเอนทิตี HTML ที่เทียบเท่า (เช่น & lt; สำหรับ <)


3
คุณสามารถใช้มันกับองค์ประกอบใหม่ ๆ ได้หากคุณต้องการแปลงเช่นนี้: const str = "foo<>'\"&"; $('<div>').text(str).html()อัตราผลตอบแทนfoo&lt;&gt;'"&amp;
amoebe

28

ฉันคิดว่าฉันพบวิธีที่เหมาะสมในการทำ ...

// Create a DOM Text node:
var text_node = document.createTextNode(unescaped_text);

// Get the HTML element where you want to insert the text into:
var elem = document.getElementById('msg_span');

// Optional: clear its old contents
//elem.innerHTML = '';

// Append the text node into it:
elem.appendChild(text_node);

ฉันเรียนรู้สิ่งใหม่เกี่ยวกับ HTML วันนี้ w3schools.com/jsref/met_document_createtextnode.asp
Sellorio

1
โปรดทราบว่าเนื้อหาของโหนดข้อความจะไม่ถูกหลบหนีหากคุณพยายามเข้าถึงเช่นนี้:document.createTextNode("<script>alert('Attack!')</script>").textContent
24919

นี่เป็นวิธีที่ถูกต้องหากสิ่งที่คุณทำคือการตั้งค่าข้อความ นั่นคือ textContent แต่เห็นได้ชัดว่ามันไม่ได้รับการสนับสนุนอย่างดี สิ่งนี้จะไม่ทำงานหากคุณกำลังสร้างสตริงโดยมีบางส่วนเป็นข้อความ html ดังนั้นคุณต้องหลบหนี
jgmjgm

28

ใช้Lodash

_.escape('fred, barney, & pebbles');
// => 'fred, barney, &amp; pebbles'

รหัสแหล่งที่มา


ตรงข้ามกับสิ่งนี้คืออะไร? ชื่อของฟังก์ชั่นที่ไม่ตรงข้ามกับนี้หรือไม่?
นิลการ์

1
ฟังก์ชันเดียวกันในเครื่องหมายขีดล่าง: underscorejs.org/#escape & underscorejs.org/#unescape
juanmirocks

21

นี่คือวิธีที่เร็วที่สุดที่ฉันได้เห็นมันทำไปแล้ว นอกจากนี้ยังทำได้โดยไม่ต้องเพิ่มลบหรือเปลี่ยนแปลงองค์ประกอบในหน้า

function escapeHTML(unsafeText) {
    let div = document.createElement('div');
    div.innerText = unsafeText;
    return div.innerHTML;
}

7
คำเตือน: มันไม่หนีราคาดังนั้นคุณไม่สามารถใช้ผลลัพธ์ภายในค่าแอตทริบิวต์ในรหัส HTML เช่นvar divCode = '<div data-title="' + escapeHTML('Jerry "Bull" Winston') + '">Div content</div>'จะให้ HTML ที่ไม่ถูกต้อง!
izogfif

17

มันน่าสนใจที่จะหาทางออกที่ดีกว่า:

var escapeHTML = function(unsafe) {
  return unsafe.replace(/[&<"']/g, function(m) {
    switch (m) {
      case '&':
        return '&amp;';
      case '<':
        return '&lt;';
      case '"':
        return '&quot;';
      default:
        return '&#039;';
    }
  });
};

ฉันไม่แยกวิเคราะห์>เพราะไม่ทำลายโค้ด XML / HTML ในผลลัพธ์

นี่คือมาตรฐาน: http://jsperf.com/regexpairs นอกจากนี้ฉันได้สร้างescapeฟังก์ชั่นสากล: http://jsperf.com/regexpairs2


1
มันน่าสนใจที่จะเห็นว่าการใช้สวิตช์เร็วกว่าแผนที่อย่างมาก ฉันไม่ได้คาดหวังสิ่งนี้! ขอบคุณสำหรับการแบ่งปัน!
ปีเตอร์ต.

มีอักขระ Unicode มากมายเกินกว่าที่คุณจะสามารถใช้รหัสได้ ฉันไม่แนะนำวิธีการด้วยตนเองเลย
vsync

เหตุใดคุณจึงต้องหลีกเลี่ยงอักขระหลายไบต์ เพียงใช้ UTF-8 ในทุกที่
Neonit

4
การข้าม> อาจทำลายรหัสได้ คุณต้องจำไว้ว่าภายใน <> นั้นเป็น html ด้วย ในกรณีนั้นการข้าม> จะแตก หากคุณกำลังหลบหนีเฉพาะระหว่างแท็กคุณอาจต้องใช้ Escape <และ &
jgmjgm

8

วิธีที่รัดกุมและมีประสิทธิภาพที่สุดในการแสดงข้อความที่ไม่ได้เข้ารหัสคือการใช้textContentคุณสมบัติ

ได้เร็วขึ้นinnerHTMLกว่าการใช้ และนั่นคือโดยไม่คำนึงถึงค่าใช้จ่ายในการหลบหนี

document.body.textContent = 'a <b> c </b>';


@ZzZombo เป็นเรื่องปกติอย่างสมบูรณ์ที่ไม่ทำงานกับแท็กสไตล์และสคริปต์ เมื่อคุณเพิ่มเนื้อหาลงในพวกเขาคุณเพิ่มรหัสไม่ใช่ข้อความใช้ InnerHTML ในกรณีนี้ ยิ่งไปกว่านั้นคุณไม่จำเป็นต้องหลบหนีสิ่งเหล่านี้เป็นสองแท็กพิเศษที่ไม่ได้แยกวิเคราะห์เป็น HTML เมื่อแยกวิเคราะห์เนื้อหาของพวกเขาได้รับการปฏิบัติเป็นข้อความจนกว่าลำดับปิด</จะพบ
ผู้ใช้

6

สนับสนุน DOM องค์ประกอบการแปลงข้อความเป็น HTML โดยมอบหมายให้innerText innerText ไม่ใช่ฟังก์ชั่น แต่การกำหนดให้มันทำงานเหมือนกับว่าข้อความถูกหลบหนี

document.querySelectorAll('#id')[0].innerText = 'unsafe " String >><>';

1
อย่างน้อยใน Chrome ที่กำหนดข้อความหลายบรรทัดเพิ่ม<br>องค์ประกอบแทนที่บรรทัดใหม่ที่สามารถแบ่งองค์ประกอบบางอย่างเช่นสไตล์หรือสคริปต์ createTextNodeไม่ได้มีแนวโน้มที่จะแก้ไขปัญหานี้
ZzZombo

1
innerTextมีปัญหาดั้งเดิม / ข้อมูลจำเพาะบางอย่าง textContentดีกว่าที่จะใช้
รอยทิงเกอร์

3

คุณสามารถเข้ารหัสอักขระทุกตัวในสตริงของคุณ:

function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}

หรือเพียงกำหนดเป้าหมายตัวละครหลักเพื่อกังวลเกี่ยวกับ (&, inebreaks, <,>, "และ ') เช่น:

function encode(r){
return r.replace(/[\x26\x0A\<>'"]/g,function(r){return"&#"+r.charCodeAt(0)+";"})
}

test.value=encode('How to encode\nonly html tags &<>\'" nice & fast!');

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<textarea id=test rows="9" cols="55">&#119;&#119;&#119;&#46;&#87;&#72;&#65;&#75;&#46;&#99;&#111;&#109;</textarea>


การเขียนฟังก์ชั่นหลบหนีของคุณเองเป็นความคิดที่ไม่ดี คำตอบอื่น ๆ ดีกว่าในเรื่องนี้
jannis

2

หนึ่งซับ (สำหรับ ES6 +):

var escapeHtml = s => (s + '').replace(/[&<>"']/g, m => ({
    '&': '&amp;', '<': '&lt;', '>': '&gt;',
    '"': '&quot;', "'": '&#39;'
})[m]);

สำหรับรุ่นเก่า:

function escapeHtml(s) {
    return (s + '').replace(/[&<>"']/g, function (m) {
        return ({
            '&': '&amp;', '<': '&lt;', '>': '&gt;',
            '"': '&quot;', "'": '&#39;'
        })[m];
    });
}

0

มาข้ามปัญหานี้เมื่อสร้างโครงสร้าง DOM คำถามนี้ช่วยฉันแก้ปัญหา ฉันต้องการใช้เครื่องหมายบั้งคู่เป็นตัวคั่นพา ธ แต่การผนวกโหนดข้อความใหม่ส่งผลโดยตรงในการแสดงรหัสอักขระที่หลบหนีมากกว่าตัวอักขระ:

var _div = document.createElement('div');
var _separator = document.createTextNode('&raquo;');
//_div.appendChild(_separator); /* this resulted in '&raquo;' being displayed */
_div.innerHTML = _separator.textContent; /* this was key */

0

หากคุณใช้โมดูลในแอปของคุณอยู่แล้วคุณสามารถใช้โมดูล escape-html

import escapeHtml from 'escape-html';
const unsafeString = '<script>alert("XSS");</script>';
const safeString = escapeHtml(unsafeString);


-4

ฉันคิดวิธีแก้ปัญหานี้

สมมติว่าเราต้องการเพิ่ม html ลงในองค์ประกอบด้วยข้อมูลที่ไม่ปลอดภัยจากผู้ใช้หรือฐานข้อมูล

var unsafe = 'some unsafe data like <script>alert("oops");</script> here';

var html = '';
html += '<div>';
html += '<p>' + unsafe + '</p>';
html += '</div>';

element.html(html);

ไม่ปลอดภัยต่อการโจมตี XSS ตอนนี้เพิ่มสิ่งนี้

$(document.createElement('div')).html(unsafe).text();

ดังนั้นมันจึงเป็น

var unsafe = 'some unsafe data like <script>alert("oops");</script> here';

var html = '';
html += '<div>';
html += '<p>' + $(document.createElement('div')).html(unsafe).text(); + '</p>';
html += '</div>';

element.html(html);

สำหรับฉันมันง่ายกว่าการใช้.replace()และมันจะลบ !!! แท็ก html ที่เป็นไปได้ทั้งหมด (ฉันหวังว่า)


นี่เป็นความคิดที่อันตรายมันแยกสตริง HTML ที่ไม่ปลอดภัยเป็น HTML ถ้าองค์ประกอบถูกแนบกับ DOM มันจะ exeute ใช้. textText แทน
teknopaul

สิ่งนี้ไม่ปลอดภัย มันจะแปลงลงใน&lt;script&gt; <script>
fgb
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.