Nginx istifadə edərək Google Diskdən faylların paylaşılması

Prehistorya

Elə oldu ki, mən hardasa 1.5 TB-dən çox məlumat saxlamalı oldum, həm də adi istifadəçilərə onu birbaşa keçid vasitəsilə yükləmək imkanı verməli oldum. Ənənəvi olaraq bu cür yaddaş həcmi VDS-ə getdiyindən, icarə haqqı layihənin büdcəsinə "etməli heç bir şey" kateqoriyasından o qədər də daxil edilmir və mənbə məlumatlarından məndə VPS 400GB SSD var idi. İstədim, itkisiz sıxılma olmadan 1.5 TB şəkillər qoya bilmədim, bu, uğur qazanacaq.

Sonra xatırladım ki, Google Diskdən zibilləri silsəm, məsələn, yalnız Windows XP-də işləyəcək proqramlar və İnternetin o qədər də sürətli olmadığı günlərdən bəri bir cihazdan digərinə keçən digər şeylər məhdudiyyətsiz deyildi ( məsələn, virtual qutunun həmin 10-20 versiyası çətin ki, nostaljidən başqa heç bir dəyərə malik olmayacaq), onda hər şey çox yaxşı uyğunlaşmalıdır. Daha tez deyildi. Beləliklə, api-yə müraciətlərin sayına dair məhdudiyyəti aşaraq (yeri gəlmişkən, texniki dəstək heç bir problem olmadan bir istifadəçi üçün sorğu kvotası 100 saniyədə 10-ə qədər artırdı), məlumatlar sürətlə onun sonrakı yerləşdirilməsi yerinə axdı. .

Hər şey yaxşı görünür, amma indi bunu son istifadəçiyə çatdırmaq lazımdır. Üstəlik, digər mənbələrə heç bir yönləndirmə olmadan, ancaq bir insan sadəcə "Yükləmə" düyməsini sıxır və dəyərli faylın xoşbəxt sahibi olur.

Burada, vallah, hər cür bəlaya girdim. Əvvəlcə AmPHP-də bir skript idi, lakin onun yaratdığı yük məni qane etmədi (başlanğıcda 100% əsas istehlaka kəskin sıçrayış). Sonra ReactPHP üçün qıvrım sarğısı işə düşdü, bu istehlak edilən CPU dövrlərinin sayı baxımından mənim istəklərimə yaxşı uyğun gəlir, lakin sürəti istədiyim qədər vermir (məlum oldu ki, sadəcə zəng intervalını azalda bilərsiniz. curl_multi_select, lakin sonra bizdə birinci seçimə bənzər acgözlük var ). Mən hətta Rust-da kiçik bir xidmət yazmağa çalışdım və o, olduqca tez işlədi (bildiyimi nəzərə alsaq, işləməsi təəccüblüdür), amma daha çox şey istədim və onu fərdiləşdirmək bir qədər çətin idi. Bundan əlavə, bütün bu həllər birtəhər qəribə bir şəkildə cavabı tamponladı və mən faylın yüklənməsinin ən böyük dəqiqliklə başa çatdığı anı izləmək istədim.

Ümumiyyətlə, bir müddət əyri idi, amma işlədi. Bir günə qədər mən öz çılğınlığı ilə diqqəti çəkən bir ideya ilə gəldim: nginx, nəzəri olaraq, istədiyimi edə bilər, tez işləyə bilər və hətta konfiqurasiya ilə hər cür təhriflərə icazə verə bilər. Biz cəhd etməliyik - əgər işləyirsə? Yarım günlük davamlı axtarışdan sonra bir neçə aydır stabil işləyən və bütün tələblərimə cavab verən bir həll doğuldu.

NGINX qurulur

# Первым делом создадим в конфигах нашего сайта отдельную локацию.
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;
}

Şərhsiz qısa versiyanı spoylerin altında görmək olar

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

Bütün bu xoşbəxtliyi idarə etmək üçün bir ssenari yazırıq

Nümunə PHP-də olacaq və bilərəkdən minimum dəstlə yazılacaq. Düşünürəm ki, hər hansı başqa dildə təcrübəsi olan hər kəs mənim nümunəmdən istifadə edərək bu bölməni birləşdirə biləcək.

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

Nəticələri

Ümumiyyətlə, bu üsul istənilən bulud yaddaşından istifadəçilərə faylların paylanmasını təşkil etməyi kifayət qədər asanlaşdırır. Bəli, hətta teleqramdan və ya VK-dan, (fayl ölçüsü bu yaddaşın icazə verilən ölçüsünü aşmamaq şərti ilə). oxşar bir fikrim var idi bu, lakin təəssüf ki, 2GB-a qədər olan fayllarla rastlaşıram və mən hələ yuxarıdan gələn cavabları yapışdırmaq üçün bir üsul və ya modul tapmamışam və bu layihə üçün bir növ sarğıların yazılması əsassız əmək tələb edir.

Diqqətinizə görə təşəkkürlər. Ümid edirəm hekayəm sizin üçün bir az maraqlı və ya faydalı oldu.

Mənbə: www.habr.com

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