Failide levitamine Google Drive'ist nginxi abil

eelajalugu

Juhtus nii, et mul oli vaja kuskile salvestada rohkem kui 1.5 TB andmeid ja pakkuda ka tavakasutajatele võimalus need otselingi kaudu alla laadida. Kuna traditsiooniliselt lähevad sellised mälumahud VDS-ile, siis rendikulu, mis ei sisaldu eriti projekti eelarves kategooriast “mitte teha” ja lähteandmetest oli mul olemas VPS 400GB SSD, kus isegi kui ma tahtsin, ma ei saanud ilma kadudeta pakkimiseta 1.5TB pilte panna, see õnnestub.

Ja siis meenus mulle, et kui ma kustutan Google Drive'ist rämpsu, nagu programmid, mis töötavad ainult Windows XP-s, ja muud asjad, mis on liikunud ühest seadmest teise alates nendest aegadest, mil Internet polnud üldse nii kiire, mitte piiramatu ( näiteks need 10-20 virtuaalkasti versiooni ei omanud tõenäoliselt muud väärtust kui nostalgiline), siis peaks kõik väga hästi sobima. Pole varem öeldud kui tehtud. Ja nii, ületades API-le esitatavate päringute arvu piirangu (muide, tehniline tugi suurendas probleemideta taotluste kvoodi kasutaja kohta 100 sekundiga 10 000-ni), liikusid andmed kiiresti selle edasise juurutamise kohta. .

Tundub, et kõik on hästi, kuid nüüd tuleb see lõppkasutajale edastada. Veelgi enam, ilma ümbersuunamisteta teistele ressurssidele, vaid nii, et inimene vajutab lihtsalt nuppu „Laadi alla” ja saab väärtusliku faili õnnelikuks omanikuks.

Siin, jumala eest, sattusin ma igasugustesse jamadesse. Alguses oli see skript AmPHP-s, kuid ma ei olnud rahul selle tekitatud koormusega (alguses järsk hüpe 100% põhitarbimisele). Siis tuli mängu Curl wrapper ReactPHP jaoks, mis kulunud protsessori tsüklite arvu poolest sobis minu soovidega, kuid ei andnud kiirust üldse seda, mida tahtsin (selgus, et helistamise intervalli saab lihtsalt vähendada curl_multi_select, kuid siis on meil esimese valikuga sarnane rämps). Üritasin isegi Rustis väikest teenust kirjutada ja see töötas üsna kiiresti (minu teadmisi arvestades on üllatav, et see töötas), kuid tahtsin rohkem ja seda oli kuidagi raske kohandada. Lisaks puhverdasid kõik need lahendused kuidagi imelikult vastust ja tahtsin jälgida hetke, millal faili allalaadimine kõige suurema täpsusega lõppes.

Üldiselt oli korraks viltu, aga töötas. Kuni ühel päeval tulin ideele, mis oli tähelepanuväärne oma hullumeelsuses: nginx saab teoreetiliselt teha seda, mida tahan, töötada kiiresti ja isegi lubada kõikvõimalikke konfiguratsiooniga perversioone. Peame proovima – mis siis, kui see toimib? Ja peale poolt päeva järjekindlat otsimist sündiski lahendus, mis oli stabiilselt töötanud mitu kuud ja vastas kõikidele minu nõuetele.

NGINX-i seadistamine

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

Lühiversioon ilma kommentaarideta on näha spoileri all

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

Kirjutame stsenaariumi, et kogu seda õnne juhtida

Näide on PHP-s ja teadlikult kirjutatud minimaalse komplektiga. Arvan, et igaüks, kellel on mõne muu keelega kogemusi, suudab selle jaotise minu näitel integreerida.

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

Tulemused

Üldiselt on selle meetodi abil üsna lihtne korraldada failide jagamist kasutajatele mis tahes pilvesalvestusest. Jah, isegi telegrammist või VK-st (eeldusel, et faili suurus ei ületa selle salvestusruumi lubatud suurust). Mul oli sarnane idee see, kuid kahjuks puutun kokku kuni 2GB failidega ja ma pole veel leidnud meetodit ega moodulit vastuste liimimiseks ülesvoolust ning mingisuguste ümbriste kirjutamine selle projekti jaoks on ebamõistlikult töömahukas.

Tänan tähelepanu eest. Loodan, et minu lugu oli teile vähemalt veidi huvitav või kasulik.

Allikas: www.habr.com

Lisa kommentaar