前段时间用 SM.MS 图床的 API 做了一个评论上传图片的小功能。然而有一天 SM.MS 的主人这样说:
喵喵喵?现在我仍在用的这个接口怎么就没有遇到跨域问题,算是默许吗?后来他又说以后还有通过 oauth2 限制上传的打算。倒是本身也是免费的东西,人家爱怎么做怎么做,我们自然没资格评论;只不过看情况,使用这个接口多半也不是长久之计。
之后大致比较下来,支持 API 上传的图床,国内基本是没有合适的了,国外的话稳定性最高的大概就是 Flickr 和 Imgur;因为 Flickr 有容量限制所以不予考虑。剩下的 Imgur 试了一下现在居然还能裸连!但是呢毕竟是外国的东西,国内访问速度受限不说,指不定哪天也被墙挡了;解决方法倒很简单,Nginx 反代一下就可以了。下面参照 Imgur 的文档写了一个简单的 Ajax 上传示例。
<form id="imgur"> <input type="file" class="imgur" accept="image/*" data-max-size="5000" /> </form> <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script>
然后到这里申请一个 Application,在下面填入你的 Client ID:
$("document").ready(function () { $('input[type=file]').on("change", function () { var $files = $(this).get(0).files; var formData = new FormData(); formData.append("image", $files[0]); if ($files.length) { // Reject big files if ($files[0].size > $(this).data("max-size") * 1024) { console.log("Please select a smaller file"); return false; } // Replace {{Your Client ID }} with your own API key var apiUrl = 'https://api.imgur.com/3/image'; var apiKey = '{{Your Client ID }}'; var settings = { "async": true, "crossDomain": true, "url": apiUrl, "method": "POST", "datatype": "json", "headers": { "Authorization": "Client-ID " + apiKey }, "processData": false, "contentType": false, "data": formData, beforeSend: function () { console.log("上传中..."); }, success: function (res) { $('body').append('<img src="' + res.data.link + '" />'); }, error: function () { alert("上传失败"); } } $.ajax(settings).done(function (res) { console.log("Done"); }); } }); });
前端上传就完成了,下面是 Nginx 反代:
server { ...... # 图片文件镜像 location ^~ /imgur/ { proxy_pass https://i.imgur.com/; proxy_buffering off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 取消下面的注释可以启用 Nginx 缓存 #proxy_cache STATIC; #proxy_cache_key $uri; #proxy_cache_valid 200 30d; #proxy_cache_use_stale error timeout invalid_header updating # http_500 http_502 http_503 http_504; #add_header X-Nginx-Cache $upstream_cache_status; } # API 镜像 location ^~ /imgur-api/ { # 跨域,注意不要和前面的跨域策略冲突/重复 add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; proxy_pass https://api.imgur.com/; proxy_buffering off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } ...... }
之后就可以通过 https://your.domain/imgur/koe07fX.jpg
访问原 URL 为 https://i.imgur.com/koe07fX.jpg
的图片了;最后把 Ajax 上传脚本里的 apiUrl
换成 https://your.domain/imgur-api/3/image
就可以通过镜像上传了。
暂时不清楚 Imgur 是否对单个 IP 有上传和下载限制,所以为了避免自己的镜像被滥用,建议限制一下 Referer
:
map $http_referer $allow_referer { default 0; "" 1; "~2heng.xin" 1; "~\.google\." 1; "~\.baidu\." 1; } map $allow_referer $disallow_referer { 0 1; 1 ""; } server { ...... location balabala { ...... if ( $http_referer = "") { return 403; } if ( $disallow_referer ) { return 403; } ...... } ...... }
成品示例:https://api.mashiro.top/imgur.html;不过博客上的上传接口暂时懒得修改了,等 SM.MS 哪天彻底完蛋了再换吧。
Q.E.D.