基于单URL实现Cantaloupe图像服务器与Amazon S3的无重定向图像映射
Great question! The core problem here is that your current approach buffers the entire image on your API server before sending it to the client, adding unnecessary latency. To fix this while keeping users on your single API URL (no redirects), you have two high-performance options—one at the Apache web server level (most efficient) and one using PHP streaming.
Option 1: Apache mod_proxy + Rewrite Rules (Best for Simple Routing)
This approach lets Apache handle the proxying directly, skipping PHP entirely. It forwards client requests straight to either S3 or your Cantaloupe server without storing the image on your API server.
Step 1: Enable Required Apache Modules
First, ensure these modules are enabled in your Apache config:
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule rewrite_module modules/mod_rewrite.so
Step 2: Add Rewrite Rules to Your VirtualHost
In the VirtualHost block for api.blavatnikarchive.org, add these rules to route requests correctly:
RewriteEngine On # Route pre-generated 512x512 thumbnails to S3 RewriteRule ^/baf__([a-f0-9]+)/full/!512,512/0/default\.jpg$ https://baf-iiif-assets.s3.amazonaws.com/$1 [P,L] # Route all other requests to Cantaloupe RewriteRule ^/(baf__[a-f0-9]+/.*)$ https://iiif.blavatnikarchive.org/iiif/2/$1 [P,L]
- The
[P]flag tells Apache to proxy the request directly to the target URL. - The
[L]flag stops processing further rules once a match is found. - This setup keeps the user on your API URL while letting the origin server (S3/Cantaloupe) serve the image directly.
Option 2: PHP Streamed Proxy (For Complex Logic)
If you need to add custom logic (like authentication, checking if a thumbnail exists in S3, or dynamic routing), use PHP to stream the image content instead of buffering it.
Example Code
<?php $requestUri = $_SERVER['REQUEST_URI']; $targetUrl = ''; // Determine target based on request parameters if (strpos($requestUri, '!512,512') !== false) { // Extract image ID (strip the baf__ prefix) preg_match('/baf__([a-f0-9]+)/', $requestUri, $matches); $imageId = $matches[1]; $targetUrl = "https://baf-iiif-assets.s3.amazonaws.com/$imageId"; } else { // Route to Cantaloupe $targetUrl = "https://iiif.blavatnikarchive.org/iiif/2" . $requestUri; } // Fetch and pass through origin headers $ch = curl_init($targetUrl); curl_setopt($ch, CURLOPT_NOBODY, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_exec($ch); $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); curl_close($ch); // Send headers to client header("Content-Type: $contentType"); header('Cache-Control: public, max-age=31536000'); // Optional: set long caching // Stream content directly to client (no buffering) $fp = fopen($targetUrl, 'rb'); fpassthru($fp); fclose($fp); exit; ?>
- This code streams the image as it receives it from the origin, so your API server never stores the full image in memory.
- Latency is drastically reduced compared to
file_get_contentssince data starts flowing to the client immediately.
Key Notes
- Apache mod_proxy is faster: It avoids PHP overhead entirely, making it the best choice if your routing logic can be handled with rewrite rules.
- Caching: Add appropriate
Cache-Controlheaders to both solutions to reduce repeat requests to your origin servers. - S3 Permissions: Ensure your S3 bucket allows access from your Apache server (or configure S3 to serve public content if appropriate).
内容的提问来源于stack exchange,提问作者Muhammad Bilawal

