RSS से 66 सोशल नेटवर्क तक: Facebook, Instagram, X, LinkedIn, Telegram और भी बहुत कुछ ब्लॉग एफिलिएट संपर्क
साइन इन करें फ्री शुरू करें
Updated: 2026-10-20
Mojolicious RSS Feed in Perl: Template, ETag and Auto-Post

Short answer: To serve an RSS feed from a Mojolicious application, add a route for /feed.xml, read the newest published rows with Mojo::SQLite or DBI, render an .ep template whose output is escaped automatically, format dates with Mojo::Date and return the result with the RSS format. Use the is_fresh helper with an ETag so repeat requests get a cheap 304 answer, test the address with curl and a validator, and then give the public URL to an auto-poster so every new item reaches your social channels.

Mojolicious is a real-time web framework for Perl that needs no dependencies beyond the language itself, and it is a favourite for small tools, internal services and long-running sites that have outlived many trends. Sooner or later such an application publishes something that people want to follow: articles, release notes, listings or event dates. A feed is the standard way to let readers, aggregators and auto-posters watch that content without an account or an API key. This guide builds a complete Mojolicious RSS feed with caching and conditional requests, explains each decision and ends with the checks that keep the feed dependable once other systems rely on it.

When a Mojolicious app needs a feed

A feed is worth adding whenever the application publishes things that people outside it want to follow:

  • articles, news or announcements stored in a database and shown through the application;
  • release notes or a changelog for a module or a public tool;
  • listings, events or offers added by staff or by users;
  • any content that should also appear on social networks without being copied by hand.

If your content already lives in a blog or a CMS, use the feed it provides instead; see how to find your WordPress feed link. For the same job in PHP, see the plain PHP and MySQL guide.

Set up the project

Install Mojolicious and the SQLite helper from CPAN. The example uses a SQLite file, but the query and the template stay the same with any database that DBI can reach.

cpanm Mojolicious Mojo::SQLite
mkdir feedapp && cd feedapp

Keep the public address of the site in configuration rather than reading it from the incoming request. Behind a proxy, the request may show an internal host name, and a feed full of internal addresses is useless to every reader. The example reads it from an environment variable with a safe default.

The application

The program below fits in one file. It opens the database, defines the feed route, builds an ETag from the newest publication time and the number of items, answers a matching request with a 304 and otherwise renders the template. The condition on the publication time matters. Without it, an item scheduled for tomorrow would appear in the feed today, and an auto-poster would share it before it exists on the website. Publication times are stored as Unix timestamps.

#!/usr/bin/env perl
use Mojolicious::Lite -signatures;
use Mojo::SQLite;
use Mojo::Date;

my $site_url = $ENV{SITE_URL} // 'https://www.example.com';
my $sql = Mojo::SQLite->new('sqlite:data/site.db');

helper latest_posts => sub ($c) {
  return $sql->db->query(
    q{SELECT id, title, slug, summary, published_at
        FROM posts
       WHERE status = 'published' AND published_at <= ?
       ORDER BY published_at DESC
       LIMIT 20}, time)->hashes;
};

get '/feed.xml' => sub ($c) {
  my $posts = $c->latest_posts;
  my $newest = $posts->size ? $posts->first->{published_at} : 0;
  my $etag = sprintf('"%s-%s"', $newest, $posts->size);

  $c->res->headers->cache_control('public, max-age=300');
  return $c->rendered(304) if $c->is_fresh(etag => $etag);

  $c->stash(posts => $posts, site_url => $site_url);
  $c->render(template => 'feed', format => 'rss');
};

app->start;

__DATA__

@@ feed.rss.ep
% use Mojo::Date;
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Example News</title>
    <link><%= $site_url %>/</link>
    <description>The latest posts from Example News</description>
    <language>en</language>
    <atom:link href="<%= $site_url %>/feed.xml" rel="self" type="application/rss+xml"/>
% for my $p (@$posts) {
    <item>
      <title><%= $p->{title} %></title>
      <link><%= $site_url %>/<%= $p->{slug} %>/</link>
      <guid isPermaLink="false">post-<%= $p->{id} %></guid>
      <pubDate><%= Mojo::Date->new($p->{published_at})->to_string %></pubDate>
      <description><%= $p->{summary} %></description>
    </item>
% }
  </channel>
</rss>

Run it with perl feed.pl daemon, or with morbo feed.pl while you develop, and open the route in a browser or with curl. You should see well-formed XML with at most twenty items, newest first. The name feed.rss.ep tells Mojolicious that the template produces the rss format, and the format argument in the render call selects it, which sets the content type application/rss+xml.

Escaping that happens for you

In an .ep template, the expression with an equals sign escapes its output by default. A title containing an ampersand or an angle bracket is converted to the proper XML entity, so the feed stays valid. This is the main reason to use a template instead of joining strings by hand. The one exception is the expression with a double equals sign, which prints raw text; never use it for titles or summaries that come from a database or from users. If a summary legitimately contains HTML, wrap it in a CDATA block or escape it, as described in the CDATA guide.

Where each field comes from

Feed fieldSource in the exampleRule to keep
titleThe title columnPlain text, escaped, no markup
linkSite address plus slugAbsolute address that returns 200 directly
guidThe row id with a prefixNever changes, even if the slug changes
pubDateThe publication timestamp in UTCEnglish day and month names, never in the future
descriptionThe summary columnOne or two sentences that make sense alone

The identifier is the most important decision. An auto-poster remembers which items it has already shared by their GUID. If the value changes when someone edits a slug or republishes an article, the same story is shared again. Using the database id with a fixed prefix avoids that. The problem and its fixes are described in why a feed auto-posts the same article twice.

Dates in the English format

RSS dates follow RFC 822, with English abbreviations for days and months. The Mojo::Date module prints a timestamp in the HTTP date format, which has English names and ends with GMT, and it does so whatever the language of the server. Avoid strftime with a locale setting for feeds, because a different locale would print month names that readers cannot parse. If you see date warnings in a validator, read the guide to RSS date format errors.

Conditional requests and caching

Auto-posters, readers and search engines request a feed often, and almost always nothing has changed. The route above handles that in two ways. The is_fresh helper compares the ETag with the If-None-Match header of the request and sets the ETag header on the response, so the route can finish with a 304 and no body. The Cache-Control header lets a proxy or a content delivery network keep the response for a few minutes. Together they cut the cost of each check to one query.

The ETag in the example combines the newest publication time with the number of items, which changes when a new item appears or an old one is removed. If you edit old items and want the feed to change, store an updated time and include it in the value. The background to both techniques is in the guide to ETags and conditional GET और the guide to feed caching. Do not cache for hours, because a long cache delays every new post by the same amount.

Running behind a proxy in production

In production, run the application with the hypnotoad server or under a process manager, and put a reverse proxy in front of it that terminates HTTPS. Tell Mojolicious that it is behind a proxy, so that it reads the forwarded headers correctly, and keep the public address in your own setting rather than depending on them. Check that the proxy does not strip the ETag and Cache-Control headers, and that it does not add its own cache that keeps old XML for too long. After every deployment, request the feed once to confirm that it still returns 200 and that the address is exactly the one you gave to the auto-poster. If the feed ever stops updating, this checklist shows what to inspect first.

Images and richer items

An auto-poster is more useful when each item carries a picture. Add an enclosure element with the address, the byte length and the type of the image, or a media content element if you prefer that namespace. Use an absolute https address and a file of reasonable size. Without an image, many networks show a plain text card. How tools read these elements is explained in the guide to enclosure tags.

Test the feed before you connect it

  1. Request the route with curl and look at the headers: the status should be 200, the content type should be application/rss+xml and an ETag should be present.
  2. Repeat the request with the ETag in an If-None-Match header and confirm that a 304 comes back.
  3. Paste the public address into the W3C Feed Validation Service and fix every error.
  4. Insert a test row and check that it appears at the top of the feed.
  5. Set a publication time in the future and check that the item stays hidden until then.

There is a longer checklist in the feed validation guide and a short curl routine in the guide to debugging a feed with curl.

Common mistakes to avoid

  • Raw output. Never print titles or summaries with the double equals expression; use the escaped form.
  • Future items. Filter by publication time so scheduled content stays hidden until its moment.
  • Unstable GUIDs. Use an identifier that never changes.
  • Wrong character encoding. Keep the database, the template and the response in UTF-8 and declare it in the XML.
  • Addresses taken from the request. Build links from the configured public address.
  • Changing the feed address. Keep the route, or redirect the old one permanently.

How PostRSS works with a Mojolicious feed

PostRSS has been publishing RSS and Atom feeds to social networks since 2014. Paste the address of your feed route, connect your accounts and choose how each post is built from the title, the description or the page title. PostRSS checks the feed as often as every minute and shares each new item, with its image and link, to the channels you choose among 66 supported networks, messengers, team chats and blogs, including LinkedIn, X, Bluesky, Mastodon and Telegram. Keyword filters, UTM parameters and posting windows let you tune each channel, and webhooks connect PostRSS to your own systems. See the PostRSS features page and the plan limits on the pricing page. More developer guides are under the Technical Guide tag.

संबंधित लेख

The bottom line

Mojolicious needs only a route, a query and one template to serve a dependable RSS feed: select published items dated in the past, let the template escape every value, use a stable GUID, format dates in English UTC with Mojo::Date, build links from a configured public address and render the rss format with an ETag and a short cache. Test the route with curl and a validator, keep the address unchanged and connect it to an auto-poster. After that, every item you publish can reach your social channels automatically.

FAQ

Does Mojolicious have a built-in RSS generator?

No. Mojolicious has no feed support in its core, but its templates make a feed easy to write. The rss format is known to the framework, so the response gets the right content type.

Why is the output escaped automatically?

The standard template expression escapes special characters, so a title with an ampersand or an angle bracket cannot break the XML. Print raw text only for markup you wrote yourself.

What does the is_fresh helper do?

It compares the ETag you supply with the If-None-Match header of the request and sets the response header. When they match, you can finish with a 304 answer and no body, which saves bandwidth for both sides.

How many items should the feed contain?

Between ten and twenty of the newest published items is enough. An auto-poster only needs recent items, and a smaller file is faster to download and parse.

How do I stop old posts from being shared again?

Give every item a stable identifier and use it as the GUID. Avoid editing the publication date of items that are already public, because some tools treat a changed date as a new item.

Can I use this feed with PostRSS?

Yes. PostRSS reads any valid RSS or Atom address that is reachable without a login. Paste the address, connect your channels and new items are shared as soon as they appear.

New guides, once a month

What changed in the networks, what broke, and how to fix it before it costs you reach.

We send a confirmation e-mail first. Unsubscribe any time.

हमारी टीम के और टूल

PostRSS बनाने वाली टीम Internet Solutions की ओर से। हर प्रोडक्ट आपका समय अपने तरीके से बचाता है।

वेबसाइटों के लिए AI लाइव चैट Talkmio आपकी वेबसाइट आपके अपने कंटेंट से, विज़िटर की भाषा में, 24/7 जवाब देती है। फ़्री प्लान · कार्ड की ज़रूरत नहीं AI असिस्टेंट Ask Mio चैट, कोड, डिज़ाइन, लेखन और रिसर्च। Mio हर काम के लिए सबसे अच्छा मॉडल चुनता है। फ़्री प्लान ब्लॉग और सोशल मीडिया के लिए AI ऑटोपायलट AI Blog Autopilot AI 2,000–3,000 शब्दों के SEO लेख लिखता है और हर लेख को 60 सोशल नेटवर्क पर शेयर करता है। पहले 3 लेख मुफ़्त वेबसाइट हेल्थ चेक साइट AI ऑडिट SEO, स्पीड, SSL, सुरक्षा और ईमेल सेटअप एक ही रिपोर्ट में, पहले क्या ठीक करना है उसी क्रम में। पहला ऑडिट मुफ़्त गहन SEO क्रॉल साइट SEO AI ऑडिट AI सर्च में दृश्यता समेत 7 क्षेत्रों में पूरा SEO क्रॉल, असर के हिसाब से क्रमबद्ध सुधारों के साथ। पहला ऑडिट मुफ़्त RSS और प्रोडक्ट फ़ीड RSS फ़ीड निर्माता किसी भी वेब पेज से RSS बनाएं, साथ ही Google और Meta के लिए प्रोडक्ट फ़ीड जो अपने आप अपडेट होते हैं। फ़्री प्लान वेब डेवलपमेंट और SEO इंटरनेट सॉल्यूशन्स वेबसाइटें, ई-शॉप और कस्टम सिस्टम — हमारी टीम डिज़ाइन करती है, बनाती है और चलाती है। 2011 से