Простой пример использования HTTP POST и использование ответа

Я хотел бы создать очень простое приложение C, которое выполняет HTTP-сообщение. Это потребует нескольких параметров и использует их для создания URL-адреса. Я просто хотел бы сделать простой HTTP POST и получить ответ без использования curl (библиотеки не установлены и не будут установлены на машине, которую это нужно запустить).

Псевдо-код:

  1. Процессы 2 args

  2. Поместите args в URL-адрес шаблона: http://api.somesite.com/apikey=ARG1&command=ARG2

  3. Сделать POST на сгенерированном URL-адресе

  4. Потребляйте ответ

Мои поиски Google и SO ничего не дали по этому поводу.

Сообщение имеет часть заголовка и тело сообщения, разделенное пустой строкой. Пустая строка ВСЕГДА нужна, даже если нет тела сообщения. Заголовок начинается с команды и имеет дополнительные строки пар значений, разделенных двоеточием и пробелом. Если есть тело сообщения, это может быть все, что вы хотите.

Строки в заголовке и пустая строка в конце заголовка должны заканчиваться парой возврата carreige and linefeed (см. Стиль разрыва строки заголовка HTTP ), поэтому именно эти строки имеют \ r \ n в конце.

URL-адрес имеет форму http://host:port/path?query_string

Существует два основных способа подачи запроса на веб-сайт:

  • GET: Строка запроса является необязательной, но, если она указана, должна быть достаточно короткой. Из-за этого заголовок может быть просто командой GET, и ничего больше. Образец сообщения может быть:

     GET /path?query_string HTTP/1.0\r\n \r\n 
  • POST: то, что обычно было бы в строке запроса, находится в тексте сообщения. Из-за этого заголовок должен включать атрибуты Content-Type: и Content-Length: а также команду POST. Образец сообщения может быть:

     POST /path HTTP/1.0\r\n Content-Type: text/plain\r\n Content-Length: 12\r\n \r\n query_string 

Итак, чтобы ответить на ваш вопрос: если URL-адрес, который вас интересует POSTing, это http://api.somesite.com/apikey=ARG1&command=ARG2, тогда нет ни строки тела или запроса, а, следовательно, нет причин для POST, потому что там нечего вставлять в тело сообщения, и поэтому ничего не вводить в Content-Type: и Content-Length:

Думаю, ты мог бы ПОСТ, если бы тебе действительно захотелось. В этом случае ваше сообщение будет выглядеть так:

 POST /apikey=ARG1&command=ARG2 HTTP/1.0\r\n \r\n 

Поэтому для отправки сообщения программе C необходимо:

  • создать сокет
  • найти IP-адрес
  • открыть розетку
  • отправить запрос
  • ждать ответа
  • закрыть розетку

Вызовы отправки и приема не обязательно будут отправлять / получать ВСЕ данные, которые вы им даете, – они возвратят количество фактически отправленных / полученных байтов. Вы можете называть их в цикле и отправлять / получать оставшуюся часть сообщения.

То, что я не делал в этом примере, – это любая реальная проверка ошибок – когда что-то не получается, я просто выхожу из программы. Дайте мне знать, если это сработает для вас:

 #include  /* printf, sprintf */ #include  /* exit */ #include  /* read, write, close */ #include  /* memcpy, memset */ #include  /* socket, connect */ #include  /* struct sockaddr_in, struct sockaddr */ #include  /* struct hostent, gethostbyname */ void error(const char *msg) { perror(msg); exit(0); } int main(int argc,char *argv[]) { /* first what are we going to send and where are we going to send it? */ int portno = 80; char *host = "api.somesite.com"; char *message_fmt = "POST /apikey=%s&command=%s HTTP/1.0\r\n\r\n"; struct hostent *server; struct sockaddr_in serv_addr; int sockfd, bytes, sent, received, total; char message[1024],response[4096]; if (argc < 3) { puts("Parameters:  "); exit(0); } /* fill in the parameters */ sprintf(message,message_fmt,argv[1],argv[2]); printf("Request:\n%s\n",message); /* create the socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); /* lookup the ip address */ server = gethostbyname(host); if (server == NULL) error("ERROR, no such host"); /* fill in the structure */ memset(&serv_addr,0,sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(portno); memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length); /* connect the socket */ if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) error("ERROR connecting"); /* send the request */ total = strlen(message); sent = 0; do { bytes = write(sockfd,message+sent,total-sent); if (bytes < 0) error("ERROR writing message to socket"); if (bytes == 0) break; sent+=bytes; } while (sent < total); /* receive the response */ memset(response,0,sizeof(response)); total = sizeof(response)-1; received = 0; do { bytes = read(sockfd,response+received,total-received); if (bytes < 0) error("ERROR reading response from socket"); if (bytes == 0) break; received+=bytes; } while (received < total); if (received == total) error("ERROR storing complete response from socket"); /* close the socket */ close(sockfd); /* process response */ printf("Response:\n%s\n",response); return 0; } 

Как и в другом ответе, 4096 байт не очень большой ответ. Я выбрал это число случайно, полагая, что ответ на ваш запрос будет коротким. Если он может быть большим, у вас есть два варианта:

  • прочитайте заголовок Content-Length: из ответа, а затем динамически выделяйте достаточное количество памяти для хранения всего ответа.
  • напишите ответ на файл по мере поступления частей

Дополнительная информация для ответа на вопрос, заданный в комментариях:

Что делать, если вы хотите получать данные POST в теле сообщения? Затем вам нужно включить заголовки Content-Type: и Content-Length:. Content-Length: фактическая длина всего после пустой строки, которая отделяет заголовок от тела.

Вот пример, который принимает следующие аргументы командной строки:

  • хозяин
  • порт
  • команда (GET или POST)
  • путь (не включая данные запроса)
  • данные запроса (помещаются в строку запроса для GET и в тело для POST)
  • список заголовков (Content-Length: автоматически, если используется POST)

Итак, для оригинального вопроса, который вы запускали:

 a.out api.somesite.com 80 GET "/apikey=ARG1&command=ARG2" 

И для вопроса, заданного в комментариях, которые вы запускаете:

 a.out api.somesite.com 80 POST / "name=ARG1&value=ARG2" "Content-Type: application/x-www-form-urlencoded" 

Вот код:

 #include  /* printf, sprintf */ #include  /* exit, atoi, malloc, free */ #include  /* read, write, close */ #include  /* memcpy, memset */ #include  /* socket, connect */ #include  /* struct sockaddr_in, struct sockaddr */ #include  /* struct hostent, gethostbyname */ void error(const char *msg) { perror(msg); exit(0); } int main(int argc,char *argv[]) { int i; /* first where are we going to send it? */ int portno = atoi(argv[2])>0?atoi(argv[2]):80; char *host = strlen(argv[1])>0?argv[1]:"localhost"; struct hostent *server; struct sockaddr_in serv_addr; int sockfd, bytes, sent, received, total, message_size; char *message, response[4096]; if (argc < 5) { puts("Parameters:     [ []]"); exit(0); } /* How big is the message? */ message_size=0; if(!strcmp(argv[3],"GET")) { message_size+=strlen("%s %s%s%s HTTP/1.0\r\n"); /* method */ message_size+=strlen(argv[3]); /* path */ message_size+=strlen(argv[4]); /* headers */ if(argc>5) message_size+=strlen(argv[5]); /* query string */ for(i=6;i5) message_size+=strlen("Content-Length: %d\r\n")+10; /* content length */ message_size+=strlen("\r\n"); /* blank line */ if(argc>5) message_size+=strlen(argv[5]); /* body */ } /* allocate space for the message */ message=malloc(message_size); /* fill in the parameters */ if(!strcmp(argv[3],"GET")) { if(argc>5) sprintf(message,"%s %s%s%s HTTP/1.0\r\n", strlen(argv[3])>0?argv[3]:"GET", /* method */ strlen(argv[4])>0?argv[4]:"/", /* path */ strlen(argv[5])>0?"?":"", /* ? */ strlen(argv[5])>0?argv[5]:""); /* query string */ else sprintf(message,"%s %s HTTP/1.0\r\n", strlen(argv[3])>0?argv[3]:"GET", /* method */ strlen(argv[4])>0?argv[4]:"/"); /* path */ for(i=6;i0?argv[3]:"POST", /* method */ strlen(argv[4])>0?argv[4]:"/"); /* path */ for(i=6;i5) sprintf(message+strlen(message),"Content-Length: %d\r\n",strlen(argv[5])); strcat(message,"\r\n"); /* blank line */ if(argc>5) strcat(message,argv[5]); /* body */ } /* What are we going to send? */ printf("Request:\n%s\n",message); /* create the socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); /* lookup the ip address */ server = gethostbyname(host); if (server == NULL) error("ERROR, no such host"); /* fill in the structure */ memset(&serv_addr,0,sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(portno); memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length); /* connect the socket */ if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) error("ERROR connecting"); /* send the request */ total = strlen(message); sent = 0; do { bytes = write(sockfd,message+sent,total-sent); if (bytes < 0) error("ERROR writing message to socket"); if (bytes == 0) break; sent+=bytes; } while (sent < total); /* receive the response */ memset(response,0,sizeof(response)); total = sizeof(response)-1; received = 0; do { bytes = read(sockfd,response+received,total-received); if (bytes < 0) error("ERROR reading response from socket"); if (bytes == 0) break; received+=bytes; } while (received < total); if (received == total) error("ERROR storing complete response from socket"); /* close the socket */ close(sockfd); /* process response */ printf("Response:\n%s\n",response); free(message); return 0; } 

Ответ Джерри велик. Однако он не обрабатывает большие ответы. Простое изменение для этого:

 memset(response, 0, sizeof(response)); total = sizeof(response)-1; received = 0; do { printf("RESPONSE: %s\n", response); // HANDLE RESPONSE CHUCK HERE BY, FOR EXAMPLE, SAVING TO A FILE. memset(response, 0, sizeof(response)); bytes = recv(sockfd, response, 1024, 0); if (bytes < 0) printf("ERROR reading response from socket"); if (bytes == 0) break; received+=bytes; } while (1); 

После нескольких недель исследований. Я придумал следующий код. Я считаю, что это минимальный минимум, необходимый для безопасного подключения к SSL на веб-сервере.

 #include  #include  #include  #include  #define APIKEY "YOUR_API_KEY" #define HOST "YOUR_WEB_SERVER_URI" #define PORT "443" int main() { // // Initialize the variables // BIO* bio; SSL* ssl; SSL_CTX* ctx; // // Registers the SSL/TLS ciphers and digests. // // Basically start the security layer. // SSL_library_init(); // // Creates a new SSL_CTX object as a framework to establish TLS/SSL // or DTLS enabled connections // ctx = SSL_CTX_new(SSLv23_client_method()); // // -> Error check // if (ctx == NULL) { printf("Ctx is null\n"); } // // Creates a new BIO chain consisting of an SSL BIO // bio = BIO_new_ssl_connect(ctx); // // Use the variable from the beginning of the file to create a // string that contains the URL to the site that you want to connect // to while also specifying the port. // BIO_set_conn_hostname(bio, HOST ":" PORT); // // Attempts to connect the supplied BIO // if(BIO_do_connect(bio) <= 0) { printf("Failed connection\n"); return 1; } else { printf("Connected\n"); } // // The bare minimum to make a HTTP request. // char* write_buf = "POST / HTTP/1.1\r\n" "Host: " HOST "\r\n" "Authorization: Basic " APIKEY "\r\n" "Connection: close\r\n" "\r\n"; // // Attempts to write len bytes from buf to BIO // if(BIO_write(bio, write_buf, strlen(write_buf)) <= 0) { // // Handle failed writes here // if(!BIO_should_retry(bio)) { // Not worth implementing, but worth knowing. } // // -> Let us know about the failed writes // printf("Failed write\n"); } // // Variables used to read the response from the server // int size; char buf[1024]; // // Read the response message // for(;;) { // // Get chunks of the response 1023 at the time. // size = BIO_read(bio, buf, 1023); // // If no more data, then exit the loop // if(size <= 0) { break; } // // Terminate the string with a 0, to let know C when the string // ends. // buf[size] = 0; // // -> Print out the response // printf("%s", buf); } // // Clean after ourselves // BIO_free_all(bio); SSL_CTX_free(ctx); return 0; } 

В приведенном выше коде будет подробно объяснено, как установить соединение TLS с удаленным сервером.

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

Когда дело касается самого запроса. Это не более чем запись запроса HTTP вручную.

Вы также можете найти в этой ссылке объяснение, как установить openSSL в вашей системе и как скомпилировать код, чтобы он использовал защищенную библиотеку .

Добавлена ​​ручка.
Добавлен заголовок узла.
Добавлена ​​поддержка linux / windows, протестирована (XP, WIN7).
ПРЕДУПРЕЖДЕНИЕ: ОШИБКА: «segmentation fault», если в качестве аргумента нет хоста, пути или порта.

 #include  /* printf, sprintf */ #include  /* exit, atoi, malloc, free */ #include  /* read, write, close */ #include  /* memcpy, memset */ #ifdef __linux__ #include  /* socket, connect */ #include  /* struct hostent, gethostbyname */ #include  /* struct sockaddr_in, struct sockaddr */ #elif _WIN32 #include  #include  #include  #pragma comment(lib,"ws2_32.lib") //Winsock Library #else #endif void error(const char *msg) { perror(msg); exit(0); } int main(int argc,char *argv[]) { int i; struct hostent *server; struct sockaddr_in serv_addr; int bytes, sent, received, total, message_size; char *message, response[4096]; int portno = atoi(argv[2])>0?atoi(argv[2]):80; char *host = strlen(argv[1])>0?argv[1]:"localhost"; char *path = strlen(argv[4])>0?argv[4]:"/"; if (argc < 5) { puts("Parameters:     [ []]"); exit(0); } /* How big is the message? */ message_size=0; if(!strcmp(argv[3],"GET")) { printf("Process 1\n"); message_size+=strlen("%s %s%s%s HTTP/1.0\r\nHost: %s\r\n"); /* method */ message_size+=strlen(argv[3]); /* path */ message_size+=strlen(path); /* headers */ if(argc>5) message_size+=strlen(argv[5]); /* query string */ for(i=6;i5) message_size+=strlen("Content-Length: %d\r\n")+10; /* content length */ message_size+=strlen("\r\n"); /* blank line */ if(argc>5) message_size+=strlen(argv[5]); /* body */ } printf("Allocating...\n"); /* allocate space for the message */ message=malloc(message_size); /* fill in the parameters */ if(!strcmp(argv[3],"GET")) { if(argc>5) sprintf(message,"%s %s%s%s HTTP/1.0\r\nHost: %s\r\n", strlen(argv[3])>0?argv[3]:"GET", /* method */ path, /* path */ strlen(argv[5])>0?"?":"", /* ? */ strlen(argv[5])>0?argv[5]:"",host); /* query string */ else sprintf(message,"%s %s HTTP/1.0\r\nHost: %s\r\n", strlen(argv[3])>0?argv[3]:"GET", /* method */ path,host); /* path */ for(i=6;i0?argv[3]:"POST", /* method */ path,host); /* path */ for(i=6;i5) sprintf(message+strlen(message),"Content-Length: %d\r\n",(int)strlen(argv[5])); strcat(message,"\r\n"); /* blank line */ if(argc>5) strcat(message,argv[5]); /* body */ } printf("Processed\n"); /* What are we going to send? */ printf("Request:\n%s\n",message); /* lookup the ip address */ total = strlen(message); /* create the socket */ #ifdef _WIN32 WSADATA wsa; SOCKET s; printf("\nInitialising Winsock..."); if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) { printf("Failed. Error Code : %d",WSAGetLastError()); return 1; } printf("Initialised.\n"); //Create a socket if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET) { printf("Could not create socket : %d" , WSAGetLastError()); } printf("Socket created.\n"); server = gethostbyname(host); serv_addr.sin_addr.s_addr = inet_addr(server->h_addr); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(portno); memset(&serv_addr,0,sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(portno); memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length); //Connect to remote server if (connect(s , (struct sockaddr *)&serv_addr , sizeof(serv_addr)) < 0) { printf("connect failed with error code : %d" , WSAGetLastError()); return 1; } puts("Connected"); if( send(s , message , strlen(message) , 0) < 0) { printf("Send failed with error code : %d" , WSAGetLastError()); return 1; } puts("Data Send\n"); //Receive a reply from the server if((received = recv(s , response , 2000 , 0)) == SOCKET_ERROR) { printf("recv failed with error code : %d" , WSAGetLastError()); } puts("Reply received\n"); //Add a NULL terminating character to make it a proper string before printing response[received] = '\0'; puts(response); closesocket(s); WSACleanup(); #endif #ifdef __linux__ int sockfd; server = gethostbyname(host); if (server == NULL) error("ERROR, no such host"); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); /* fill in the structure */ memset(&serv_addr,0,sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(portno); memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length); /* connect the socket */ if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) error("ERROR connecting"); /* send the request */ sent = 0; do { bytes = write(sockfd,message+sent,total-sent); if (bytes < 0) error("ERROR writing message to socket"); if (bytes == 0) break; sent+=bytes; } while (sent < total); /* receive the response */ memset(response, 0, sizeof(response)); total = sizeof(response)-1; received = 0; printf("Response: \n"); do { printf("%s", response); memset(response, 0, sizeof(response)); bytes = recv(sockfd, response, 1024, 0); if (bytes < 0) printf("ERROR reading response from socket"); if (bytes == 0) break; received+=bytes; } while (1); if (received == total) error("ERROR storing complete response from socket"); /* close the socket */ close(sockfd); #endif free(message); return 0; } сторона #include  /* printf, sprintf */ #include  /* exit, atoi, malloc, free */ #include  /* read, write, close */ #include  /* memcpy, memset */ #ifdef __linux__ #include  /* socket, connect */ #include  /* struct hostent, gethostbyname */ #include  /* struct sockaddr_in, struct sockaddr */ #elif _WIN32 #include  #include  #include  #pragma comment(lib,"ws2_32.lib") //Winsock Library #else #endif void error(const char *msg) { perror(msg); exit(0); } int main(int argc,char *argv[]) { int i; struct hostent *server; struct sockaddr_in serv_addr; int bytes, sent, received, total, message_size; char *message, response[4096]; int portno = atoi(argv[2])>0?atoi(argv[2]):80; char *host = strlen(argv[1])>0?argv[1]:"localhost"; char *path = strlen(argv[4])>0?argv[4]:"/"; if (argc < 5) { puts("Parameters:     [ []]"); exit(0); } /* How big is the message? */ message_size=0; if(!strcmp(argv[3],"GET")) { printf("Process 1\n"); message_size+=strlen("%s %s%s%s HTTP/1.0\r\nHost: %s\r\n"); /* method */ message_size+=strlen(argv[3]); /* path */ message_size+=strlen(path); /* headers */ if(argc>5) message_size+=strlen(argv[5]); /* query string */ for(i=6;i5) message_size+=strlen("Content-Length: %d\r\n")+10; /* content length */ message_size+=strlen("\r\n"); /* blank line */ if(argc>5) message_size+=strlen(argv[5]); /* body */ } printf("Allocating...\n"); /* allocate space for the message */ message=malloc(message_size); /* fill in the parameters */ if(!strcmp(argv[3],"GET")) { if(argc>5) sprintf(message,"%s %s%s%s HTTP/1.0\r\nHost: %s\r\n", strlen(argv[3])>0?argv[3]:"GET", /* method */ path, /* path */ strlen(argv[5])>0?"?":"", /* ? */ strlen(argv[5])>0?argv[5]:"",host); /* query string */ else sprintf(message,"%s %s HTTP/1.0\r\nHost: %s\r\n", strlen(argv[3])>0?argv[3]:"GET", /* method */ path,host); /* path */ for(i=6;i0?argv[3]:"POST", /* method */ path,host); /* path */ for(i=6;i5) sprintf(message+strlen(message),"Content-Length: %d\r\n",(int)strlen(argv[5])); strcat(message,"\r\n"); /* blank line */ if(argc>5) strcat(message,argv[5]); /* body */ } printf("Processed\n"); /* What are we going to send? */ printf("Request:\n%s\n",message); /* lookup the ip address */ total = strlen(message); /* create the socket */ #ifdef _WIN32 WSADATA wsa; SOCKET s; printf("\nInitialising Winsock..."); if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) { printf("Failed. Error Code : %d",WSAGetLastError()); return 1; } printf("Initialised.\n"); //Create a socket if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET) { printf("Could not create socket : %d" , WSAGetLastError()); } printf("Socket created.\n"); server = gethostbyname(host); serv_addr.sin_addr.s_addr = inet_addr(server->h_addr); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(portno); memset(&serv_addr,0,sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(portno); memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length); //Connect to remote server if (connect(s , (struct sockaddr *)&serv_addr , sizeof(serv_addr)) < 0) { printf("connect failed with error code : %d" , WSAGetLastError()); return 1; } puts("Connected"); if( send(s , message , strlen(message) , 0) < 0) { printf("Send failed with error code : %d" , WSAGetLastError()); return 1; } puts("Data Send\n"); //Receive a reply from the server if((received = recv(s , response , 2000 , 0)) == SOCKET_ERROR) { printf("recv failed with error code : %d" , WSAGetLastError()); } puts("Reply received\n"); //Add a NULL terminating character to make it a proper string before printing response[received] = '\0'; puts(response); closesocket(s); WSACleanup(); #endif #ifdef __linux__ int sockfd; server = gethostbyname(host); if (server == NULL) error("ERROR, no such host"); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); /* fill in the structure */ memset(&serv_addr,0,sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(portno); memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length); /* connect the socket */ if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) error("ERROR connecting"); /* send the request */ sent = 0; do { bytes = write(sockfd,message+sent,total-sent); if (bytes < 0) error("ERROR writing message to socket"); if (bytes == 0) break; sent+=bytes; } while (sent < total); /* receive the response */ memset(response, 0, sizeof(response)); total = sizeof(response)-1; received = 0; printf("Response: \n"); do { printf("%s", response); memset(response, 0, sizeof(response)); bytes = recv(sockfd, response, 1024, 0); if (bytes < 0) printf("ERROR reading response from socket"); if (bytes == 0) break; received+=bytes; } while (1); if (received == total) error("ERROR storing complete response from socket"); /* close the socket */ close(sockfd); #endif free(message); return 0; } 
  • OkHttp Post Body как JSON
  • Чтение FromUri и FromBody одновременно
  • Как программно отправлять запрос POST на страницу JSF без использования HTML-формы?
  • Опубликовать x-www-form-urlencoded запрос от React Native
  • POST multipart / form-data с Objective-C
  • Android, Java: HTTP POST Request
  • Как сделать HTTP-сообщение в Android?
  • Получение переменной POST
  • Отправить запрос POST с данными, указанными в файле через Curl
  • jQuery не-AJAX POST
  • Как использовать тип: «POST» в jsonp ajax call
  • Давайте будем гением компьютера.