#Next.js#Security#Tailwind CSS#AI Side Hustle#UI/UX
【第19回】本文内の画像URLを自動サムネイル展開!安全なプロキシ経由とモーダルプレビューの実装

【第19回】本文内の画像URLを自動サムネイル展開!安全なプロキシ経由とモーダルプレビューの実装

📅

💡 この記事のまとめ

ブログやSNS、チャットツール開発で必須の「画像URL自動サムネイル化」。セキュリティを守るプロキシ構築と、UXを爆上げするモーダル表示の実装方法を解説します。AI副業での応用方法も公開!

本文内の画像URLを自動サムネイル展開!安全なプロキシ経由とモーダルプレビューの実装

こんにちは!AI技術を駆使してWebサービスを開発し、マネタイズする「AI副業」の世界へようこそ。

近年、チャットツールやブログ、SNSなどのWebサービスにおいて、**「ユーザーが投稿した画像URLを自動で検知し、サムネイルとして表示する機能」**はもはや標準装備となっています。リンクをクリックせずとも視覚的に情報が伝わるため、ユーザーの滞在時間を延ばし、サイトの価値(ひいては広告収入や成約率)を大きく高めることができます。

しかし、この機能を何も考えずに実装すると、**「セキュリティの脆弱性(SSRFなど)」や「外部画像への直接アクセスによるロード遅延、リンク切れ」**といった深刻な問題に直面します。

そこで今回は、**「安全なプロキシサーバーを経由した画像取得」と、「クリックで美しく拡大するモーダルプレビュー」**を組み合わせた、安全でUX(顧客体験)の高いサムネイル自動展開システムの実装方法を徹底解説します!

この技術をマスターすれば、クライアントワークでの単価アップや、自身で運営するアフィリエイトメディア、SNS風サービスの差別化に直結します。


1. 今回実装するコンセプトと全体像

まずは、今回構築するシステムの全体像を理解しましょう。

① 本文内の画像URL自動抽出

ユーザーが入力したテキスト(Markdownやプレーンテキスト)から、正規表現を用いて「画像ファイルの拡張子(.jpg, .png, .gif, .webpなど)を持つURL」を自動検知します。

② 安全な画像プロキシ(Proxy)の経由

外部の画像URLを直接 <img> タグに設定すると、以下のリスクが生じます:

  • ユーザーのIPアドレスが外部サーバーに漏洩する(プライバシー問題)
  • HTTPSのサイト内にHTTPの画像が混ざり、セキュリティ警告が出る(Mixed Content)
  • 相手サーバーからアクセス拒否(CORSエラー)される

これらを防ぐため、自前のAPI(プロキシ)を1つ挟み、サーバー側で画像を一度取得・キャッシュしてから、安全な形でクライアントに配信します。

③ モーダルプレビューによる快適なUX

展開されたサムネイルをクリックすると、画面全体が暗くなり、滑らかなアニメーションと共に大画面で画像が表示される「モーダルプレビュー」を実装します。これにより、サイトからの離脱を防ぎつつ、詳細な情報をユーザーに提供できます。


2. 実装コード解説(Next.js / React & Tailwind CSS)

今回は、現在モダンなWeb開発で主流となっている Next.js (App Router) と Tailwind CSS を使った実装例をご紹介します。非常にシンプルかつセキュアに構築できます。

ステップ1:セキュアな画像プロキシAPIの作成

まずはサーバーサイドで外部画像を安全に取得するAPIルーティングを作成します。

ファイルパス: app/api/proxy/route.js

javascript import { NextResponse } from 'next/server';

export async function GET(request) { const { searchParams } = new URL(request.url); const imageUrl = searchParams.get('url');

if (!imageUrl) { return new NextResponse('Missing URL parameter', { status: 400 }); }

try { // SSRF対策:ローカルホスト等のIPへのアクセスを制限する簡易チェック if (imageUrl.startsWith('http://localhost') || imageUrl.startsWith('http://127.0.0.1')) { return new NextResponse('Blocked suspicious URL', { status: 403 }); }

const response = await fetch(imageUrl, {
  headers: {
    'User-Agent': 'SafeImageProxy/1.0',
  },
});

if (!response.ok) throw new Error('Failed to fetch image');

const contentType = response.headers.get('content-type');
// 画像フォーマットのみを許可
if (!contentType || !contentType.startsWith('image/')) {
  return new NextResponse('Invalid content type', { status: 400 });
}

const buffer = await response.arrayBuffer();

return new NextResponse(buffer, {
  headers: {
    'Content-Type': contentType,
    'Cache-Control': 'public, max-age=86400', // 1日キャッシュ
  },
});

} catch (error) { console.error('Proxy Error:', error); return new NextResponse('Error fetching image', { status: 500 }); } }

ステップ2:テキスト解析 & モーダル付きコンポーネントの実装

次に、テキストから画像URLを検出し、プロキシ経由のサムネイルを表示、クリックでモーダルを開くUIパーツを作成します。

ファイルパス: components/RichTextRenderer.jsx

jsx 'use client';

import { useState } from 'react';

export default function RichTextRenderer({ text }) { const [selectedImage, setSelectedImage] = useState(null);

// 画像URL(http〜webp等)を検出する正規表現 const imageRegex = /(https?://[^\s]+.(?:png|jpg|jpeg|gif|webp))/gi;

// テキストを改行などで分割し、URLがあればサムネイルを展開する処理 const renderContent = () => { const parts = text.split(imageRegex); return parts.map((part, index) => { if (part.match(imageRegex)) { // 安全なプロキシ用のURLを生成 const proxyUrl = /api/proxy?url=${encodeURIComponent(part)}; return ( <div key={index} className="my-4"> <img src={proxyUrl} alt="Thumbnail Preview" className="max-w-xs h-auto rounded-lg shadow-md cursor-pointer hover:opacity-90 transition duration-200" onClick={() => setSelectedImage(proxyUrl)} /> <span className="text-xs text-gray-500 block mt-1 break-all">{part}</span> </div> ); } return <span key={index} className="whitespace-pre-wrap">{part}</span>; }); };

return ( <div className="p-4 border rounded-xl bg-white shadow-sm"> <div className="text-gray-800 leading-relaxed">{renderContent()}</div>

  {/* モーダルプレビュー画面 */}
  {selectedImage && (
    <div
      className="fixed inset-0 bg-black/80 flex items-center justify-center z-50 animate-fade-in"
      onClick={() => setSelectedImage(null)}
    >
      <div className="relative max-w-4xl max-h-[90vh] p-2">
        <button
          className="absolute top-4 right-4 text-white bg-black/50 hover:bg-black/80 w-10 h-10 rounded-full flex items-center justify-center text-xl font-bold transition"
          onClick={() => setSelectedImage(null)}
        >
          ✕
        </button>
        <img
          src={selectedImage}
          alt="Full Preview"
          className="max-w-full max-h-[85vh] object-contain rounded"
        />
      </div>
    </div>
  )}
</div>

); }


3. この技術を活用した「AI副業」マネタイズガイド

この安全な画像プレビュー機能をどのように収益化に結びつけるのか、具体的なステップを紹介します。

ステップ1:特化型「まとめ・キュレーションサイト」の構築

AI(ChatGPTやClaude)を使って、海外の有益なテック情報やデザインのトレンド情報を自動翻訳・収集します。 その際、本文中のデモ画像を自動サムネイル表示させ、ユーザーがクリックしてモーダルで確認できる高機能な「まとめサイト」を構築します。視覚的な美しさと安全性が担保されたサイトは、滞在時間が非常に長くなり、Google AdSenseやAmazonアソシエイトなどの広告収入を最大化できます。

ステップ2:クライアントワーク(Web制作)の単価アップ

企業のブログシステムや、コミュニティサイトを制作する際、ただテキストを表示するだけでなく、

「セキュリティ対策を施した、画像リンクの自動プレビュー機能も標準で実装できますよ」

と提案します。これにより、競合エンジニアと差別化でき、開発単価を数万円〜数十万円上乗せして受注することが可能になります。

ステップ3:有料コミュニティ・SaaSの開発

Notionのように「URLを入力したらリッチなブログカードや画像プレビューが生成される」機能を組み込んだ、独自のクローズドな情報共有ツールや、特定のニッチ市場に向けた有料フォーラムを運営・販売(SaaS化)します。


4. メリットとデメリット

メリット

  • 圧倒的なUX向上:ユーザーがいちいち別タブで画像を開くストレスがゼロになります。
  • 高いセキュリティ:ユーザーのIPアドレスを保護し、SSRF(Server-Side Request Forgery)などの攻撃からサーバーとユーザーを守ります。
  • CORS問題の回避:サーバーが代わりに取得するため、ブラウザ側での読み込みエラーが発生しません。

デメリット

  • サーバー負荷の増加:大量の画像アクセスがプロキシに集中すると、自社サーバーの転送量が増大します。これには「CDN(Cloudflare等)による画像キャッシュ」を併用することで解決できます。
  • 悪意ある画像の取得リスク:ウイルスが仕込まれたファイルをプロキシが読み込むリスク。これは、MIMEタイプ(Content-Type)チェックを厳格化することで防ぎます。

5. まとめ

「本文内の画像URL自動サムネイル展開」は、一見シンプルですが、「セキュリティ(プロキシ)」と「使いやすさ(モーダル)」を高いレベルで両立させて初めて完成するプロの技術です。

AIを駆使してテキストコンテンツを大量生成・配信できる時代だからこそ、こうした「ガワ(システムやUI/UX)」のクオリティに投資することで、競合に大きな差をつけることができます。

ぜひ今回のコードを参考に、ご自身のWebサービスに実装し、より価値の高いWebサイト構築(AI副業の収益化)に役立ててください!

次回は、さらに一歩進んで「画像だけでなく、YouTubeやTwitter(X)の埋め込みを自動で安全に行う方法」についてお届けします。お楽しみに!