Distribúcia súborov z Disku Google pomocou nginx

pravek

Náhodou sa stalo, že som potreboval niekde uložiť viac ako 1.5 TB dát a poskytnúť aj možnosť pre bežných používateľov stiahnuť si ich cez priamy odkaz. Keďže tradične také množstvo pamäte ide na VDS, náklady na prenájom, ktorý nie je veľmi zahrnutý v rozpočte projektu z kategórie „nič robiť“ a zo zdrojových dát som mal VPS 400GB SSD, kde aj keď chcel, nemohol som dať 1.5 TB obrázkov bez bezstratovej kompresie sa to podarí.

A potom som si spomenul, že ak z Disku Google vymažem nevyžiadanú poštu, ako sú programy, ktoré pobežia len na Windows XP, a ďalšie veci, ktoré sa presúvajú z jedného zariadenia na druhé od čias, keď internet nebol vôbec taký rýchly, nie sú neobmedzené ( napríklad tých 10-20 verzií virtuálnej skrinky pravdepodobne nebude mať inú hodnotu ako nostalgickú), potom by všetko malo veľmi dobre sedieť. Len čo sa povie, tak urobí. A tak po prelomení limitu na počet požiadaviek na api (mimochodom technická podpora bez problémov zvýšila kvótu požiadaviek na používateľa na 100 10 za 000 sekúnd), dáta rýchlo prúdili na miesto jeho ďalšieho nasadenia. .

Všetko sa zdá byť v poriadku, ale teraz to treba sprostredkovať koncovému užívateľovi. Navyše bez akýchkoľvek presmerovaní na iné zdroje, ale tak, že človek jednoducho stlačí tlačidlo „Stiahnuť“ a stane sa šťastným vlastníkom cenného súboru.

Tu, preboha, som išiel do všelijakých problémov. Najprv to bol skript v AmPHP, ale nebol som spokojný so záťažou, ktorú vytvoril (prudký skok pri štarte na 100% spotrebu jadra). Potom prišiel na rad curl wrapper pre ReactPHP, ktorý dobre zapadol do mojich želaní, čo sa týka počtu spotrebovaných cyklov CPU, ale vôbec nedával rýchlosť to, čo som chcel (ukázalo sa, že interval volania môžete jednoducho skrátiť curl_multi_select, ale potom tu máme obžerstvo podobné prvej možnosti). Dokonca som sa pokúsil napísať malú službu v Ruste a fungovalo to pomerne rýchlo (je prekvapujúce, že to fungovalo, vzhľadom na moje znalosti), ale chcel som viac a bolo nejako ťažké si to prispôsobiť. Všetky tieto riešenia navyše akosi zvláštne vyrovnávali odozvu a chcel som s najväčšou presnosťou sledovať moment, kedy sa sťahovanie súboru skončilo.

Vo všeobecnosti to chvíľu krívalo, ale fungovalo to. Až kým som jedného dňa neprišiel s nápadom, ktorý bol pozoruhodný svojou šialenosťou: nginx si teoreticky môže robiť, čo chcem, pracovať rýchlo a dokonca umožňuje všetky druhy zvráteností s konfiguráciou. Musíme vyskúšať – čo ak to funguje? A po pol dni vytrvalého hľadania sa zrodilo riešenie, ktoré stabilne fungovalo niekoľko mesiacov a spĺňalo všetky moje požiadavky.

Nastavenie NGINX

# Первым делом создадим в конфигах нашего сайта отдельную локацию.
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;
}

Pod spojlerom vidno krátku verziu bez komentárov

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;
}

Píšeme scenár, aby sme všetko toto šťastie zvládli

Príklad bude v PHP a zámerne napísaný s minimom súpravy. Myslím si, že každý, kto má skúsenosti s akýmkoľvek iným jazykom, bude schopný integrovať túto časť pomocou môjho príkladu.

<?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));

Výsledky

Vo všeobecnosti táto metóda uľahčuje organizáciu distribúcie súborov používateľom z akéhokoľvek cloudového úložiska. Áno, dokonca aj z telegramu alebo VK (za predpokladu, že veľkosť súboru nepresiahne povolenú veľkosť tohto úložiska). Mal som podobný nápad ako toto, ale bohužiaľ narážam na súbory do 2GB a zatiaľ som nenašiel metódu alebo modul na lepenie odpovedí z upstreamu a písanie nejakých obalov pre tento projekt je neprimerane prácne.

Ďakujem za tvoju pozornosť. Dúfam, že môj príbeh bol pre vás aspoň trochu zaujímavý alebo užitočný.

Zdroj: hab.com

Pridať komentár