Google Drive-аас nginx ашиглан файлуудыг түгээж байна

Эрьт урьдын түүх

Би хаа нэгтээ 1.5 ТБ-аас илүү өгөгдлийг хадгалах шаардлагатай болж, энгийн хэрэглэгчдэд шууд холбоосоор дамжуулан татаж авах боломжийг олгох шаардлагатай болсон. Уламжлал ёсоор ийм хэмжээний санах ой VDS-д очдог тул түрээсийн зардал нь төслийн төсөвт "хийх зүйлгүй" гэсэн ангилалд багтдаггүй бөгөөд эх сурвалжаас харахад надад VPS 400GB SSD байсан. Хүссэн ч би алдагдалгүй шахалтгүйгээр 1.5 TB-ийн зургийг оруулж чадсангүй, энэ нь амжилтанд хүрэх болно.

Тэгээд дараа нь би Google Drive-аас хог хаягдлыг устгавал, тухайлбал зөвхөн Windows XP дээр ажилладаг програмууд болон интернет тийм ч хурдан биш байсан үеэс хойш нэг төхөөрөмжөөс нөгөө төхөөрөмж рүү шилжиж байсан бусад зүйлсийг устгавал хязгааргүй гэдгийг санав. жишээлбэл, виртуал хайрцагны эдгээр 10-20 хувилбар нь дурсахуйгаас өөр үнэ цэнэтэй байх магадлал багатай байсан), тэгвэл бүх зүйл маш сайн тохирох ёстой. Хэлэхээс өмнө хийсэн. Тиймээс API-д хандах хүсэлтийн тооны хязгаарыг давж (дашрамд хэлэхэд, техникийн дэмжлэг нь ямар ч асуудалгүйгээр нэг хэрэглэгчдэд ногдох хүсэлтийн квотыг 100 секундэд 10 хүртэл нэмэгдүүлсэн) өгөгдөл нь түүнийг цаашид байршуулах газар руу хурдан урсаж байв. .

Бүх зүйл сайхан байгаа мэт боловч одоо үүнийг эцсийн хэрэглэгчдэд хүргэх хэрэгтэй. Түүгээр ч барахгүй бусад эх сурвалж руу дахин чиглүүлэхгүйгээр хүн зүгээр л "Татаж авах" товчийг дарж, нандин файлын аз жаргалтай эзэн болно.

Энд бурхан минь, би янз бүрийн асуудалд орсон. Эхлээд энэ нь AmPHP-ийн скрипт байсан боловч түүний үүсгэсэн ачаалалд сэтгэл хангалуун бус байсан (эхэндээ огцом үсрэлт 100% үндсэн хэрэглээ). Дараа нь ReactPHP-д зориулсан буржгар боодол хэрэгжиж эхэлсэн бөгөөд энэ нь ашигласан CPU-ийн циклийн тоогоор миний хүсэлд нийцсэн боловч миний хүссэн хурдыг огт өгөөгүй (та зүгээр л дуудлагын интервалыг багасгах боломжтой болсон). 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));

Үр дүн

Ерөнхийдөө энэ арга нь ямар ч үүл хадгалах сангаас хэрэглэгчдэд файл түгээх ажлыг зохион байгуулахад маш хялбар болгодог. Тийм ээ, тэр ч байтугай Telegram эсвэл VK-ээс (файлын хэмжээ нь энэ хадгалах сангийн зөвшөөрөгдөх хэмжээнээс хэтрэхгүй бол). Үүнтэй төстэй санаа надад байсан энэ нь, гэхдээ харамсалтай нь би 2 ГБ хүртэлх хэмжээтэй файлуудтай тааралдсан бөгөөд би дээд урсгалаас хариултуудыг наах арга эсвэл модулийг хараахан олоогүй байгаа бөгөөд энэ төсөлд зориулж зарим төрлийн боодол бичих нь үндэслэлгүй хөдөлмөр их шаарддаг.

Анхаарал тавьсанд баярлалаа. Миний түүх танд бага ч гэсэн сонирхолтой эсвэл хэрэгтэй байсан гэж найдаж байна.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх