Tiedostojen jakaminen Google Drivesta nginxillä

esihistoria

Sattui vain niin, että minun piti tallentaa yli 1.5 TB tietoa jonnekin ja tarjota myös tavallisille käyttäjille mahdollisuus ladata se suoran linkin kautta. Koska perinteisesti tällaiset määrät muistia menevät VDS:lle, vuokraus, joka ei juurikaan sisälly projektibudjettiin "ei mitään tekemistä" -kategoriasta, ja lähdetiedoista minulla oli VPS 400GB SSD, jossa vaikka Halusin, en voinut laittaa 1.5 Tt kuvia ilman häviötöntä pakkausta, se onnistuu.

Ja sitten muistin, että jos poistan Google Drivesta roskaa, kuten ohjelmia, jotka toimivat vain Windows XP:ssä, ja muita asioita, jotka ovat siirtyneet laitteesta toiseen niistä ajoista, jolloin Internet ei ollut ollenkaan niin nopea, ei rajaton ( esimerkiksi näillä 10-20 versiolla virtuaalilaatikosta ei todennäköisesti ollut muuta arvoa kuin nostalginen), niin kaiken pitäisi sopia erittäin hyvin. Ei ennemmin sanottu kuin tehty. Ja niin, rikkomalla API:n pyyntöjen lukumäärän rajoitus (muuten, tekninen tuki ilman ongelmia nosti pyyntöjen kiintiön käyttäjää kohti 100 10:een 000 sekunnissa), tiedot virtasivat nopeasti sen jatkokäyttöön. .

Kaikki näyttää olevan hyvin, mutta nyt se on välitettävä loppukäyttäjälle. Lisäksi ilman uudelleenohjauksia muihin resursseihin, vaan niin, että henkilö painaa vain "Lataa" -painiketta ja hänestä tulee arvokkaan tiedoston onnellinen omistaja.

Täällä, Jumala, jouduin kaikenlaisiin ongelmiin. Aluksi se oli AmPHP-skripti, mutta en ollut tyytyväinen sen luomaan kuormaan (jyrkkä hyppy alussa 100% ydinkulutukseen). Sitten tuli peliin ReactPHP:n curl-kääre, joka sopi hyvin toiveisiini kulutettujen prosessorijaksojen lukumäärän suhteen, mutta ei antanut nopeutta ollenkaan mitä halusin (kävi ilmi, että voit yksinkertaisesti lyhentää soittoväliä curl_multi_select, mutta silloin meillä on samanlainen ahmatti kuin ensimmäisessä vaihtoehdossa ). Yritin jopa kirjoittaa pienen palvelun Rustiin, ja se toimi melko nopeasti (yllättävää, että se toimi, tietämykseni perusteella), mutta halusin enemmän, ja sitä oli jotenkin vaikea muokata. Lisäksi kaikki nämä ratkaisut jotenkin oudosti puskuroivat vastausta, ja halusin seurata hetkeä, jolloin tiedostojen lataus päättyi suurimmalla tarkkuudella.

Yleensä se oli jonkin aikaa vinossa, mutta se toimi. Kunnes eräänä päivänä keksin idean, joka oli hämmästyttävä hulluudellaan: nginx voi teoriassa tehdä mitä haluan, työskennellä nopeasti ja jopa sallia kaikenlaiset perversiot konfiguroinnilla. Meidän on yritettävä - entä jos se toimii? Ja puolen päivän jatkuvan etsinnän jälkeen syntyi ratkaisu, joka oli toiminut vakaasti useita kuukausia ja täytti kaikki vaatimukseni.

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

Lyhyt versio ilman kommentteja löytyy spoilerin alta

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

Kirjoitamme käsikirjoitusta hallitaksemme kaikkea tätä onnellisuutta

Esimerkki on PHP:llä ja tarkoituksella kirjoitettu vähimmäismäärällä. Uskon, että jokainen, jolla on kokemusta jostain muusta kielestä, pystyy integroimaan tämän osion esimerkkiäni avulla.

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

Tulokset

Yleensä tämän menetelmän avulla on melko helppoa järjestää tiedostojen jakelu käyttäjille mistä tahansa pilvitallennustilasta. Kyllä, jopa sähkeestä tai VK:sta (edellyttäen, että tiedostokoko ei ylitä tämän tallennustilan sallittua kokoa). Minulla oli samanlainen idea tämä, mutta valitettavasti törmään 2GB tiedostoihin, enkä ole vielä löytänyt menetelmää tai moduulia vastausten liimaamiseen ylävirrasta, ja jonkinlaisten kääreiden kirjoittaminen tähän projektiin on kohtuuttoman työvoimavaltaista.

Kiitos huomiostasi. Toivottavasti tarinani oli ainakin hieman kiinnostava tai hyödyllinen sinulle.

Lähde: will.com

Lisää kommentti