Nginx арқылы Google Drive файлдарын тарату

тарихын

Маған 1.5 ТБ-тан астам деректерді бір жерде сақтау керек болды, сонымен қатар қарапайым пайдаланушыларға оны тікелей сілтеме арқылы жүктеп алу мүмкіндігін қамтамасыз ету керек болды. Дәстүрлі түрде жадтың мұндай көлемі VDS-ке түсетіндіктен, жалға алу құны жобаның бюджетіне «ештеңе істеуге болмайды» санатынан кірмейді, ал бастапқы деректер бойынша менде VPS 400 ГБ SSD болды, мұнда тіпті, егер мен қаласам, мен 1.5 ТБ кескінді жоғалтпай қысусыз қоя алмадым, ол сәтті болады.

Содан кейін мен Google Drive-тан қажетсіз нәрселерді жойсам, мысалы, Windows XP жүйесінде жұмыс істейтін бағдарламалар және Интернет соншалықты жылдам болмаған кезден бастап бір құрылғыдан екіншісіне ауысатын басқа нәрселер шексіз емес екенін есіме түсірдім ( мысалы, виртуалды қораптың 10-20 нұсқасының ностальгиялықтан басқа мәнге ие болуы екіталай еді), онда бәрі өте жақсы сәйкес келуі керек. Айтылды орындалды. Осылайша, api-ге сұраулар санының шегін бұзып (айтпақшы, техникалық қолдау ешбір қиындықсыз бір пайдаланушыға арналған сұраулар квотасын 100 секундта 10 000-ға дейін арттырды), деректер оны одан әрі орналастыру орнына тез ағынды. .

Бәрі жақсы сияқты, бірақ енді оны соңғы пайдаланушыға жеткізу керек. Сонымен қатар, басқа ресурстарға қайта бағыттаусыз, бірақ адам жай ғана «Жүктеу» түймесін басып, құнды файлдың бақытты иесі болады.

Міне, құдайға ант етемін, мен неше түрлі қиындыққа тап болдым. Бастапқыда бұл AmPHP сценарийі болды, бірақ ол жасаған жүктеме мені қанағаттандырмады (бастапқыда 100% негізгі тұтынуға күрт секіру). Содан кейін ReactPHP үшін бұйралағыш қаптама іске қосылды, ол тұтынылатын CPU циклдерінің саны бойынша менің тілектеріме сәйкес келеді, бірақ мен қалағандай жылдамдықты бермеді (қоңырау аралығын жай ғана қысқартуға болады екен. curl_multi_select, бірақ бізде бірінші нұсқаға ұқсас ашкөздік бар ). Мен тіпті Rust-та шағын қызметті жазуға тырыстым және ол тез жұмыс істеді (менің білімімді ескере отырып, ол жұмыс істегені таңқаларлық), бірақ мен одан да көп нәрсені қалаймын және оны баптау қиын болды. Сонымен қатар, осы шешімдердің барлығы қандай да бір түрде жауапты буферлендірді және мен файлды жүктеудің ең үлкен дәлдікпен аяқталған сәтін қадағалағым келді.

Жалпы, ол біраз уақыт қисық болды, бірақ ол жұмыс істеді. Бір күнге дейін мен оның ақылсыздығымен таң қалдыратын идеяны ойлап таптым: nginx, теориялық тұрғыдан, мен қалаған нәрсені жасай алады, тез жұмыс істей алады және тіпті конфигурациямен әртүрлі бұрмалауға мүмкіндік береді. Біз тырысуымыз керек - егер ол жұмыс істесе ше? Жарты күндік табанды ізденістен кейін бірнеше ай бойы тұрақты жұмыс істеп, менің барлық талаптарыма жауап беретін шешім дүниеге келді.

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

Түсініктемесіз қысқа нұсқаны спойлердің астынан көруге болады

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

Біз осы бақытты басқару үшін сценарий жазып жатырмыз

Мысал PHP тілінде болады және ең аз жинақпен әдейі жазылады. Менің ойымша, кез келген басқа тілде тәжірибесі бар кез келген адам менің мысалды қолдана отырып, бұл бөлімді біріктіре алады.

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

Нәтижелері

Жалпы алғанда, бұл әдіс кез келген бұлттық қоймадан пайдаланушыларға файлдарды таратуды ұйымдастыруды айтарлықтай жеңілдетеді. Иә, тіпті Telegram немесе VK сайтынан (файл өлшемі осы жадтың рұқсат етілген өлшемінен аспаған жағдайда). Менде ұқсас идея болды бұл, бірақ, өкінішке орай, мен 2 ГБ дейінгі файлдарды кездестіремін және мен жоғарыдан жауаптарды желімдеу әдісін немесе модулін әлі таппадым, және бұл жоба үшін қаптамалардың қандай да бір түрін жазу негізсіз еңбекті қажет етеді.

Назарларыңызға рахмет. Менің әңгімем сізге аз да болса қызықты немесе пайдалы болды деп үміттенемін.

Ақпарат көзі: www.habr.com

пікір қалдыру