Универсальная процедура по загрузке файла из интернета

Публикация № 622811

Программирование - Практика программирования

универсальный шаблон библиотека

11
Передаем в процедуру всего два параметра: откуда взять и куда положить. Остальное она сделает сама

Данная процедура сама разберет адрес скачиваемого файла на составные части, подставит их в объект HTTPСоединение и загрузит файл.
Умеет скачивать по незащищенному и защищенному протоколам (без авторизации). Для остальных случаев можно использовать ее в качестве шаблона.
  

Процедура ЗагрузитьФайлИзИнтернета(АдресФайлаВИнтернете, АдресФайлаНаКлиенте)
	
	Если Найти(НРег(АдресФайлаВИнтернете),"https://") = 1 Тогда
		ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL;
	Иначе
		ЗащищенноеСоединение = Неопределено;
	КонецЕсли;
	
	// "http://static.1c.ru/images/logo.png" -> "static.1c.ru/images/logo.png"
	АдресБезHTTP = СтрЗаменить(АдресФайлаВИнтернете, "//", Символы.ПС);
	АдресБезHTTP = СтрПолучитьСтроку(АдресБезHTTP, СтрЧислоСтрок(АдресБезHTTP));
	
	// "static.1c.ru/images/logo.png" -> "static.1c.ru"
	АдресСервера = СтрПолучитьСтроку(СтрЗаменить(АдресБезHTTP, "/", Символы.ПС), 1);
	
	// "static.1c.ru/images/logo.png" -> "/images/logo.png"
	ПутьКФайлуВнутриДомена = Сред(АдресБезHTTP, Найти(АдресБезHTTP, "/"));
	
	// скачиваем на диск
	Соединение = Новый HTTPСоединение(АдресСервера, ,,,, 3, ЗащищенноеСоединение);
	Соединение.Получить(ПутьКФайлуВнутриДомена, АдресФайлаНаКлиенте);	
	
КонецПроцедуры

Тестировалась на платформе 8.3.8 в режиме совместимости 8.2.13, а также с отключенным режимом совместимости.
Прикладываю обработку, которая в качестве примера загружает картинки по защищенному и незащищенному протоколам. Обработка для примера написана на управляемых формах, но процедура работает также и на обычных формах.

11

Скачать файлы

Наименование Файл Версия Размер
Загрузка файла из интернета (пример)
.epf 7,12Kb
17.05.17
9
.epf 7,12Kb 9 Скачать

См. также

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. Diversus 1942 18.05.17 10:00 Сейчас в теме
Процедура не универсальна. Она, например, не анализирует то, что было на веб-сервере перемещено и отдает статус 301 (страница, которая была перемещена и по старому адресу происходит редирект).

Вот универсальная, автор Поручик (если не ошибаюсь):
Функция ПолучитьСодержимоеВебАдреса(Знач СерверПриемник, Знач АдресСтраницы = "",
                Знач ПараметрыСоединения = Неопределено, ЗаголовкиHTTP = Неопределено,
                Знач ПолучитьКакДвоичныеДанные = Ложь, Знач ЗащищенноеСоединение = Ложь) Экспорт
    Перем ИмяФайлаОтветаКодированное, ИмяФайлаОтвета, Порт, Логин, Пользователь, Пароль, Прокси, Таймаут;

    Если Не ЗначениеЗаполнено(СерверПриемник) Тогда Возврат Неопределено; КонецЕсли;
    Если ТипЗнч(ЗаголовкиHTTP) <> Тип("Соответствие") Тогда ЗаголовкиHTTP = Новый Соответствие; КонецЕсли;
    Если Найти(Нрег(СерверПриемник), "https://") = 1 Тогда ЗащищенноеСоединение = Истина; КонецЕсли;

    Протокол = ?(Найти(Нрег(СерверПриемник), "https://") = 1 ИЛИ ЗащищенноеСоединение, "https://", "http://");
    Если Лев(НРег(СерверПриемник), СтрДлина(Протокол)) = Протокол Тогда
        СерверПриемник = Сред(СерверПриемник, СтрДлина(Протокол) + 1);
    КонецЕсли;

    Если НЕ ЗначениеЗаполнено(АдресСтраницы) Тогда
        Позиция = Найти(СерверПриемник, "/");
        Если Позиция > 0 Тогда
            АдресСтраницы = Сред(СерверПриемник, Позиция, СтрДлина(СерверПриемник));
            СерверПриемник = Лев(СерверПриемник, Позиция - 1);
        Иначе
            АдресСтраницы = "/";
        КонецЕсли;
    КонецЕсли;

    СерверПриемник = СтрЗаменить(СерверПриемник, "/", "");

    //Выделяем порт из доменного имени
    ПозицияДвоеточия = Найти(СерверПриемник, ":");
    Если ПозицияДвоеточия > 0 Тогда
        Порт = Число(Сред(СерверПриемник, ПозицияДвоеточия + 1));
        СерверПриемник = Лев(СерверПриемник, ПозицияДвоеточия - 1);
    КонецЕсли;

    Если ТипЗнч(ПараметрыСоединения) = Тип("Структура") Тогда
        Для каждого КлючЗначение из ПараметрыСоединения Цикл
            Значение = КлючЗначение.Значение; Выполнить(КлючЗначение.Ключ + " = Значение;");
        КонецЦикла;
        Пользователь = ?(ЗначениеЗаполнено(Пользователь), Пользователь, Логин);
    КонецЕсли;
    НТТР = Новый HTTPСоединение(СерверПриемник, Порт, Пользователь, Пароль, Прокси, Таймаут,
                        ?(ЗащищенноеСоединение, Новый ЗащищенноеСоединениеOpenSSL(), Неопределено));

    //Ответ от сервера получим в возвращаемом значении типа HTTPОтвет
    ОтветHTTP = НТТР.Получить(Новый HTTPЗапрос(АдресСтраницы, ЗаголовкиHTTP)); //
    ОшибкаЗапроса = (ОтветHTTP.КодСостояния >= 400);

    //После получения ответа сервера необходимо проверить статус или код состояния.
    //http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
    //Если сервер вернул один из статусов переадресации
    //301 Moved Permanently («перемещено навсегда») или 302 Moved Temporarily («перемещено временно»),
    //то в этом случае можно попытаться перейти на ресурс, на который переадресовал сервер
    Если ОтветHTTP.КодСостояния = 301 или ОтветHTTP.КодСостояния = 302 Тогда

        Если ОтветHTTP.Заголовки.Количество() > 0 Тогда
            //Адрес страницы переадресации содержится в поле Location заголовка ответа
            АдресСтраницы = ОтветHTTP.Заголовки["Location"]; //
            Если ЗначениеЗаполнено(АдресСтраницы) Тогда
                Если Найти(НРег(АдресСтраницы), "http://") = 0 И Найти(НРег(АдресСтраницы), "https://") = 0 Тогда
                    АдресСтраницы = ?(Лев(АдресСтраницы, 1) = "/", Сред(АдресСтраницы, 2), АдресСтраницы);
                    Если Найти(АдресСтраницы, СерверПриемник + "/") = 0  Тогда
                        АдресСтраницы = Протокол + СерверПриемник + ?(ЗначениеЗаполнено(Порт), ":" + Порт, "") + "/" + АдресСтраницы;
                    КонецЕсли;
                КонецЕсли;

                //Если сервер вернул cookies (http://ru.wikipedia.org/wiki/HTTP_cookie, http://www.faqs.org/rfcs/rfc6265.html?#41;,
                //вставим их в заголовки для передачи на страницу перехода
                Куки = ОтветHTTP.Заголовки["Set-Cookie"];//
                Если ЗначениеЗаполнено(Куки) Тогда ЗаголовкиHTTP.Вставить("Cookie", Куки); КонецЕсли;

                //Рекурсивный вызов
                Возврат ПолучитьСодержимоеВебАдреса(АдресСтраницы, , , ЗаголовкиHTTP, ПолучитьКакДвоичныеДанные, ЗащищенноеСоединение);//

            КонецЕсли;
        КонецЕсли;

    ИначеЕсли ОтветHTTP.КодСостояния >= 100 И ОтветHTTP.КодСостояния <= 200 Тогда
        //Статус ответа в интервале между 100 и 200 Ok говорит о нормальном результате HTTP-запроса
        Если ОтветHTTP.Заголовки.Количество() > 0 Тогда
            ТипСодержимого = ОтветHTTP.Заголовки["Content-Type"];
            //http://ru.wikipedia.org/wiki/Список_MIME-типов
            Если Найти(ТипСодержимого, "text/") = 1 ИЛИ Найти(ТипСодержимого, "/javascript")
                ИЛИ Найти(ТипСодержимого, "+xml") ИЛИ Найти(ТипСодержимого, "/xml") <> 0 ИЛИ Найти(ТипСодержимого, "/json") <> 0 Тогда
                ПолучитьКакДвоичныеДанные = Ложь;
            ИначеЕсли Найти(ТипСодержимого, "image/") = 1 ИЛИ Найти(ТипСодержимого, "video/") = 1 
                ИЛИ Найти(ТипСодержимого, "application/") = 1 ИЛИ Найти(ТипСодержимого, "audio/") = 1 Тогда
                //Если содержимое полученного ответа представляет собой изображение, видео, приложение,
                //возвращаем двоичные данные, так как возвращать в виде строки не имеет смысла.
                ПолучитьКакДвоичныеДанные = Истина;
            КонецЕсли;
            //Некоторые сервера возвращают в типе содержимого имя отданного файла, например image/png; name="Имя файла.png"
            //или отдают в заголовке Content-Disposition: attachment; filename=Имя файла.png (http://www.http11.ru/post.php?post=2)
            Если ОтветHTTP.Заголовки["Content-Disposition"] <> Неопределено Тогда
                ТипСодержимого = ОтветHTTP.Заголовки["Content-Disposition"];
            КонецЕсли;
            ТипСодержимого = СтрЗаменить(СтрЗаменить(ТипСодержимого, """", ""), "'", "");

            //в ключе filename*=UTF-8'' содержится url-кодированное имя файла
            ПозицияИмениФайла = Найти(ТипСодержимого, "filename*=UTF-8");
            Если ПозицияИмениФайла <> 0 Тогда
                ИмяФайлаОтветаКодированное = Сред(ТипСодержимого, ПозицияИмениФайла + СтрДлина("filename*=UTF-8"));
                ПозицияДвоеточия = Найти(ИмяФайлаОтветаКодированное, ";");
                Если ПозицияДвоеточия <> 0 Тогда
                    ИмяФайлаОтветаКодированное = Лев(ИмяФайлаОтветаКодированное, ПозицияДвоеточия - 1);
                КонецЕсли;
            КонецЕсли;

            //в ключе filename= содержится обычное имя файла
            ПозицияИмениФайла = Найти(ТипСодержимого, "name=");
            Если ПозицияИмениФайла <> 0 Тогда
                ИмяФайлаОтвета = Сред(ТипСодержимого, ПозицияИмениФайла + СтрДлина("name="));
                ПозицияДвоеточия = Найти(ИмяФайлаОтвета, ";");
                Если ПозицияДвоеточия <> 0 Тогда
                    ИмяФайлаОтвета = Лев(ИмяФайлаОтвета, ПозицияДвоеточия - 1);
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;

    ЗаголовкиHTTP = ОтветHTTP.Заголовки;
    //Добавляем в заголовки ответа код состояния (ответа) HTTP-сервера и имя файла содержимого, если есть.
    ЗаголовкиHTTP.Вставить("StatusCode", ОтветHTTP.КодСостояния);
    Если ЗначениеЗаполнено(ИмяФайлаОтвета) Тогда ЗаголовкиHTTP.Вставить("FileName", ИмяФайлаОтвета); КонецЕсли;
    Если ЗначениеЗаполнено(ИмяФайлаОтветаКодированное) Тогда
        ЗаголовкиHTTP.Вставить("EncodeFileName", ИмяФайлаОтветаКодированное);
    КонецЕсли;

    Если ОшибкаЗапроса ИЛИ НЕ ПолучитьКакДвоичныеДанные Тогда Возврат ОтветHTTP.ПолучитьТелоКакСтроку(); КонецЕсли;
    Возврат ОтветHTTP.ПолучитьТелоКакДвоичныеДанные();

КонецФункции // ПолучитьСодержимоеВебАдреса()
Показать
kote; SolovieFF; json; +3 Ответить
2. json 18.05.17 21:30 Сейчас в теме
(1) спасибо. Сохранил себе в копилку очереную процедуру от Поручика
Оставьте свое сообщение