使用 MarkupString 在 Blazor 中渲染原始 HTML

· 1 分钟阅读

有一天,我正在构建一个组件,需要渲染一些来自 CMS 的 HTML。我将 HTML 字符串放在一个变量中,然后将其放入模板中,例如 @myHtml。当然,Blazor 转义了所有内容并将实际标签呈现为页面上的文本。不是我想要的。

问题

默认情况下,Blazor 对您在模板中呈现的任何字符串进行编码。所以如果你有:

@code {
    private string content = "<strong>Hello</strong> <em>world</em>";
}

你这样做:

<div>@content</div>

您将在页面上看到文字文本 <strong>Hello</strong> <em>world</em>,而不是 Hello world。 Blazor 这样做的目的是为了防止 XSS 攻击,这是正确的默认行为。

解决方案:MarkupString

如果您确实需要渲染原始 HTML,请将字符串包装在 MarkupString 中:

<div>@((MarkupString)content)</div>

就是这样!现在 Blazor 会将 HTML 呈现为实际标记。您还可以将其分配给变量:

@code {
    private string rawHtml = "<strong>Hello</strong> <em>world</em>";
    private MarkupString HtmlContent => (MarkupString)rawHtml;
}
<div>@HtmlContent</div>

一个现实世界的例子

我从 API 中提取博客内容,并需要在预览组件中呈现它。内容包含各种 HTML——标题、代码块、链接、图像。大概是这样的:

@inject HttpClient Http

@if (article is not null)
{
    <article>
        <h1>@article.Title</h1>
        <div class="content">
            @((MarkupString)article.HtmlBody)
        </div>
    </article>
}

@code {
    [Parameter]
    public int ArticleId { get; set; }

    private ArticleDto? article;

    protected override async Task OnInitializedAsync()
    {
        article = await Http.GetFromJsonAsync<ArticleDto>($"api/articles/{ArticleId}");
    }
}

工作完美。来自 API 的 HTML 被呈现为实际标记。

小心不受信任的内容

这很重要:MarkupString 不会**清理 HTML。它会渲染您提供的任何内容,包括 <script> 标签。因此,如果内容来自用户输入或不受信任的来源,您需要首先对其进行清理。

Blazor 中没有内置的 HTML 清理程序,但您可以使用 HtmlSanitizer 等库:

using Ganss.Xss;

@code {
    private HtmlSanitizer sanitizer = new();

    private MarkupString SafeHtml(string html)
    {
        var clean = sanitizer.Sanitize(html);
        return (MarkupString)clean;
    }
}
<div>@SafeHtml(untrustedContent)</div>

这会去除危险元素,例如 <script>onclick 处理程序以及您不希望从用户提供的内容中呈现的其他内容。

何时使用它

我使用 MarkupString 来:

  • CMS 内容或 markdown 已转换为 HTML 服务器端
  • 富文本编辑器输出
  • 电子邮件模板预览
  • 来自可信来源的任何预构建 HTML

对于来自用户输入的任何内容,始终首先进行清理。安全总比后悔好。

希望你喜欢这篇文章!请随时通过任何社交媒体与我联系:@emimontesdeoca

资源