Ndarja e skedarëve nga Google Drive duke përdorur nginx

parahistorinë

Thjesht ndodhi që më duhej të ruaja më shumë se 1.5 TB të dhëna diku, dhe gjithashtu t'u siguroja përdoruesve të zakonshëm mundësinë për t'i shkarkuar ato përmes një lidhjeje të drejtpërdrejtë. Meqenëse tradicionalisht sasi të tilla memorie shkojnë në VDS, kostoja e qirasë e cila nuk përfshihet shumë në buxhetin e projektit nga kategoria "asgjë për të bërë", dhe nga të dhënat burimore kisha një SSD VPS 400 GB, ku, edhe nëse doja, nuk mund të vendosja 1.5 TB imazhe pa kompresim pa humbje, do të ketë sukses.

Dhe pastaj m'u kujtua që nëse fshij mbeturinat nga Google Drive, si programet që do të funksionojnë vetëm në Windows XP, dhe gjëra të tjera që kanë lëvizur nga një pajisje në tjetrën që nga ditët kur interneti nuk ishte aspak aq i shpejtë, jo i pakufizuar ( për shembull, ato 10-20 versione të kutisë virtuale nuk kishin gjasa të kishin ndonjë vlerë tjetër përveç nostalgjisë), atëherë gjithçka duhet të përshtatet shumë mirë. E thënë më shpejt se sa bëhet. Dhe kështu, duke thyer kufirin e numrit të kërkesave në api (nga rruga, mbështetja teknike pa asnjë problem rriti kuotën e kërkesave për përdorues në 100 në 10 sekonda), të dhënat rrodhën shpejt në vendin e vendosjes së tij të mëtejshme .

Gjithçka duket se është mirë, por tani duhet t'i përcillet përdoruesit përfundimtar. Për më tepër, pa ndonjë ridrejtim në burime të tjera, por në mënyrë që një person thjesht të shtyp butonin "Shkarko" dhe të bëhet pronari i lumtur i skedarit të çmuar.

Këtu, për Zotin, unë hyra në të gjitha llojet e telasheve. Në fillim ishte një skenar në AmPHP, por nuk isha i kënaqur me ngarkesën që krijoi (një kërcim i mprehtë në fillim në 100% të konsumit bazë). Pastaj hyri në lojë mbështjellësi i kaçurrelave për ReactPHP, i cili përshtatet mjaft me dëshirat e mia për sa i përket numrit të cikleve të CPU-së të konsumuara, por nuk dha shpejtësinë fare atë që doja (rezultoi se thjesht mund të zvogëloni intervalin e thirrjeve curl_multi_select, por atëherë kemi një grykësi të ngjashme me opsionin e parë). Unë madje u përpoqa të shkruaj një shërbim të vogël në Rust, dhe funksionoi mjaft shpejt (është për t'u habitur që funksionoi, duke pasur parasysh njohuritë e mia), por doja më shumë dhe ishte disi e vështirë ta personalizoja. Për më tepër, të gjitha këto zgjidhje në një farë mënyre e zbutën përgjigjen në mënyrë të çuditshme dhe doja të gjurmoja momentin kur shkarkimi i skedarit përfundoi me saktësinë më të madhe.

Në përgjithësi, për një kohë ishte shtrembër, por funksionoi. Derisa një ditë dola me një ide që ishte e jashtëzakonshme në çmendurinë e saj: nginx, në teori, mund të bëjë atë që dua, të punojë shpejt dhe madje të lejojë të gjitha llojet e perversioneve me konfigurim. Duhet të provojmë - çka nëse funksionon? Dhe pas gjysmë dite kërkimi të vazhdueshëm, lindi një zgjidhje që kishte disa muaj që punonte në mënyrë të qëndrueshme dhe plotësonte të gjitha kërkesat e mia.

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

Një version i shkurtër pa komente mund të shihet nën spoiler

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

Ne po shkruajmë një skenar për të menaxhuar gjithë këtë lumturi

Shembulli do të jetë në PHP dhe i shkruar qëllimisht me një minimum komplete. Mendoj se kushdo që ka përvojë me ndonjë gjuhë tjetër do të jetë në gjendje ta integrojë këtë seksion duke përdorur shembullin tim.

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

Rezultatet e

Në përgjithësi, kjo metodë e bën mjaft të lehtë organizimin e shpërndarjes së skedarëve tek përdoruesit nga çdo hapësirë ​​​​ruajtjeje cloud. Po, edhe nga telegrami ose VK, (me kusht që madhësia e skedarit të mos kalojë madhësinë e lejuar të kësaj ruajtjeje). Unë kisha një ide të ngjashme me kjo, por për fat të keq kam hasur në skedarë deri në 2 GB, dhe nuk kam gjetur ende një metodë ose modul për ngjitjen e përgjigjeve nga rrjedha e sipërme, dhe shkrimi i një lloj mbështjellësish për këtë projekt është në mënyrë të paarsyeshme punë intensive.

Faleminderit per vemendjen. Shpresoj se historia ime ishte të paktën pak interesante ose e dobishme për ju.

Burimi: www.habr.com

Shto një koment