Dijeljenje fajlova sa Google diska koristeći nginx

prapovijest

Desilo se da sam trebao negdje pohraniti više od 1.5 TB podataka, a također i omogućiti običnim korisnicima da ih preuzmu putem direktne veze. Pošto tradicionalno takve količine memorije idu na VDS, trošak zakupa koji nije mnogo uključen u budžet projekta iz kategorije „ništa za raditi“, a prema izvornim podacima imao sam VPS 400GB SSD, gdje, čak i ako sam htio, nisam mogao staviti 1.5TB slika bez kompresije bez gubitaka, uspjet će.

I onda sam se sjetio da ako izbrišem smeće sa Google Drive-a, poput programa koji će raditi samo na Windows XP-u, i drugih stvari koje se sele sa jednog uređaja na drugi još od dana kada internet uopšte nije bio tako brz, nije neograničen ( na primjer, tih 10-20 verzija virtualne kutije vjerojatno neće imati nikakvu vrijednost osim nostalgične), onda bi sve trebalo jako dobro stati. Ne pre rečeno nego učinjeno. I tako, probijajući ograničenje broja zahtjeva prema api-u (usput, tehnička podrška je bez problema povećala kvotu zahtjeva po korisniku na 100 u 10 sekundi), podaci su brzo tekli do mjesta njegove daljnje implementacije .

Čini se da je sve dobro, ali sada to treba prenijeti do krajnjeg korisnika. Štaviše, bez ikakvih preusmjeravanja na druge resurse, već tako da osoba jednostavno pritisne dugme „Preuzmi“ i postane sretni vlasnik dragocjene datoteke.

Eto, bogami, upao sam u razne nevolje. Isprva je to bila skripta u AmPHP-u, ali nisam bio zadovoljan opterećenjem koje je stvorio (oštar skok na početku na 100% potrošnje jezgra). Tada je na scenu stupio curl wrapper za ReactPHP, koji se sasvim uklopio u moje želje po broju potrošenih CPU ciklusa, ali nije dao brzinu kakvu sam želio (ispostavilo se da jednostavno možete smanjiti interval pozivanja curl_multi_select, ali tada imamo proždrljivost sličnu prvoj opciji). Pokušao sam čak i da napišem mali servis u Rustu, i to je prilično brzo funkcioniralo (iznenađujuće je da je uspjelo, s obzirom na moje znanje), ali sam želio više, i bilo je nekako teško prilagoditi ga. Osim toga, sva ova rješenja su nekako čudno omeđivala odziv, a ja sam htio s najvećom preciznošću pratiti trenutak kada je preuzimanje datoteke završilo.

Općenito, neko vrijeme je bilo krivo, ali je radilo. Sve dok jednog dana nisam došao na ideju koja je bila izuzetna po svojoj ludosti: nginx, u teoriji, može da radi šta hoću, da radi brzo, pa čak i da dozvoli sve vrste perverzija sa konfiguracijom. Moramo pokušati - šta ako uspije? I nakon pola dana upornog traženja, rodilo se rješenje koje je stabilno radilo nekoliko mjeseci i ispunjavalo sve moje zahtjeve.

Postavljanje NGINX-a

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

Kratku verziju bez komentara možete vidjeti ispod spojlera

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

Pišemo scenario da upravljamo svom ovom srećom

Primjer će biti na PHP-u i namjerno napisan sa minimalnim kompletom. Mislim da će svako ko ima iskustva s bilo kojim drugim jezikom moći integrirati ovaj odjeljak koristeći moj primjer.

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

Ishodi

Općenito, ova metoda olakšava organiziranje distribucije datoteka korisnicima iz bilo kojeg skladišta u oblaku. Da, čak i iz telegrama ili VK-a, (pod uslovom da veličina datoteke ne prelazi dozvoljenu veličinu ove memorije). Imao sam sličnu ideju ovo, ali nažalost nailazim na fajlove do 2GB, a još nisam našao metodu ili modul za lijepljenje odgovora od upstreama, a pisanje nekakvih omota za ovaj projekat je nerazumno naporno.

Hvala vam na pažnji. Nadam se da vam je moja priča bila barem malo zanimljiva ili korisna.

izvor: www.habr.com

Dodajte komentar