使用 Cloudflare Workers 搭建一个获取必应每日美图的API
以前在自己的服务器上用PHP代码做了一个接口,服务器过期后就失效了。最近接触到 Cloudflare Workers,因为不用部署在服务器上,而且支持 HTTPS,每天有免费的10万次请求数,于是又在 Cloudflare Workers 上做了一个。
以下步骤及代码均来源于阿里云·通义大模型:
要使用 Cloudflare Workers 搭建一个获取必应每日美图的 API,你可以按照以下步骤进行:
注册并登录 Cloudflare 账户:
- 如果还没有 Cloudflare 账户,首先需要注册一个。
创建一个新的 Worker:
- 登录 Cloudflare 控制台后,进入 Workers 部分,点击“Create a service”按钮。
- 输入你的 Worker 名称,然后点击“Create service”。
编写 Worker 代码:
- 在 Worker 编辑器中,你可以编写 JavaScript 代码来实现获取必应每日美图的功能。
- 必应每日美图的 URL 是
https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=en-US
,你可以通过这个 URL 获取图片信息。
示例代码:
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) })
async function handleRequest(request) { const bingDailyImageURL = 'https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN';
const response = await fetch(bingDailyImageURL); const data = await response.json(); const baseUrl = 'https://s.cn.bing.net'; const imageUrl = `${baseUrl}${data.images[0].url}`; return Response.redirect(imageUrl, 302); }
|
部署 Worker:
- 编写完代码后,点击“Save and Deploy”按钮将你的 Worker 部署到 Cloudflare 的边缘网络。
测试 API:
- 部署完成后,你可以通过浏览器或者工具(如 Postman)访问你的 Worker URL 来测试 API 是否正常工作。
设置自定义域名(可选):
- 如果你有自己的域名,可以在 Cloudflare 中添加域名,并将 Worker 关联到这个域名上,以便通过自定义域名访问你的 API。
通过以上步骤,你就可以成功搭建一个使用 Cloudflare Workers 获取必应每日美图的 API。
上面的代码我替换了国内访问速度较快的必应地址。
然后又想增加通过参数来获取不同分辨率的图片,于是修改了一下代码:
初步优化的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) }) async function handleRequest(request) { const supportedResolutions = { '1080': '1920', '720': '1280', '768': '1024', '600': '800', '480': '640' }; const url = new URL(request.url); const h = url.searchParams.get('h'); const defaultResolution = '1080'; const height = h && supportedResolutions[h] ? h : defaultResolution; const width = supportedResolutions[height]; const bingDailyImageDataURL = 'https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN'; const response = await fetch(bingDailyImageDataURL); const data = await response.json(); const baseUrl = 'https://s.cn.bing.net/'; let imageUrl = `${baseUrl}${data.images[0].url}`; const defaultResolutionStr = '1920x1080'; const requestedResolutionStr = `${width}x${height}`; if (imageUrl.includes(defaultResolutionStr)) { imageUrl = imageUrl.replace(defaultResolutionStr, requestedResolutionStr); } else { const imageBase = imageUrl.split('_').slice(0, -1).join('_'); imageUrl = `${imageBase}_${requestedResolutionStr}.jpg`; } return Response.redirect(imageUrl, 302); }
|
这个代码首先定义了一个对象,用于存储支持的分辨率映射。然后,它从请求的查询参数中获取’h’参数,并检查它是否存在于支持的分辨率映射中。如果不存在,则使用默认的分辨率。
接着优化:每天第一次访问时,会请求必应的API,获取今日美图的信息,然后根据请求的分辨率参数,构建完整的图片URL,然后把构建好的URL作为重定向目标返回给客户端,同时缓存到KV中,下次再访问时,直接从KV中读取图片URL,减少对必应的请求次数。但是这样一来,跟必应的API更新时间有一点差距,但无伤大雅。
优化完成的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
| addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)); });
const kvNamespace = globalThis['bing.worker'];
const supportedResolutions = { '1080': '1920', '720': '1280', '768': '1024', '600': '800', '480': '640', '2160': '3840', '1920': '1080', '1280': '720' };
const specialResolutionIdentifiers = { '3840x2160': 'UHD' };
async function handleRequest(request) { try { const url = new URL(request.url); const h = url.searchParams.get('h') || '1080'; const requestedResolutionStr = `${supportedResolutions[h] || '1920'}x${h}`;
const cachedImageUrl = await kvNamespace.get(requestedResolutionStr, 'text');
if (cachedImageUrl) { return Response.redirect(cachedImageUrl, 302); }
const imageLinks = await fetchAndCacheBingDailyImage();
const imageUrl = imageLinks[requestedResolutionStr] || imageLinks['1920x1080'];
return Response.redirect(imageUrl, 302); } catch (error) { console.error('Error handling request:', error); return new Response('Internal Server Error', { status: 500 }); } }
async function fetchAndCacheBingDailyImage() { try { const bingDailyImageDataURL = 'https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN'; const response = await fetch(bingDailyImageDataURL);
if (!response.ok) { throw new Error(`Failed to fetch Bing daily image: ${response.statusText}`); }
const data = await response.json(); const baseUrl = 'https://cn.bing.com'; let originalImageUrl = `${baseUrl}${data.images[0].url}`;
const cleanedImageUrl = cleanImageUrl(originalImageUrl);
const imageLinks = Object.entries(supportedResolutions).reduce((acc, [height, width]) => { const resolutionStr = `${width}x${height}`; const replacement = specialResolutionIdentifiers[resolutionStr] || resolutionStr; acc[resolutionStr] = cleanedImageUrl.replace('1920x1080', replacement); return acc; }, {});
await Promise.all( Object.keys(imageLinks).map(resolution => kvNamespace.put(resolution, imageLinks[resolution], { expirationTtl: 8 * 60 * 60 }) ) );
return imageLinks; } catch (error) { console.error('Error fetching and caching Bing daily image:', error); throw error; } }
function cleanImageUrl(url) { try { const urlObj = new URL(url); urlObj.searchParams.delete('rf'); urlObj.searchParams.delete('pid');
return urlObj.toString(); } catch (error) { console.error('Error cleaning URL:', error); throw error; } }
|
使用/?h=720
请求这个API,就可以得到一个302重定向到1280x720分辨率的图片。
效果如下:
API 已部署在 Cloudflare 上,可以通过访问这个链接来获取不同分辨率的图片。如果不附带参数或请求的参数不在支持的列表中,则返回默认的分辨率(1920x1080)。
参数 | 对应分辨率 |
---|
2160 | 3840x2160 |
1920 | 1080x1920 |
1280 | 720x1280 |
1080 | 1920x1080 |
720 | 1280x720 |
768 | 1024x768 |
600 | 800x600 |
480 | 640x480 |
PS:workers的默认域名workers.dev
在国内无法直接访问,需要设置自定义域名后才能访问。