مشاركة الملفات من Google Drive باستخدام nginx

قبل التاريخ

لقد حدث أنني كنت بحاجة إلى تخزين أكثر من 1.5 تيرابايت من البيانات في مكان ما، وكذلك توفير القدرة للمستخدمين العاديين على تنزيلها عبر رابط مباشر. نظرًا لأن هذه الكميات من الذاكرة تذهب تقليديًا إلى VDS، فإن تكلفة الإيجار لا يتم تضمينها كثيرًا في ميزانية المشروع من فئة "لا شيء يجب القيام به"، ومن البيانات المصدر كان لدي VPS 400GB SSD، حيث، حتى لو كنت أردت ذلك، لم أتمكن من وضع 1.5 تيرابايت من الصور دون الضغط بدون فقدان البيانات، وسوف ينجح ذلك.

وبعد ذلك تذكرت أنني إذا قمت بحذف الملفات غير المرغوب فيها من Google Drive، مثل البرامج التي ستعمل فقط على نظام التشغيل Windows XP، وغيرها من الأشياء التي كانت تنتقل من جهاز إلى آخر منذ الأيام التي لم يكن فيها الإنترنت سريعًا على الإطلاق وليس غير محدود ( على سبيل المثال، من غير المرجح أن يكون لهذه الإصدارات من 10 إلى 20 من الصندوق الافتراضي أي قيمة بخلاف الحنين إلى الماضي)، فيجب أن يكون كل شيء مناسبًا بشكل جيد للغاية. لا قال في وقت أقرب مما فعله. وهكذا، من خلال اختراق الحد الأقصى لعدد طلبات واجهة برمجة التطبيقات (بالمناسبة، قام الدعم الفني دون أي مشاكل بزيادة حصة الطلبات لكل مستخدم إلى 100 في 10 ثانية)، وتدفقت البيانات بسرعة إلى مكان نشرها الإضافي .

يبدو أن كل شيء على ما يرام، ولكن الآن يجب نقله إلى المستخدم النهائي. علاوة على ذلك، دون أي عمليات إعادة توجيه إلى موارد أخرى، ولكن بحيث يضغط الشخص ببساطة على زر "تنزيل" ويصبح المالك السعيد للملف العزيز.

وهنا والله وقعت في كل أنواع المشاكل. في البداية كان البرنامج نصيًا بتنسيق AmPHP، لكنني لم أكن راضيًا عن التحميل الذي أنشأه (قفزة حادة في البداية إلى استهلاك أساسي بنسبة 100٪). ثم تم تشغيل غلاف الضفيرة الخاص بـ ReactPHP، والذي يتناسب جيدًا مع رغباتي من حيث عدد دورات وحدة المعالجة المركزية المستهلكة، لكنه لم يمنح السرعة على الإطلاق ما أردت (اتضح أنه يمكنك ببساطة تقليل الفاصل الزمني للاتصال curl_multi_select، ولكن بعد ذلك لدينا شراهة مشابهة للخيار الأول ). حتى أنني حاولت كتابة خدمة صغيرة في Rust، وعملت بسرعة كبيرة (من المدهش أنها نجحت، نظرًا لمعرفتي)، لكنني أردت المزيد، وكان من الصعب تخصيصها إلى حد ما. بالإضافة إلى ذلك، كل هذه الحلول تخزن الاستجابة بشكل غريب بطريقة أو بأخرى، وأردت تتبع اللحظة التي انتهى فيها تنزيل الملف بأكبر قدر من الدقة.

بشكل عام، كان ملتوية لفترة من الوقت، لكنه نجح. حتى توصلت ذات يوم إلى فكرة كانت رائعة في جنونها: يمكن لـ 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

إضافة تعليق