Distribuera filer från Google Drive med nginx

förhistoria

Det råkade bara vara så att jag behövde lagra mer än 1.5 TB data någonstans, och även ge vanliga användare möjlighet att ladda ner den via en direktlänk. Eftersom traditionellt sådana mängder minne går till VDS, kostnaden för att hyra som inte ingår särskilt mycket i projektbudgeten från kategorin "ingenting att göra" och från källdata hade jag en VPS 400GB SSD, där, även om jag ville, jag kunde inte lägga 1.5 TB bilder utan förlustfri komprimering det kommer att lyckas.

Och sedan kom jag ihåg att om jag raderar skräp från Google Drive, som program som bara körs på Windows XP, och andra saker som har flyttat från en enhet till en annan sedan de dagar då Internet inte var så snabbt alls, inte obegränsat ( till exempel var de 10-20 versionerna av den virtuella lådan osannolikt att ha något annat värde än nostalgiskt), då borde allt passa väldigt bra. Inte tidigare sagt än gjort. Och så, genom att bryta igenom gränsen för antalet förfrågningar till api:n (förresten, teknisk support ökade utan problem kvoten av förfrågningar per användare till 100 10 på 000 sekunder), flödade data snabbt till platsen för dess vidare distribution .

Allt verkar vara bra, men nu måste det förmedlas till slutanvändaren. Dessutom utan några omdirigeringar till andra resurser, men så att en person helt enkelt trycker på knappen "Ladda ner" och blir den lyckliga ägaren av den värdefulla filen.

Här, gudom, jag hamnade i alla möjliga problem. Först var det ett skript i AmPHP, men jag var inte nöjd med belastningen det skapade (ett kraftigt hopp i början till 100 % kärnförbrukning). Sedan kom curl-omslaget för ReactPHP in i spelet, som passade väl in i mina önskemål vad gäller antalet förbrukade CPU-cykler, men som inte alls gav hastigheten vad jag ville ha (det visade sig att du helt enkelt kan minska intervallet för samtal curl_multi_select, men då har vi en frosseri som liknar det första alternativet ). Jag försökte till och med skriva en liten tjänst i Rust, och det fungerade ganska snabbt (det är förvånande att det fungerade, med tanke på min kunskap), men jag ville ha mer, och det var på något sätt svårt att anpassa det. Dessutom buffrade alla dessa lösningar på något konstigt sätt svaret, och jag ville spåra ögonblicket när filnedladdningen slutade med största noggrannhet.

I allmänhet var det snett ett tag, men det gick. Tills jag en dag kom på en idé som var anmärkningsvärd i sin galenskap: nginx, i teorin, kan göra vad jag vill, arbeta snabbt och till och med tillåta alla typer av perversioner med konfiguration. Vi måste prova – tänk om det fungerar? Och efter en halv dag av ihärdigt letande föddes en lösning som hade fungerat stabilt i flera månader och uppfyllde alla mina krav.

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

En kortversion utan kommentarer kan ses under spoilern

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

Vi skriver ett manus för att hantera all denna lycka

Exemplet kommer att vara i PHP och medvetet skrivet med ett minimum av kit. Jag tror att alla som har erfarenhet av något annat språk kommer att kunna integrera detta avsnitt med mitt exempel.

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

Resultat av

I allmänhet gör denna metod det ganska enkelt att organisera distributionen av filer till användare från valfri molnlagring. Ja, även från telegram eller VK, (förutsatt att filstorleken inte överstiger den tillåtna storleken för denna lagring). Jag hade en idé liknande detta, men tyvärr stöter jag på filer upp till 2 GB, och jag har ännu inte hittat en metod eller modul för att limma svar från uppströms, och att skriva någon form av omslag för det här projektet är orimligt arbetskrävande.

Tack för din uppmärksamhet. Jag hoppas att min berättelse var åtminstone lite intressant eller användbar för dig.

Källa: will.com

Lägg en kommentar