Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
著 Chrome 77 的發布,谷歌也為 Android 和桌面版本引入了全新的站點隔離安全特性。此前,當熔毀(Meltdown)和幽靈(Spectre)漏洞被披露的時候,谷歌就快速推出了這項安全特性,以便 Chrome 67 用戶啟用。開啟之后,Chrome 瀏覽器將把用戶訪問的每個網站,都加載到單獨的沙盒進程中,以限制其對資源和功能的訪問。
(題圖 via Bleeping Computer)
通過這種方式,能夠有效地防止惡意網站利用推測執行攻擊漏洞,來訪問加載在其它瀏覽器選項卡中的數據。
然而啟用站點隔離的代價,就是耗費更多的進程和內存資源,導致某些網站的內存用量爆炸。但在安全性和資源利用率之間,總要作出一定的權衡。
隨著 Android 版 CChrome 77 的發布,谷歌決定進一步增強對移動用戶的防護,所以引入了與桌面版本略有不同的網站隔離措施。
據悉,Android 版“網站隔離”特性,僅會保護用戶通過密碼登陸的站點,以減少移動設備的資源占用率,畢竟其處理器和內存性能都低于臺式機計算機。
谷歌表示,目前已有 99% 運行 Android 且內存超過 2GB 的用戶啟用了此功能,且有 1% 用戶保留了監測功能以提升性能。在未來,谷歌還考慮向更多設備提供支持。
對于想要提供完整站點隔離保護功能的用戶,可在地址欄輸入 chrome:// flags/#enable-site-per-process 并跳轉,然后啟用這個標記。
至于臺式機用戶,目前 Chrome 77 的“站點隔離”功能亦可保護用戶免受渲染器進程的影響。這些進程負責各個標簽頁中發生的事情,例如將 HTML、CSS 和 JavaScript 代碼轉義為網頁并顯示。
一些攻擊者試圖對其它標簽頁中的網頁代碼展開攻擊,但新加入的隔離措施,可有效防止此類惡意活動的發生。
者:HelloGitHub-追夢人物
文中涉及的示例代碼,已同步更新到HelloGitHub-Team 倉庫[1]
上一篇中我們使用了 Markdown 來為文章提供排版支持。Markdown 在解析內容的同時還可以自動提取整個內容的目錄結構,現在我們來使用 Markdown 為文章自動生成目錄。
先來回顧一下博客的 Post(文章)模型,其中 body 是我們存儲 Markdown 文本的字段:
blog/models.py from django.db import models class Post(models.Model): # Other fields ... body = models.TextField()
再來回顧一下文章詳情頁的視圖,我們在 detail 視圖函數中將 post 的 body 字段中的 Markdown 文本解析成了 HTML 文本,然后傳遞給模板顯示。
blog/views.py def detail(request, pk): post = get_object_or_404(Post, pk=pk) post.body = markdown.markdown(post.body, extensions=[ 'markdown.extensions.extra', 'markdown.extensions.codehilite', 'markdown.extensions.toc', ]) return render(request, 'blog/detail.html', context={'post': post})
markdown.markdown() 方法把 post.body 中的 Markdown 文本解析成了 HTML 文本。同時我們還給該方法提供了一個 extensions 的額外參數。其中 markdown.extensions.toc 就是自動生成目錄的拓展(這里可以看出我們有先見之明,如果你之前沒有添加的話記得現在添加進去)。
在渲染 Markdown 文本時加入了 toc 拓展后,就可以在文中插入目錄了。方法是在書寫 Markdown 文本時,在你想生成目錄的地方插入 [TOC] 標記即可。例如新寫一篇 Markdown 博文,其 Markdown 文本內容如下:
[TOC] ## 我是標題一 這是標題一下的正文 ## 我是標題二 這是標題二下的正文 ### 我是標題二下的子標題 這是標題二下的子標題的正文 ## 我是標題三 這是標題三下的正文
其最終解析后的效果就是:
原本 [TOC] 標記的地方被內容的目錄替換了。
上述方式的一個局限性就是只能通過 [TOC] 標記在文章內容中插入目錄。如果我想在頁面的其它地方,比如側邊欄插入一個目錄該怎么做呢?方法其實也很簡單,只需要稍微改動一下解析 Markdown 文本內容的方式即可,具體代碼就像這樣:
blog/views.py def detail(request, pk): post = get_object_or_404(Post, pk=pk) md = markdown.Markdown(extensions=[ 'markdown.extensions.extra', 'markdown.extensions.codehilite', 'markdown.extensions.toc', ]) post.body = md.convert(post.body) post.toc = md.toc return render(request, 'blog/detail.html', context={'post': post})
和之前的代碼不同,我們沒有直接用 markdown.markdown() 方法來渲染 post.body 中的內容,而是先實例化了一個 markdown.Markdown 對象 md,和 markdown.markdown() 方法一樣,也傳入了 extensions 參數。接著我們便使用該實例的 convert 方法將 post.body 中的 Markdown 文本解析成 HTML 文本。而一旦調用該方法后,實例 md 就會多出一個 toc 屬性,這個屬性的值就是內容的目錄,我們把 md.toc 的值賦給 post.toc 屬性(要注意這個 post 實例本身是沒有 toc 屬性的,我們給它動態添加了 toc 屬性,這就是 Python 動態語言的好處)。
接下來就在博客文章詳情頁的文章目錄側邊欄渲染文章的目錄吧!刪掉占位用的目錄內容,替換成如下代碼:
{% block toc %} <div class="widget widget-content"> <h3 class="widget-title">文章目錄</h3> {{ post.toc|safe }} </div> {% endblock toc %}
即使用模板變量標簽 {{ post.toc }} 顯示模板變量的值,注意 post.toc 實際是一段 HTML 代碼,我們知道 django 會對模板中的 HTML 代碼進行轉義,所以要使用 safe 標簽防止 django 對其轉義。其最終渲染后的效果就是:
現在目錄已經可以完美生成了,不過還有一個異常情況,當文章沒有任何標題元素時,Markdown 就提取不出目錄結構,post.toc 就是一個空的 div 標簽,如下:
<div class="toc"> <ul></ul> </div>
對于這種沒有目錄結構的文章,在側邊欄顯示一個目錄是沒有意義的,所以我們希望只有在文章存在目錄結構時,才顯示側邊欄的目錄。那么應該怎么做呢?
分析 toc 的內容,如果有目錄結構,ul 標簽中就有值,否則就沒有值。我們可以使用正則表達式來測試 ul 標簽中是否包裹有元素來確定是否存在目錄。
def detail(request, pk): post = get_object_or_404(Post, pk=pk) md = markdown.Markdown(extensions=[ 'markdown.extensions.extra', 'markdown.extensions.codehilite', 'markdown.extensions.toc', ]) post.body = md.convert(post.body) m = re.search(r'<div class="toc">\s*<ul>(.*)</ul>\s*</div>', md.toc, re.S) post.toc = m.group(1) if m is not None else '' return render(request, 'blog/detail.html', context={'post': post})
這里我們正則表達式去匹配生成的目錄中包裹在 ul 標簽中的內容,如果不為空,說明目錄,就把 ul 標簽中的值提取出來(目的是只要包含目錄內容的最核心部分,多余的 HTML 標簽結構丟掉)賦值給 post.toc;否則,將 post 的 toc 置為空字符串,然后我們就可以在模板中通過判斷 post.toc 是否為空,來決定是否顯示側欄目錄:
{% block toc %} {% if post.toc %} <div class="widget widget-content"> <h3 class="widget-title">文章目錄</h3> <div class="toc"> <ul> {{ post.toc|safe }} </ul> </div> </div> {% endif %} {% endblock toc %}
這里我們看到了一個新的模板標簽 {% if %},這個標簽用來做條件判斷,和 Python 中的 if 條件判斷是類似的。
文章內容的標題被設置了錨點,點擊目錄中的某個標題,頁面就會跳到該文章內容中標題所在的位置,這時候瀏覽器的 URL 顯示的值可能不太美觀,比如像下面的樣子:
http://127.0.0.1:8000/posts/8/#_1 http://127.0.0.1:8000/posts/8/#_3
#_1 就是錨點,Markdown 在設置錨點時利用的是標題的值,由于通常我們的標題都是中文,Markdown 沒法處理,所以它就忽略的標題的值,而是簡單地在后面加了個 \_1 這樣的錨點值。為了解決這一個問題,需要修改一下傳給 extentions 的參數,其具體做法如下:
blog/views.py from django.utils.text import slugify from markdown.extensions.toc import TocExtension def detail(request, pk): post = get_object_or_404(Post, pk=pk) md = markdown.Markdown(extensions=[ 'markdown.extensions.extra', 'markdown.extensions.codehilite', # 記得在頂部引入 TocExtension 和 slugify TocExtension(slugify=slugify), ]) post.body = md.convert(post.body) m = re.search(r'<div class="toc">\s*<ul>(.*)</ul>\s*</div>', md.toc, re.S) post.toc = m.group(1) if m is not None else '' return render(request, 'blog/detail.html', context={'post': post})
和之前不同的是,extensions 中的 toc 拓展不再是字符串 markdown.extensions.toc ,而是 TocExtension 的實例。TocExtension 在實例化時其 slugify 參數可以接受一個函數,這個函數將被用于處理標題的錨點值。Markdown 內置的處理方法不能處理中文標題,所以我們使用了 django.utils.text 中的 slugify 方法,該方法可以很好地處理中文。
這時候標題的錨點 URL 變得好看多了。
http://127.0.0.1:8000/posts/8/#我是標題一 http://127.0.0.1:8000/posts/8/#我是標題二下的子標題
References
[1] HelloGitHub-Team 倉庫: https://github.com/HelloGitHub-Team/HelloDjango-blog-tutorial
歡迎關注 HelloGitHub 公眾號,獲取更多開源項目的資料和內容
『講解開源項目系列』啟動——讓對開源項目感興趣的人不再畏懼、讓開源項目的發起者不再孤單。跟著我們的文章,你會發現編程的樂趣、使用和發現參與開源項目如此簡單。歡迎聯系我們給我們投稿,讓更多人愛上開源、貢獻開源~
*請認真填寫需求信息,我們會在24小時內與您取得聯系。