Выполнение POST-запросов и загрузки файлов с помощью URLSession
За прошедшие годы встроенный в Foundation URLSession API превратился в универсальный и очень мощный сетевой инструмент, настолько, что часто сторонние библиотеки теперь больше не требуются для выполнения стандартных сетевых вызовов HTTP простым и понятным способом.
Хотя многие из удобных API-интерфейсов, с которыми поставляется URLSession, ориентированы на GET-запросы, используемые для получения данных, в этой статье давайте рассмотрим, как именно можно использовать и другие методы HTTP, в частности, как различные типы POST-запросов могут выполняться без любых внешних зависимостей.
Данные и задачи загрузки
Возможно, самый простой способ использовать URLSession для выполнения POST- запроса — это использовать основанные на URLRequest перегрузке различных API-интерфейсов dataTask (которые поддерживают делегаты и колбеки, работающие на клоужерах, а также Combine). Помимо прочего, URLRequest позволяет нам настроить, какой httpMethod должен использовать данный сетевой вызов, а также другие полезные параметры, например, какие данные httpBody отправлять и какой cachePolicy использовать. Например:
struct Networking { var urlSession = URLSession.shared func sendPostRequest( to url: URL, body: Data, then handler: @escaping (Result<Data, Error>) -> Void ) { // To ensure that our request is always sent, we tell // the system to ignore all local cache data: var request = URLRequest( url: url, cachePolicy: .reloadIgnoringLocalCacheData ) request.httpMethod = "POST" request.httpBody = body let task = urlSession.dataTask( with: request, completionHandler: { data, response, error in // Validate response and call handler ... } ) task.resume() } }
В зависимости от сервера, на который отправляется наш POST-запрос, мы также можем при желании дополнительно настроить наш экземпляр URLRequest, предоставив ему, например, заголовок Content-Type.
В качестве альтернативы мы могли бы вместо этого использовать API uploadTask для создания собственной задачи запроса, позволяющей нам загружать данные, пока приложение находится в фоновом режиме, и обеспечивающей встроенную поддержку для прикрепления массива данных непосредственно к самой задаче:
struct Networking { var urlSession = URLSession.shared func sendPostRequest( to url: URL, body: Data, then handler: @escaping (Result<Data, Error>) -> Void ) { var request = URLRequest( url: url, cachePolicy: .reloadIgnoringLocalCacheData ) request.httpMethod = "POST" let task = urlSession.uploadTask( with: request, from: body, completionHandler: { data, response, error in // Validate response and call handler ... } ) task.resume() } }
Наблюдение за обновлениями прогресса
Хотя любой из двух вышеперечисленных подходов будет отлично работать при отправке меньших объемов данных как часть POST-запроса, иногда нам может потребоваться загрузить файл, который может быть довольно большим (даже что-то простое, например изображение, может весить несколько мегабайт). При этом мы, скорее всего захотим чтобы пользователь мог отслеживать обновление прогресса в реальном времени, иначе пользовательский интерфейс нашего приложения может работать медленно или даже совсем не отвечать на запрос.
К сожалению, ни один из API-интерфейсов URLSession, работающих на замыканиях или Combine, не предлагает прямой поддержки для наблюдения за текущим прогрессом запроса, но, к счастью, это то, что мы можем довольно легко реализовать, используя старый добрый шаблон делегирования.
Чтобы наглядно это продемонстрировать, давайте создадим класс FileUploader (он должен быть подклассом NSObject Objective-C).
class FileUploader: NSObject { // We'll define a few type aliases to make our code easier to read: typealias Percentage = Double typealias ProgressHandler = (Percentage) -> Void typealias CompletionHandler = (Result<Void, Error>) -> Void // Creating our custom URLSession instance. We'll do it lazily // to enable 'self' to be passed as the session's delegate: private lazy var urlSession = URLSession( configuration: .default, delegate: self, delegateQueue: .main ) private var progressHandlersByTaskID = [Int : ProgressHandler]() func uploadFile( at fileURL: URL, to targetURL: URL, progressHandler: @escaping ProgressHandler, completionHandler: @escaping CompletionHandler ) { var request = URLRequest( url: targetURL, cachePolicy: .reloadIgnoringLocalCacheData ) request.httpMethod = "POST" let task = urlSession.uploadTask( with: request, fromFile: fileURL, completionHandler: { data, response, error in // Validate response and call handler ... } ) progressHandlersByTaskID[task.taskIdentifier] = progressHandler task.resume() } }
Затем давайте реализуем протокол URLSessionTaskDelegate, который представляет собой специализированную версию базового протокола URLSessionDelegate, который добавляет несколько дополнительных методов, позволяющих нам отслеживать события, связанные с конкретной задачей. В этом случае мы хотим получать уведомления только о том, когда был обновлен ход выполнения данной задачи URLSessionTask, и это можно сделать, реализовав следующий метод:
extension FileUploader: URLSessionTaskDelegate { func urlSession( _ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64 ) { let progress = Double(totalBytesSent) / Double(totalBytesExpectedToSend) let handler = progressHandlersByTaskID[task.taskIdentifier] handler?(progress) } }
С учетом вышеизложенного теперь мы сможем использовать процентные значения, передаваемые в каждый клоужер progressHandler для управления любым компонентом пользовательского интерфейса, который мы хотим использовать для визуализации хода загрузки, например, ProgressView, UIProgressView или NSProgressIndicator.
Показатель загрузки процесса во времени
Наконец, давайте также посмотрим, как можно преобразовать указанный выше FileUploader для использования Combine вместо нескольких замыканий. В конце концов, дизайн Combine, ориентированный на «значения с течением времени», идеально подходит для моделирования обновлений прогресса, поскольку мы хотим отправить какие-то процентные значения с течением времени, а затем закончить событие завершением, что и является тем, что делает publisher Combine.
Хотя мы могли бы реализовать эту функцию с помощью кастомного publisher, давайте в данном случае воспользуемся CurrentValueSubject, который предоставляет встроенный способ отправки значений, которые затем кэшируются и отправляются каждому новому подписчику. Таким образом, мы можем связать каждую задачу загрузки с заданным субъектом (точно так же, как мы ранее хранили каждый клоужер progressHandler), а затем вернуть этот субъект в качестве publisher с помощью API eraseToAnyPublisher — например:
class FileUploader: NSObject { typealias Percentage = Double typealias Publisher = AnyPublisher<Percentage, Error> private typealias Subject = CurrentValueSubject<Percentage, Error> private lazy var urlSession = URLSession( configuration: .default, delegate: self, delegateQueue: .main ) private var subjectsByTaskID = [Int : Subject]() func uploadFile(at fileURL: URL, to targetURL: URL) -> Publisher { var request = URLRequest( url: targetURL, cachePolicy: .reloadIgnoringLocalCacheData ) request.httpMethod = "POST" let subject = Subject(0) var removeSubject: (() -> Void)? let task = urlSession.uploadTask( with: request, fromFile: fileURL, completionHandler: { data, response, error in // Validate response and send completion ... subject.send(completion: .finished) removeSubject?() } ) subjectsByTaskID[task.taskIdentifier] = subject removeSubject = { [weak self] in self?. subjectsByTaskID.removeValue(forKey: task.taskIdentifier) } task.resume() return subject.eraseToAnyPublisher() } }
Теперь все, что осталось — это обновить нашу реализацию URLSessionTaskDelegate для отправки каждого значения прогресса субъекту, связанному с рассматриваемой задачей, вместо вызова замыкания:
extension FileUploader: URLSessionTaskDelegate { func urlSession( _ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64 ) { let progress = Double(totalBytesSent) / Double(totalBytesExpectedToSend) let subject = subjectsByTaskID[task.taskIdentifier] subject?.send(progress) } }
Теперь мы можем легко выполнять как более простые POST-запросы, так и загрузку файлов с отображением прогресса загрузки, используя либо Combine, либо API на основе замыканий. Классяче!
Оригинал статьи
Как сделать POST-запрос с помощью cURL на Ubuntu / Debian
Содержание
- Что такое cURL?
- Установка cURL на Ubuntu / Debian
- Как сделать POST-запрос с помощью cURL на Ubuntu / Debian
- Заключение
Здравствуйте, друзья. Команда cURL — это полезная команда особенно для сетевых подключений в терминале. В этом посте вы узнаете, как сделать POST-запрос с помощью cURL. Таким образом, вы сможете быстро выполнить несколько тестов по отправке данных.
Что такое cURL?
Согласно сайту проекта
CURL — ЭТО ИНСТРУМЕНТ КОМАНДНОЙ СТРОКИ И БИБЛИОТЕКА ДЛЯ ПЕРЕДАЧИ ДАННЫХ С ПОМОЩЬЮ URL (АДРЕСОВ).
Также это инструмент не имеющий графического интерфейса, но простой в использовании. Кроме того, он имеет открытый исходный код, что позволяет легко проводить аудит ПО.
cURL доступен практически в любом дистрибутиве Linux, а в некоторых из них даже установлен по умолчанию. Поэтому получить его не составит труда.
Данный инструмент используется в командных строках или скриптах для передачи данных. Его применение простирается от компьютеров, до автомобилей, телевизоров и других устройств, которым он необходим.
И так поехали.
Установка cURL на Ubuntu / Debian
Как я уже говорил, cURL доступен практически для любой системы и лучше всего его устанавливать из официальных репозиториев. Итак, чтобы установить его, откройте терминал и выполните следующие команды.
sudo apt update
sudo apt upgrade
Это так быстро и просто.
Теперь проверьте установленную версию.
curl --version
Образец ответа терминала.
Выполнение POST-запроса с помощью cURL на Ubuntu / DebianТеперь мы можем продолжить.
Как сделать POST-запрос с помощью cURL на Ubuntu / Debian
Идея заключается в отправке данных с помощью HTTP POST. Это очень удобно для скриптов и конфигураций. В целом синтаксис выглядит следующим образом.
curl -X POST [options] [URL]
Не обязательно, но обычно POST-запрос выполняется при использовании HTML-форм.
Если вы хотите отправить некоторые данные подобным образом, вы также можете использовать параметр -d.
curl -d "name=Angelo&website=unixcop" -X POST https://setiwik.ru/
В этом случае информация отправляется на определенный адрес. Для этого запрашивается Имя и Веб-сайт. Как видите, таким образом, включаются некоторые данные. Для этого обратите внимание, что вам нужен точный адрес получателя данных.
Существует опция -H, с помощью которой вы можете указать формат, в котором будут отправлены данные. Например, если вы хотите отправить информацию в HTML-форме с форматом application/x-www-form-urlencoded, то нужно указать его.
curl -X POST https://setiwik.ru/form -H "Content-Type: application/x-www-form-urlencoded" -d "name=Angelo1&[email protected]"
Таким образом, cURL уже знает в каком формате передавать данные. Другой пример с этим же параметром — в формате JSON.
curl -X POST https://setiwik.ru/json -H 'Content-Type: application/json' -d '{"name": "angelo", "password": "21125"}'.
Повторяю, вы должны знать в каком формате сайт будет обрабатывать запрос, прежде чем определять команду curl.
Еще один полезный пример — обработка XML-файлов.
curl -X POST https://setiwik.ru/echo/post/xml -H "Content-Type: application/xml" -d "<Data><Id>1</Id><Username>setiwik</Username></Data>"
Или отправить файл. Для этого случая curl по умолчанию включает отправку формата в зависимости от файла, но вы должны указать полный путь к файлу. Вы также можете указать конкретный тип с помощью опции -H.
curl -d @[путь] https://setiwik.ru/server
Как видите, процесс прост.
Заключение
В этом посте вы узнали как использовать cURL для отправки данных с помощью POST. Надеюсь вам понравилось и вы сможете применить это в своих проектах.
rest — Ошибка при выполнении почтового запроса весной mvc
Задавать вопрос
спросил
Изменено 7 лет, 4 месяца назад
Просмотрено 1к раз
При выполнении следующего почтового запроса в почтальоне:
http://localhost:8080/FinalSmsApi/rest/requestSms/hello
с параметрами имя пользователя, пароль и телефон. Я получаю следующую ошибку:
HTTP-статус 415: сервер отклонил этот запрос, поскольку объект запроса находится в формате, не поддерживаемом запрошенным ресурсом для запрошенного метода.
Это контроллер:
@RestController открытый класс MainController1 { @RequestMapping (значение = "/ привет", метод = POST, потребляет = "приложение/json") public void Register(@RequestParam(value = "username") Строковое имя пользователя, @RequestParam(value = "password") Строковый пароль, @RequestParam(value = "phone") String phone) {...} }
Использование версии Spring 4.
- пружина
- остальные
- пружина-MVC
Состояние HTTP 415: сервер отклонил этот запрос…
Это означает, что ваша конечная точка не может обработать переданное тело запроса
. Эта ошибка имеет две основные причины: либо вы , а не указали тип тела вашего запроса, либо вы передали неверные данные.
Путем добавления Content-Type
в заголовки вашего запроса, эта проблема будет решена:
Content-Type: application/json
Кроме того, вы не фиксируете тело запроса в методе public void Register(..)
. Если вы планируете пойти по этому пути, лучше отказаться от атрибута Consumers
и передать все параметры с Query Parameters
, как вы это сделали.
Другой подход заключается в определении класса ресурсов, например:
public class User { частное строковое имя пользователя; закрытый строковый пароль; личный телефон String; // геттеры и сеттеры }
Затем измените свой контроллер для захвата тела запроса, например:
@RequestMapping (значение = "/ привет", метод = POST, потребляет = "приложение/json") public void Register(@RequestBody User user) {...}
И, наконец, отправьте представление JSON
вместе с вашим запросом:
curl -XPOST -H'Content-Type: application/json' --data '{"username": "", "password": "" , "телефон": ""}' http://localhost:8080/hello7
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google Зарегистрироваться через Facebook Зарегистрируйтесь, используя электронную почту и парольОпубликовать как гость
Электронная почтаОбязательно, но не отображается
Опубликовать как гость
Электронная почтаТребуется, но не отображается
Нажимая «Опубликовать свой ответ», вы соглашаетесь с нашими условиями обслуживания и подтверждаете, что прочитали и поняли нашу политику конфиденциальности и кодекс поведения.
Отправка запроса POST в REST API | Junos OS
Используйте запрос HTTP POST для отправки одного или нескольких запросов RPC к REST API. Вы можете использовать запрос POST для настройки устройства.
Для одной команды rpc
общий формат конечных точек:
схема://имя-устройства:порт/rpc/метод[@атрибуты]/параметры
схема 9 0042 :
http
илиhttps
метод
: Имя любой команды Junos OSrpc
. Имя методаparams
: Необязательные значения параметров (имя[=значение]
).
Для аутентификации запроса отправьте имя пользователя и пароль в кодировке base64, включенные в заголовок авторизации:
curl -u "имя пользователя:пароль" http://имя-устройства:порт/rpc/get-interface-information
Чтобы указать данные rpc
в качестве строки запроса в URI для запросов POST, отправьте данные запроса в теле POST. В таких случаях вы можете указать Content-Type
как text/plain
или application/xml
, как показано в этих эквивалентных вызовах cURL:
curl -u "имя пользователя: пароль" http://имя-устройства :port/rpc/get-interface-information --header "Content-Type: text/plain" –d "interface-name=cbp0" curl -u "имя пользователя: пароль" http://имя-устройства:порт/rpc/get-interface-information --header "Тип содержимого: application/xml" –d "cbp0"
Как для одной, так и для нескольких команд RPC заголовки HTTP Accept могут использоваться для указания формата возврата с использованием одного из следующих значений Content-Type:
Например, следующий вызов cURL указывает выходной формат JSON:
curl -u "имя пользователя: пароль" http://имя-устройства:порт/rpc -d--header "Accept: application/json"
Вы также можете указать формат вывода, используя необязательный параметр формат
атрибут:
curl -u "имя пользователя:пароль" http://имя-устройства:порт/rpc -d "Примечание:"
Content-Type по умолчанию для Запросы POST, содержащие аргументы в теле, имеют вид application/xml. Если вы хотите использовать любой другой контент, например строку запроса, вы можете указать Content-Type text/plain. Укажите атрибут формата в командах конфигурации.
При выполнении нескольких команд rpc
в одном запросе общий формат конечной точки:
схема://имя-устройства:порт/rpc
RPC должны предоставляться в виде данных XML в теле POST. Content-Type для ответа — составной/смешанный, с границей и подтипом, связанным с выходными данными каждого выполнения RPC. Формат, указанный в заголовке Accept, используется в качестве выходного формата для каждого RPC, если в них отсутствует атрибут формата
. Если заголовок Accept не указан и в заданном RPC не указан атрибут формата
, выходным форматом по умолчанию является XML. Например, чтобы отправить один HTTP-запрос для выполнения RPC get-software-information
и get-interface-information
, отправьте запрос POST на /rpc
с «Auth: Basic
, «Content-Type: application/xml»
. Тело POST будет содержать:
Вот вызов cURL с использованием этого тела POST:
curl -u "имя пользователя: пароль" http: //имя-устройства:порт/rpc -d ""
Вывод запроса, содержащего XML по умолчанию, будет выглядеть следующим образом:
HTTP/1.1 200 OK Content-Type: составной/смешанный; граница = fkj49sn38dcn3 Передача-кодирование: по частям Дата: Чт, 20 марта 2014 г., 11:01:27 по Гринвичу Сервер: lighttpd/1.4.32 --fkj49sn38dcn3 Тип содержимого: приложение/xml <информация о программном обеспечении> <имя-хоста>...имя-хоста> ... информация о программном обеспечении> --fkj49sn38dcn3 Тип содержимого: приложение/xml <информация об интерфейсе> <физический-интерфейс>...физический-интерфейс> информация об интерфейсе> --fkj49sn38dcn3--
Вы также можете указать выходной формат для каждого из элементов в теле POST.