Google Drive-ից ֆայլերի բաշխում nginx-ի միջոցով

նախապատմությանը

Պարզապես այնպես ստացվեց, որ ինձ անհրաժեշտ էր ինչ-որ տեղ պահել 1.5 ՏԲ-ից ավելի տվյալներ, ինչպես նաև ապահովել սովորական օգտատերերի համար դրանք ներբեռնելու ուղիղ հղման միջոցով: Քանի որ ավանդաբար հիշողության նման ծավալները գնում են VDS-ին, վարձակալության արժեքը, որն այնքան էլ ներառված չէ նախագծի բյուջեում «անելու բան չկա» կատեգորիայից, և աղբյուրի տվյալներից ես ունեի VPS 400 ԳԲ SSD, որտեղ, նույնիսկ եթե ես ուզեցի, չկարողացա տեղադրել 1.5 ՏԲ պատկեր առանց կորուստների սեղմման, դա կհաջողվի:

Եվ հետո ես հիշեցի, որ եթե ես ջնջեմ աղբը Google Drive-ից, ինչպես ծրագրերը, որոնք կաշխատեն միայն Windows XP-ով, և այլ բաներ, որոնք տեղափոխվել են մի սարքից մյուսը այն օրերից, երբ ինտերնետն ամենևին էլ այդքան արագ չէր, անսահմանափակ ( օրինակ, վիրտուալ տուփի այդ 10-20 տարբերակները դժվար թե նոստալգիկական արժեք ունենան), ուրեմն ամեն ինչ պետք է շատ լավ տեղավորվի։ Ոչ շուտ ասել, քան արվել: Եվ այսպես, ճեղքելով api-ի հարցումների քանակի սահմանը (ի դեպ, տեխնիկական աջակցությունն առանց որևէ խնդրի 100 վայրկյանում մեկ օգտագործողի հարցումների քվոտան ավելացրեց մինչև 10-ի), տվյալները արագ հոսեցին դեպի դրա հետագա տեղակայման վայրը: .

Թվում է, թե ամեն ինչ լավ է, բայց այժմ այն ​​պետք է փոխանցվի վերջնական օգտագործողին: Ավելին, առանց այլ ռեսուրսների վերահղումների, բայց այնպես, որ մարդը պարզապես սեղմի «Ներբեռնում» կոճակը և դառնա թանկարժեք ֆայլի երջանիկ սեփականատերը:

Այստեղ, Աստծով, ես մտա ամեն տեսակ փորձանքների մեջ։ Սկզբում դա սկրիպտ էր AmPHP-ում, բայց ես գոհ չէի նրա ստեղծած ծանրաբեռնվածությունից (սկզբում կտրուկ թռիչք մինչև 100% հիմնական սպառումը): Այնուհետև գործարկվեց ReactPHP-ի գանգուր փաթաթումը, որը լիովին համապատասխանում էր իմ ցանկություններին՝ սպառված պրոցեսորի ցիկլերի քանակի առումով, բայց ամենևին չտվեց իմ ուզած արագությունը (պարզվեց, որ դուք պարզապես կարող եք կրճատել զանգի միջակայքը 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));

Արդյունքները

Ընդհանուր առմամբ, այս մեթոդը բավականին հեշտ է դարձնում ֆայլերի բաշխումը օգտվողներին ցանկացած ամպային պահեստից: Այո, նույնիսկ հեռագրից կամ VK-ից (պայմանով, որ ֆայլի չափը չի գերազանցում այս պահեստի թույլատրելի չափը): Ես նման գաղափար ունեի սա է, բայց, ցավոք, ես հանդիպում եմ մինչև 2 ԳԲ ֆայլեր, և ես դեռ չեմ գտել պատասխանները վերևից սոսնձելու մեթոդ կամ մոդուլ, և այս նախագծի համար ինչ-որ փաթաթաներ գրելը անհիմն աշխատատար է:

Շնորհակալություն ուշադրության համար. Հուսով եմ, որ իմ պատմությունը գոնե մի փոքր հետաքրքիր կամ օգտակար էր ձեզ համար:

Source: www.habr.com

Добавить комментарий