利用 RSS 功能,不用到網站也能收到最新文章
維基百科對 RSS 的解釋是這樣的:
RSS(英文全稱:RDF Site Summary 或 Really Simple Syndication),中文譯作簡易資訊聚合,也稱聚合內容,是一種訊息來源格式規範,用以聚合多個網站更新的內容並自動通知網站訂閱者。使用 RSS 後,網站訂閱者便無需再手動檢視網站是否有新的內容,同時 RSS 可將多個網站更新的內容進行整合,以摘要的形式呈現,有助於訂閱者快速獲取重要資訊,並選擇性地點閱檢視。
部落格系統或是新聞資訊網站大多提供 RSS 訂閱功能,使用者在 RSS 程式或 app 輸入訂閱網址後接收更新資訊,不用開網站就能閱讀最新消息。
在 Laravel 建立 RSS 訂閱功能過程簡介
Laravel 有許多 RSS 相關的套件,自己則是閱讀 〈How to Create RSS Feed in Laravel 9 Example〉這篇文章後瞭解:以我的部落格來說,利用現有功能就可以打造簡單的 RSS 訂閱服務。
整個過程大致如下:
- 有個用 Laravel 框架建立的專案網站。
- 透過 migration 建立儲存文章的資料表,並建立操作資料表的 Model。
- 有個與 RSS 訂閱用的 Controller,撰寫方法:將要推送的文章傳送到 RSS 訂閱 blade template。
- 為 RSS 訂閱建立 blade template,使用 XML 格式呈現 Controller 傳過來的資料。
- 建立路由,同時也是 RSS 訂閱網址。
程式碼無問題但是報錯,去問 ChatGPT
瞭解建立流程後撰寫有關程式碼,關於 Controller 部分我是這樣寫的:
<?php
namespace App\\Http\\Controllers;
use App\\Models\\Article;
use Illuminate\\Http\\Request;
class RSSFeedController extends Controller
{
public function index()
{
$articles = Article::latest()->get();
return response()->view('frontend.rss', [
'articles' => $articles
])->header('Content-Type', 'text/xml');
}
}
顯示訂閱資料的 blade template 是這樣:
<?=
'<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL ?>
<rss version="2.0">
<channel>
<title>
<![CDATA[ abo.tw ]]>
</title>
<link>
<![CDATA[ <https://abo.tw/feed> ]]>
</link>
<description>
<![CDATA[ A-Bo 的部落格文章 ]]>
</description>
<language>zh_TW</language>
<pubDate>{{ now() }}</pubDate>
@foreach ($articles as $article)
<item>
<title>
<![CDATA[{{ $article->title }}]]>
</title>
<link>{{ $article->slug }}</link>
<description>
<![CDATA[{!! $article->content !!}]]>
</description>
<category>{{ $article->category->name }}</category>
<author>
<![CDATA[Made Sun Neng Lee aka A-Bo Lee]]>
</author>
<guid>{{ $article->id }}</guid>
<pubDate>
{{ $article->created_at->toRssString() }}
</pubDate>
</item>
@endforeach
</channel>
</rss>
路由內容是這樣子:
// RSS Feed
Route::get('feed', 'App\\Http\\Controllers\\RSSFeedController@index');
檢查完程式內容無誤後在瀏覽器輸入訂閱網址,原本預期會看到 XML 頁面內容但是看到的是 Laravel 的除錯畫面,錯誤訊息提到「created_at(建立 migration 時預設建立欄位,用以記載建立時間)」為 null。
怎麼會…拿第一筆記錄出來用 dd 函式檢驗看看
$article = Article::find(1);
dd($article->created_at->toRssString());
加上上述程式碼後畫面輸出以 RSS 格式顯示的建立日期,也就是說傳遞的資料是沒有問題的,那現在換我不知道問題在哪了…
此時偶然想到主管之前提過:可以試試將程式碼以及自己的疑問丟給 ChatGPT,看她怎麼回答你。我將上述內容跟 created_at 怎麼會是 null 的疑問丟給了 ChatGPT,得到了以下的回答:
「可能是迴圈中的某個文章」引起我的注意,難道說有文章的「created_at」欄位值是空白的嗎?
還真的有。
網站的「服務條款」跟「隱私權政策」是以文章的方式存在資料庫中,並且在「created_at」欄位部分是空白的。在顯示上「網站運作用文件」與「網站文章」是分開處理的,但是因為我在 Controller 中寫的程式碼關係將「articles」資料表的所有記錄都查詢出來,包含「created_at」欄位沒有資料的網站文件…
加上「精選」為「是」這個篩選條件後,瀏覽器開啟訂閱網址顯示的是 XML 格式的內容頁面,網站能提供 RSS 訂閱了。
$articles = Article::latest()->where('featured', 'yes')->get();
「程式是按你寫的跑,不是按你想的跑」,受教了。
網站能夠訂閱了,不過圖片出不來
用 iPad 上的 RSS 訂閱程式輸入訂閱網址後接收到網站文章標題、內文等內容,同時也發現:文章內的圖片無法顯示。
為了能在本機環境或是在正式環境都能正確顯示,關於圖片檔案的路徑描述我使用的是「相對路徑」格式:列出相對於 Web 伺服器根目錄的描述。換成 RSS 訂閱,環境不同的情況就行不通了。
圖檔改成絕對路徑描述就能讓讓訂閱者在有網路連線的情況下看到圖片,不過相對的在本機測試環境中圖片就不是讀取本機檔案而是網站檔案,有沒有兩全其美的方法呢?
重新檢視整個流程,發現自己的死腦筋
想到這邊,我才恍然大悟:我把兩件事情混淆成一件事了。
回顧流程:
- 查詢 articles(文章)資料表中精選為「是」的所有文章,將結果倒序排列指定為變數 $articles。
- 將 $articles 傳送到 blade template 顯示。
此時的 $articles 儲存的是查詢結果而不是資料表本身,對 $articles 所做的任何變動都與資料表無關,直到我將結果寫回資料表之前都是如此。
所以我可以(本來就是,唉)在用 $articles 接收查詢結果後,透過 foreach 函式將圖片網址替換為絕對路徑表示,以及加入其他為了 RSS 訂閱增加的 HTML 描述語法後寫回 $articles,上述作業皆與資料表內容無關。
更改過後的程式碼如下:
$articles = Article::latest()->where('featured', 'yes')->get();
// 遍歷 $articles 集合中的每篇文章
foreach ($articles as $article) {
// 讀取文章的 content 屬性
$content = $article->content;
// 替換 content 中的字串
$newContent = str_replace('src="/storage', 'width="100%" src="https://' . $_SERVER['SERVER_NAME'] . '/storage', $content);
// 將修改後的 content 值寫回
$article->content = $newContent;
}
程式問題可以問 ChatGPT,前提是能理解程式碼
從 2022 年底開放公眾使用開始我經常使用 ChatGPT 詢問程式方面的問題,在瞭解其便利性(例如詢問不熟悉的語言如 JavaScript)的同時也意識到:ChatGPT 是個大型語言預訓練模型,她雖然可以依據你輸入的內容提供最接近的結果,但是她並不知道(本文撰寫當時的情況)提供的結果是否正確,「一臉正經說幹話」的情況是會發生的。
如果你對要撰寫的程式碼語法很清楚,可以將需求細節提供給 ChatGPT,請她輸出程式碼後再調整部分內容,節省大量輸入時間:前提是你要知道她寫了什麼。
在基礎層次、重複性高、變化性低的知識產製已經可以用 ChatGPT 取代,可以說「○○工作被新技術取代」的說法從工業革命時期就有,但是就在被取代的同時也會衍生新的工作需求。「瞭解自身優勢,善用新技術強化自身實力」會是各類人工智慧發展下唯一的努力方向。
居住在臺灣的 Joomler,期望以程式設計、開放原碼推廣活動收入養活一家老小。
35 歲後改姓李,id 作為曾為郭姓的證明。
FFXI:Abokuo@Sylph鯖、よろしくです。