Distribui dosierojn de Google Drive uzante nginx

antaŭhistorio

Okazis, ke mi bezonis ie stoki pli ol 1.5 TB da datumoj, kaj ankaŭ disponigi la kapablon por ordinaraj uzantoj elŝuti ĝin per rekta ligo. Ĉar tradicie tiaj kvantoj da memoro iras al VDS, la kosto de luo, kiu ne estas tre inkluzivita en la projektbuĝeto de la kategorio "nenio farenda", kaj el la fontaj datumoj mi havis VPS 400GB SSD, kie, eĉ se mi deziris, mi ne povus meti 1.5TB da bildoj sen senperda kunpremo, ĝi sukcesos.

Kaj tiam mi rememoris, ke se mi forigas rubaĵojn de Google Drive, kiel programojn, kiuj nur ruliĝos en Windows XP, kaj aliajn aferojn, kiuj moviĝas de unu aparato al alia ekde la tagoj, kiam Interreto tute ne estis tiel rapida ne senlima ( ekzemple, tiuj 10-20 versioj de la virtuala skatolo verŝajne ne havis ian valoron krom nostalgia), tiam ĉio devus konveni tre bone. Ne pli frue dirite ol farite. Kaj tiel, trarompante la limon de la nombro da petoj al la api (cetere, teknika subteno senprobleme pliigis la kvoton de petoj por uzanto al 100 en 10 sekundoj), la datumoj rapide fluis al la loko de sia plua disfaldo. .

Ĉio ŝajnas esti bona, sed nun ĝi devas esti transdonita al la fina uzanto. Krome, sen ajnaj alidirektiloj al aliaj rimedoj, sed tiel ke persono simple premas la butonon "Elŝuti" kaj fariĝu la feliĉa posedanto de la trezora dosiero.

Ĉi tie, je Dio, mi eniris ĉiajn problemojn. Komence ĝi estis skripto en AmPHP, sed mi ne kontentiĝis pri la ŝarĝo, kiun ĝi kreis (akra salto ĉe la komenco al 100% kerna konsumo). Tiam ekfunkciis la bukla envolvaĵo por ReactPHP, kiu bone kongruis kun miaj deziroj laŭ la nombro da CPU-cikloj konsumitaj, sed tute ne donis la rapidecon tion, kion mi volis (montriĝis, ke vi povas simple redukti la intervalon de vokado. curl_multi_select, sed tiam ni havas glutecon similan al la unua opcio). Mi eĉ provis verki malgrandan servon en Rust, kaj ĝi funkciis sufiĉe rapide (estas surprize, ke ĝi funkciis, konsiderante miajn sciojn), sed mi volis pli, kaj estis iel malfacile personecigi ĝin. Krome, ĉiuj ĉi tiuj solvoj iel strange bufris la respondon, kaj mi volis spuri la momenton, kiam la dosiero elŝuto finiĝis kun la plej granda precizeco.

Ĝenerale ĝi estis kurba dum iom da tempo, sed ĝi funkciis. Ĝis unu tagon mi elpensis ideon kiu estis rimarkinda en sia frenezo: nginx, en teorio, povas fari kion mi volas, labori rapide, kaj eĉ permesi ĉiajn perversecojn kun agordo. Ni devas provi - kio se ĝi funkcias? Kaj post duontaga persista serĉado naskiĝis solvo, kiu stabile funkciis dum kelkaj monatoj kaj plenumis ĉiujn miajn postulojn.

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

Mallonga versio sen komentoj videblas sub la 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;
}

Ni skribas skripton por administri ĉi tiun tutan feliĉon

La ekzemplo estos en PHP kaj intence skribita kun minimumo de ilaro. Mi pensas, ke ĉiu, kiu havas sperton kun iu ajn alia lingvo, povos integri ĉi tiun sekcion uzante mian ekzemplon.

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

Rezultoj

Ĝenerale, ĉi tiu metodo faras sufiĉe facile organizi la distribuadon de dosieroj al uzantoj de iu ajn nuba stokado. Jes, eĉ de telegramo aŭ VK, (kondiĉe ke la dosiergrandeco ne superas la permeseblan grandecon de ĉi tiu stokado). Mi havis ideon similan al ĉi tio, sed bedaŭrinde mi trovas dosierojn ĝis 2GB, kaj mi ankoraŭ ne trovis metodon aŭ modulon por glui respondojn de kontraŭflue, kaj skribi ian envolvaĵojn por ĉi tiu projekto estas senracie laborintensa.

Dankon pro via atento. Mi esperas, ke mia rakonto estis almenaŭ iom interesa aŭ utila al vi.

fonto: www.habr.com

Aldoni komenton