Дистрибуција на датотеки од Google Drive користејќи nginx

праисторијата

Едноставно, ми требаше да складирам повеќе од 1.5 ТБ податоци некаде, а исто така да обезбедам можност за обичните корисници да ги преземат преку директна врска. Бидејќи традиционално таквите количини на меморија одат за VDS, трошоците за изнајмување кои не се многу вклучени во буџетот на проектот од категоријата „нема да се направи“, а од изворните податоци имав VPS 400GB 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, (под услов големината на датотеката да не ја надминува дозволената големина на ова складирање). Имав идеја слична на ова, но за жал наидувам на датотеки до 2GB, а сеуште не сум нашол метод или модул за лепење одговори од upstream, а пишувањето некакви обвивки за овој проект е неразумно трудоинтензивно.

Ви благодариме за вниманието. Се надевам дека мојата приказна беше барем малку интересна или корисна за вас.

Извор: www.habr.com

Додадете коментар