Fájlok terjesztése a Google Drive-ról az nginx használatával

őstörténet

Történt ugyanis, hogy 1.5 TB-nál több adatot kellett tárolnom valahol, és lehetőséget kell biztosítani a hétköznapi felhasználók számára, hogy közvetlen linken keresztül letölthessék. Mivel hagyományosan ekkora memóriamennyiség megy a VDS-hez, a bérleti díj nem nagyon szerepel a projekt költségvetésében a „nincs tennivaló” kategóriából, illetve a forrásadatokból volt egy VPS 400GB SSD-m, ahol még ha szerettem volna, nem tudtam veszteségmentes tömörítés nélkül feltenni 1.5 TB-os képet, ez sikerülni fog.

És akkor eszembe jutott, hogy ha törlöm a szemetet a Google Drive-ról, mint például a csak Windows XP-n futó programokat, és más dolgokat, amelyek azóta mozognak egyik eszközről a másikra, amikor az internet egyáltalán nem volt olyan gyors, nem korlátlan ( például a virtuális doboznak az a 10-20 verziója nem valószínű, hogy a nosztalgián kívül más értéket képviselt volna), akkor mindennek nagyon jól kell illeszkednie. Alig mondják, mint kész. És így, áttörve az API-hoz intézett kérések számának korlátját (mellesleg a technikai támogatás minden probléma nélkül 100 másodperc alatt 10 000-re emelte a felhasználónkénti kérések kvótáját), az adatok gyorsan eljutottak a további telepítés helyére. .

Úgy tűnik, minden rendben van, de most már el kell juttatni a végfelhasználóhoz. Sőt, mindenféle átirányítás nélkül más erőforrásokhoz, hanem úgy, hogy az ember egyszerűen megnyomja a „Letöltés” ​​gombot, és a kincses fájl boldog tulajdonosa lesz.

Itt, Istenemre, mindenféle bajba keveredtem. Eleinte egy AmPHP-s szkript volt, de nem voltam elégedett az általa létrehozott terheléssel (éles ugrás az elején 100%-os magfogyasztásra). Aztán bejött a ReactPHP curl wrapperje, ami az elfogyasztott CPU ciklusok számát tekintve teljesen megfelelt a vágyaimnak, de egyáltalán nem azt a sebességet adta, amit szerettem volna (kiderült, hogy egyszerűen csökkentheti a hívási intervallumot curl_multi_select, de akkor ugyanaz a falánk, mint az első opciónál ). Megpróbáltam még Rustban is írni egy kis szolgáltatást, és elég gyorsan működött (meglepő, hogy a tudásom alapján működött), de többet akartam, és valahogy nehéz volt testreszabni. Ráadásul mindezek a megoldások valahogy furcsán pufferelték a választ, és szerettem volna nyomon követni azt a pillanatot, amikor a fájlletöltés a legnagyobb pontossággal véget ért.

Általában egy ideig ferde volt, de működött. Egészen addig, amíg egy nap eszembe jutott egy ötlet, ami a maga őrültségében figyelemre méltó volt: az nginx elméletben azt csinál, amit akarok, gyorsan dolgozik, és még mindenféle perverziót is megenged a konfigurációval. Meg kell próbálnunk – mi van, ha sikerül? Fél nap kitartó keresgélés után pedig megszületett egy több hónapja stabilan működő, minden igényemnek megfelelő megoldás.

Az NGINX beállítása

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

A spoiler alatt egy rövid, kommentár nélküli változat látható

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

Írunk egy forgatókönyvet, hogy kezeljük ezt a boldogságot

A példa PHP-ben lesz, és szándékosan íródott minimális készlettel. Azt hiszem, bárki, akinek van tapasztalata más nyelvekkel, képes lesz integrálni ezt a részt az én példám segítségével.

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

Eredményei

Általánosságban elmondható, hogy ez a módszer meglehetősen egyszerűvé teszi a fájlok elosztását a felhasználók számára bármely felhőalapú tárolóról. Igen, még táviratból vagy VK-ból is (feltéve, hogy a fájl mérete nem haladja meg a tárhely megengedett méretét). Volt egy hasonló ötletem ezt, de sajnos 2 GB-os fájlokkal találkozom, és még nem találtam módszert vagy modult az upstream válaszok ragasztására, és ehhez a projekthez valamiféle wrappereket írni indokolatlanul munkaigényes.

Köszönöm a figyelmet. Remélem, a történetem legalább egy kicsit érdekes vagy hasznos volt számodra.

Forrás: will.com

Hozzászólás