Nginx yordamida Google Drive-dan fayllarni tarqatish

Sana oldin

Shunday qilib, men 1.5 TB dan ortiq ma'lumotni biron bir joyda saqlashim kerak edi, shuningdek, oddiy foydalanuvchilarga uni to'g'ridan-to'g'ri havola orqali yuklab olish imkoniyatini taqdim etishim kerak edi. An'anaviy ravishda bunday hajmdagi xotira VDS-ga o'tganligi sababli, ijara narxi loyiha byudjetiga "hech narsa qilish kerak emas" toifasidan unchalik ko'p kiritilmagan va manba ma'lumotlariga ko'ra menda VPS 400 GB SSD bor edi, hatto men bo'lsam ham. Xohlasam, 1.5 TB hajmdagi tasvirlarni yo'qotishsiz siqishsiz joylashtira olmadim, bu muvaffaqiyatga erishadi.

Va keyin esladim, agar men Google Drive-dan keraksiz narsalarni o'chirib tashlasam, masalan, faqat Windows XP da ishlaydigan dasturlar va Internet unchalik tez bo'lmagan kunlardan beri bir qurilmadan ikkinchisiga o'tadigan boshqa narsalar cheksiz emas ( masalan, virtual qutining o'sha 10-20 versiyasi nostaljikdan boshqa qiymatga ega bo'lishi ehtimoldan yiroq edi), keyin hamma narsa juda yaxshi mos kelishi kerak. Aytilgan gap otilgan o'q. Shunday qilib, api-ga so'rovlar soni chegarasidan o'tib (aytmoqchi, texnik yordam muammosiz har bir foydalanuvchi uchun so'rovlar kvotasi 100 soniyada 10 000 tagacha ko'tarildi), ma'lumotlar tezda uni keyingi joylashtirish joyiga oqib chiqdi. .

Hamma narsa yaxshi ko'rinadi, lekin endi uni oxirgi foydalanuvchiga etkazish kerak. Bundan tashqari, boshqa manbalarga yo'naltirilmasdan, lekin odam shunchaki "Yuklab olish" tugmasini bosadi va qimmatbaho faylning baxtli egasiga aylanadi.

Mana, xudo haqi, men har xil balolarga kirdim. Avvaliga bu AmPHP-dagi skript edi, lekin men u yaratgan yukdan qoniqmadim (boshida 100% asosiy iste'molga keskin sakrash). Keyin ReactPHP uchun jingalak o'rami ishga tushdi, bu iste'mol qilingan CPU tsikllari soni bo'yicha mening xohishlarimga to'liq mos keldi, lekin men xohlagan tezlikni bermadi (siz shunchaki qo'ng'iroqlar oralig'ini qisqartirishingiz mumkinligi ma'lum bo'ldi. curl_multi_select, lekin keyin bizda birinchi variantga o'xshash ochko'zlik bor ). Men hatto Rust-da kichik xizmat yozishga harakat qildim va u juda tez ishladi (bilimdan kelib chiqib, u ishlaganligi ajablanarli), lekin men ko'proq narsani xohlardim va uni sozlash qandaydir qiyin edi. Bundan tashqari, ushbu echimlarning barchasi qandaydir tarzda javobni g'alati tarzda buferladi va men faylni yuklab olish eng yuqori aniqlik bilan tugagan vaqtni kuzatmoqchi edim.

Umuman olganda, u bir muddat egri edi, lekin u ishladi. Bir kungacha men aqldan ozganligi bilan ajoyib g'oyani o'ylab topdim: nginx, nazariy jihatdan, men xohlagan narsani qila oladi, tez ishlaydi va hatto konfiguratsiya bilan har xil buzuqliklarga yo'l qo'yadi. Biz sinab ko'rishimiz kerak - agar u ishlasa nima bo'ladi? Va yarim kunlik doimiy izlanishlardan so'ng, bir necha oy davomida barqaror ishlaydigan va mening barcha talablarimga javob beradigan yechim tug'ildi.

NGINX sozlanmoqda

# Первым делом создадим в конфигах нашего сайта отдельную локацию.
location ~* ^/google_drive/(.+)$ {

    # И закроем её от посторонних глаз (рук, ног и прочих частей тела).
    internal;

    # Ограничим пользователям скорость до разумных пределов (я за равноправие).
    limit_rate 1m;

    # А чтоб nginx мог найти сервера google drive укажем ему адрес резолвера.
    resolver 8.8.8.8;

    # Cоберем путь к нашему файлу (мы потом передадим его заголовками).
    set $download_url https://www.googleapis.com/drive/v3/files/$upstream_http_file_id?alt=media;

    # А так же Content-Disposition заголовок, имя файла мы передадим опять же в заголовках.
    set $content_disposition 'attachment; filename="$upstream_http_filename"';

    # Запретим буфферизировать ответ на диск.
    proxy_max_temp_file_size 0;

    # И, что немаловажно, передадим заголовок с токеном (не знаю почему, но в заголовках из $http_upstream токен передать не получилось. Вернее передать получилось, но скорей всего его где-то нужно экранировать, потому что гугл отдает ошибку авторизации).
    proxy_set_header Authorization 'Bearer $1';

    # И все, осталось отправить запрос гуглу по ранее собранному нами адресу.
    proxy_pass $download_url;

    # А чтоб у пользователя при скачивании отобразилось правильное имя файла мы добавим соответствующий заголовок.
    add_header Content-Disposition $content_disposition;

    # Опционально можно поубирать ненужные нам заголовки от гугла.
    proxy_hide_header Content-Disposition;
    proxy_hide_header Alt-Svc;
    proxy_hide_header Expires;
    proxy_hide_header Cache-Control;
    proxy_hide_header Vary;
    proxy_hide_header X-Goog-Hash;
    proxy_hide_header X-GUploader-UploadID;
}

Sharhsiz qisqa versiyani spoyler ostida ko'rish mumkin

location ~* ^/google_drive/(.+)$ {
    internal;
    limit_rate 1m;
    resolver 8.8.8.8;
    
    set $download_url https://www.googleapis.com/drive/v3/files/$upstream_http_file_id?alt=media;
    set $content_disposition 'attachment; filename="$upstream_http_filename"';
    
    proxy_max_temp_file_size 0;
    proxy_set_header Authorization 'Bearer $1';
    proxy_pass $download_url;
    
    add_header Content-Disposition $content_disposition;
    
    proxy_hide_header Content-Disposition;
    proxy_hide_header Alt-Svc;
    proxy_hide_header Expires;
    proxy_hide_header Cache-Control;
    proxy_hide_header Vary;
    proxy_hide_header X-Goog-Hash;
    proxy_hide_header X-GUploader-UploadID;
}

Biz bu baxtni boshqarish uchun ssenariy yozyapmiz

Misol PHP da bo'ladi va minimal to'plam bilan ataylab yozilgan. O'ylaymanki, har qanday boshqa tilda tajribaga ega bo'lgan har bir kishi mening misolimdan foydalanib, ushbu bo'limni birlashtira oladi.

<?php

# Токен для Google Drive Api.
define('TOKEN', '*****');

# ID файла на гугл диске
$fileId = 'abcdefghijklmnopqrstuvwxyz1234567890';

# Опционально, но так как мы не передаем никаких данных - почему бы и нет?
http_response_code(204);

# Зададим заголовок c ID файла (в конфигах nginx мы потом получим его как $upstream_http_file_id).
header('File-Id: ' . $fileId);
# И заголовок с именем файла (соответственно $upstream_http_filename).
header('Filename: ' . 'test.zip');
# Внутренний редирект. А еще в адресе мы передадим токен, тот самый, что мы получаем из $1 в nginx.
header('X-Accel-Redirect: ' . rawurlencode('/google_drive/' . TOKEN));

natijalar

Umuman olganda, bu usul har qanday bulutli xotiradan foydalanuvchilarga fayllarni tarqatishni tashkil qilishni ancha osonlashtiradi. Ha, hatto telegramdan yoki VK dan, (fayl hajmi ushbu saqlashning ruxsat etilgan hajmidan oshmasligi sharti bilan). Menda shunga o'xshash fikr bor edi bu, lekin afsuski, men 2 Gb gacha bo'lgan fayllarga duch kelaman va men hali yuqori oqimdan javoblarni yopishtirish uchun usul yoki modul topa olmadim va bu loyiha uchun qandaydir o'ramlarni yozish asossiz mehnat talab qiladi.

E'tiboringiz uchun rahmat. Umid qilamanki, mening hikoyam siz uchun hech bo'lmaganda biroz qiziqarli yoki foydali bo'ldi.

Manba: www.habr.com

a Izoh qo'shish