Как лучше всего загружать файлы на другой домен из браузера?

Я создаю веб-службу запланированных сообщений в какой-то социальной сети.
Нужна помощь с загрузкой файлов при большом трафике.

Обзор процесса:

  • Пользователь загружает файлы на SomeServer (не мой).
  • Затем SomeServer отвечает строкой JSON.
  • Мое веб-приложение должно хранить этот ответ JSON.

Вариант 1: сохранить, cURL POST, удалить tmp
глупый способ, которым я это сделал:

  1. Пользователь загружает файлы в MyWebApp;
  2. MyWebApp cURL отправляет файл на SomeServer, получая ответ.

Вариант 2. Магия JS
Умный способ сделать его идеальным:

  1. Пользователь загружает файл непосредственно на SomeServer из iFrame;
  2. MyWebApp получает ответ через JavaScript.

Но это (?) невозможно из-за «Политики одного и того же происхождения», не так ли?

Вариант 3: проксирование nginx?
Лучший способ для рабочего сервера:

  1. Пользователь загружает файлы в MyWebApp;
  2. nginx перехватывает загрузку файлов и отправляет их прямо на SomeServer;
  3. Ответ JSON также перехватывается nginx и обрабатывается MyWebApp.

Имеет ли это какой-то смысл, и какой будет конфигурация nginx, скажем, для /fileupload Location, чтобы проксировать его на SomeServer?


person Serge    schedule 10.04.2012    source источник
comment
Вы можете обойти политику одинакового происхождения, но для этого SomeServer должен добавить Общий доступ к ресурсам между источниками. (CORS) к своим ответам. Проверьте, реализует ли он CORS, или вы можете убедить разработчиков SomeServer внедрить его.   -  person Dmytro Shevchenko    schedule 14.04.2012
comment
SomeServer реализует заголовки CORS, но, к сожалению, только для своего собственного корневого домена. HTTP-заголовок Access-Control-Allow-Origin предлагает одно значение. Я сомневаюсь, что их разработчики настроят это для моей службы. Итак, вернемся к nginx/переадресации сообщений.   -  person Serge    schedule 17.04.2012
comment
Вы также можете использовать postMessage для связи между фреймами независимо от исходного домена.   -  person tkone    schedule 18.04.2012
comment
@tkone Это правда, но вы не можете загружать файлы с помощью postMessage. Ну, может быть, вы могли бы как-то сериализовать/десериализовать файл. Но в любом случае использование postMessage требует разработки на стороне SomeServer, чего @SergikS, похоже, не может сделать. Кстати, postMessage используется как часть способа связи в EasyXDM, о чем я упоминал в своем ответе ниже.   -  person Dmytro Shevchenko    schedule 18.04.2012
comment
@tkone: postMessage требует программирования на стороне сервера. Но как вы могли загружать файлы с помощью postMessage !!   -  person Abdur Rahman    schedule 19.04.2012


Ответы (2)


У меня нет сервера, который я мог бы заменить SomeServer, чтобы проверить свои предложения, но я все равно попробую. Если я не прав, то, думаю, вам просто нужно используйте Flash (пример кода из ВК).

Как насчет использования iFrame для загрузки файла на SomeServer, получения ответа JSON, а затем использования postMessage для передачи ответа JSON из iFrame в главное окно вашего сайта. Насколько я понимаю, это в значительной степени мотивация для создания postMessage в первую очередь.

В общем, я думаю о чем-то подобном этому или модуль io() YUI, но с добавлением postMessage, чтобы обойти ту же политику происхождения.

Или, в случае с ВКонтакте, используя явную поддержку iFrame. Мне кажется, что вы можете добавить метод к глобальному объекту ВКонтакте, а затем вызвать этот метод из исходного домена ВКонтакте, используя VK.callMethod(). Вы можете использовать этот обходной путь для создания функции, которая может считывать ответ из скрытого iFrame.

Таким образом, вы используете VK.api('photos.getUploadServer', ...) для получения URL-адреса POST.

Затем вы используете JS, чтобы вставить этот URL-адрес в качестве действия для вашей ФОРМЫ, которую вы используете для загрузки файла. Следуйте примеру в разделе «Загрузка файлов в форме HTML» в io() документах и в complete используйте postMessage, чтобы отправить JSON обратно в родительское окно. См. пример и документацию здесь. (Если это не работает с io(), вы, безусловно, можете заставить его работать, используя список -ваш собственный пример кода, если я прав насчет VK.callMethod().)

Затем в ответ на postMessage вы можете использовать обычный AJAX для загрузки ответа JSON обратно на ваш сервер.

person Old Pro    schedule 19.04.2012
comment
URL-адрес SomeServer каждый раз новый — он выбирается из большого CDN. Загрузка файла состоит из 3 шагов: 1) вызов API для api.SomeServer, который возвращает URL-адрес типа cdn1234.SomeServer плюс некоторые параметры; 2) HTTP POST для этого URL-адреса с полем file1, содержащим данные файла изображения; Сервер не возвращает ничего, кроме строки JSON с хеш-полем, которое мне понадобится в дальнейшем. 3) другой вызов API, чтобы «включить» загруженное изображение по его хешу. - person Serge; 19.04.2012
comment
Одно действительно плохое решение, которое я видел, заключалось в том, чтобы внедрить JS в возвращаемый ответ, отменив пользовательский плагин для браузера (увидел один для Chrome), который должен был установить каждый пользователь моего веб-приложения. Затем этот плагин добавлял мой JS к каждой странице из доменов SomeServer, обеспечивая связь между источниками. Но это действительно странное решение. - person Serge; 19.04.2012
comment
@Serg, ты говоришь, что SomeServer на самом деле ВКонтакте. Вы читали документацию VK по iFrame? В частности внизу, Использование VK API в приложении IFrame - person Old Pro; 19.04.2012
comment
@OldPro Это для случая, когда приложение размещено в iFrame внутри ВКонтакте. Я понимаю, что Серг настроен наоборот. Что касается postMessage, я считаю, что это возможно только в том случае, если у вас есть прокси-сервер html/js, размещенный на SomeServer. - person Dmytro Shevchenko; 19.04.2012
comment
@OldPro уверен, что я это читал. Вызов методов API здесь не проблема. Это загрузка файла через POST-запрос и ответ на него в формате JSON, который хочет получить myWebApp, размещенный на отдельном домене. Это трехсторонняя головоломка: U загружает в A, B хочет знать ответ A. Нет возможности настроить внутренности A. Та же политика происхождения должна быть переопределена без взломов браузера и без доступа к одному из серверов. - person Serge; 19.04.2012
comment
@Serg, я добавил больше деталей в свой ответ, чтобы шаг за шагом показать, как это сделать. Если это по-прежнему не работает, вы можете сделать это с помощью Flash, используя пример загрузки ВКонтакте - person Old Pro; 20.04.2012
comment
@OldPro Единственная (неразрешимая) проблема здесь заключается в том, чтобы обойти ту же политику происхождения. Что вы предлагаете по этому поводу? Используете postMessage? Но тогда вам придется иметь html/js прокси на сервере ВК, не так ли? - person Dmytro Shevchenko; 20.04.2012
comment
@Shedal, скрытая информация, стоящая за этой информацией, заключается в том, что SameServer просто нереально настроить так, чтобы он не предоставлял решение проблемы OP. Здесь SameServer — это ВКонтакте, а ВКонтакте предлагает решение. Теперь их решение использует Flash, но, как оказалось, их решение iFrame тоже должно работать. Вам не нужен html/js прокси в ВК, вам просто нужен iFrame в ВК, который будет общаться с вашим окном на вашем сайте (используя postMessage или какой-то другой механизм). Это то, что обеспечивает поддержка iFrame ВКонтакте. - person Old Pro; 20.04.2012
comment
@OldPro Ты понимаешь по-русски? поддержка iFrame предназначена для приложений, работающих в iframe, где основной окно — это сам ВК. По-моему, у Серга наоборот, т.е. у него есть страница, которая открывается ВК в iFrame. Сергей, можете подтвердить? - person Dmytro Shevchenko; 20.04.2012
comment
@Shedal, нет, я не понимаю по-русски. Согласно документации и примерам на английском языке, поддержка iFrame предназначена для встраивания iFrame VK в вашу страницу на вашем сервере, чтобы ваша страница могла получить доступ к VK. - person Old Pro; 06.05.2012

Я вижу только два основных подхода к этой проблеме: проксирование на стороне сервера и межсайтовая загрузка на стороне клиента/javascript. Ваши подходы 1 и 3 — это одно и то же. На самом деле не имеет значения, используете ли вы файлы POST с помощью cURL или nginx - в любом случае, не с точки зрения производительности. Итак, если вы уже реализовали подход 1 из своего вопроса, я не вижу причин переходить на 3.

Что касается javascript и политики одинакового происхождения, кажется, что есть много способов достичь вашей цели, но во всех этих случаях либо ваш сценарий должен поддерживаться разработчиками SomeServer, либо у вас должен быть какой-то доступ к SomeServer. Вот примерный список возможностей:

  • CORS — вашему домену должен быть разрешен доступ к домену SomeServer;
  • Изменение document.domain — для этого требуется, чтобы ваша страница и целевая страница размещены на поддоменах одного домена;
  • Использование флэш-загрузчика (например, SWFUpload) — по-прежнему требуется, чтобы ваш домен был разрешен через междоменную политику, в случае Flash — через crossdomain.xml в корне домена SomeServer;
  • xdcomm (например, EasyXDM) – требуется, чтобы вы могли загрузить хотя бы одну HTML-страницу в целевой домен. Затем эту страницу можно использовать в качестве прокси-сервера javascript для ваших манипуляций с iframe SomeServer.

Последнее на самом деле может быть реальной возможностью для вас, поскольку вы можете загружать файлы на SomeServer. Но, конечно, это зависит от того, как это реализовано — например, если есть другой домен, с которого обслуживаются файлы, или если есть какие-то меры безопасности, которые не позволят вам размещать html-файлы, это может не сработать.

person Dmytro Shevchenko    schedule 18.04.2012
comment
SomeServer — это vk, если это имеет смысл. Для загрузки файлов они сначала предоставляют доступный URL-адрес сервера CDN, а затем вы загружаете файлы на этот URL-адрес. Он принимает только изображения/аудио/видео, без html/js или чего-то еще. Так что я бы откатился к первоначальному вопросу о настройке nginx. Обход php/tmp storage/curl сэкономил бы много ресурсов сервера, по крайней мере, с потоками памяти curl/php. Так что я все еще смотрю на этот подход. - person Serge; 18.04.2012
comment
У меня сложилось впечатление, что ваше веб-приложение было основным, и вы загружали SomeServer в iframe. Но позволяет ли это ВК? Можете ли вы добавить более подробную информацию о том, что представляет собой ваше приложение (автономный сайт? приложение VK iframe?), и как именно оно использует VK? - person Dmytro Shevchenko; 18.04.2012
comment
Это далеко выходит за рамки первоначального вопроса. @Shedal, вы можете связаться со мной в Skype или написать мне по электронной почте, чтобы обсудить само приложение. Вопрос о загрузке файлов проксированием nginx остается открытым. - person Serge; 18.04.2012
comment
@Serg Я просто подумал, что в некоторых случаях магия JS может быть не совсем исключена, в зависимости от того, как настроено ваше приложение. Что касается проксирования nginx — пробовали ли вы использовать HttpProxyModule? Например. как описано в этом ответе. - person Dmytro Shevchenko; 18.04.2012
comment
спасибо за другую ссылку ответа. Похоже, что пересылка данных POST противоречит спецификации HTTP. Возможно, мне следует придерживаться первоначальной стратегии «человек посередине»: сохранить загрузку пользователя на MyWebApp, а затем свернуть ее на SomeServer. - person Serge; 18.04.2012
comment
@Serg На самом деле, HttpProxyModule перенаправляет запросы на стороне сервера, а не через перенаправление заголовка ответа HTTP 301/302. Таким образом, сообщения POST будут перенаправлены таким образом. Цитата Мэтью из спецификации должна была объяснить, почему возникла первоначальная проблема - JihoKang пытался перенаправить с помощью перезаписи nginx, которая использует заголовок ответа HTTP. В чем я не совсем уверен, так это в том, получит ли браузер клиента ответ JSON (при использовании HttpProxyModule). С другой стороны, я действительно не понимаю, почему бы и нет. В любом случае, вам придется его протестировать. - person Dmytro Shevchenko; 18.04.2012
comment
Тогда возникает следующий вопрос: как позволить nginx обрабатывать ответ на запрос, который он перенаправил на другой сервер, вместо того, чтобы просто передать его запрашивающему браузеру? Nginx in the middle :) - person Serge; 19.04.2012
comment
В чем проблема передать ответ обратно в браузер? - person Dmytro Shevchenko; 19.04.2012
comment
на самом деле это не проблема: с этой настройкой JS сможет передать ответ JSON обратно в myWebApp — поскольку он только что получил это от него: тот же источник. Просто несовершенство: зачем передавать ответ браузеру, а не JS/ajax обратно, когда у нас только что были все необходимые данные внутри прокси-модуля? знак равно - person Serge; 19.04.2012
comment
Да, но я думаю, что вы сейчас слишком многого хотите ;) Прокси - это именно то, что есть - прокси. Это прозрачно как для клиента, так и для вашего приложения. Если вам нужна дополнительная логика, вы можете остановиться на варианте № 1, где вы реализуете часть проксирования вручную. - person Dmytro Shevchenko; 19.04.2012