获取request中用POST方式“Content-type”是“text/plain”发送的json数据

本文介绍了一种从HTTP请求中解析使用POST方法且Content-type为text/plain的JSON数据的方法。通过读取请求体并将其转换为字符串或指定类型的对象,实现对这类数据的有效处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

public static String fetchPostByTextPlain(HttpServletRequest request) {
        try {
            BufferedReader reader = request.getReader();
            char[] buf = new char[512];
            int len = 0;
            StringBuffer contentBuffer = new StringBuffer();
            while ((len = reader.read(buf)) != -1) {
                contentBuffer.append(buf, 0, len);
            }
            return contentBuffer.toString();

        } catch (IOException e) {
            e.printStackTrace();
            log.error("[获取request中用POST方式“Content-type”是“text/plain”发送的json数据]异常:{}", e.getCause());
        }
        return "";
    }
    
    public static <T> T fetchPostByTextPlain(HttpServletRequest request, Class<T> clazz) {
        try {
            BufferedReader reader = request.getReader();
            char[] buf = new char[512];
            int len = 0;
            StringBuffer contentBuffer = new StringBuffer();
            while ((len = reader.read(buf)) != -1) {
                contentBuffer.append(buf, 0, len);
            }
            return JSON.parseObject(contentBuffer.toString(), clazz);

        } catch (IOException e) {
            e.printStackTrace();
            log.error("[获取request中用POST方式“Content-type”是“text/plain”发送的json数据]异常:{}", e.getCause());
        }
        return null;
    }
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include "utils.h" // 创建监听 socket int create_listen_socket(int port) { int sockfd; struct sockaddr_in addr; int opt = 1; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(EXIT_FAILURE); } setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(port); if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); close(sockfd); exit(EXIT_FAILURE); } if (listen(sockfd, SOMAXCONN) < 0) { perror("listen"); close(sockfd); exit(EXIT_FAILURE); } return sockfd; } void log_debug(const char *message) { printf("[DEBUG] %s\n", message); } void log_error(const char *message) { fprintf(stderr, "[ERROR] %s\n", message); }第一个文件,#include <string.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/sendfile.h> #include <libgen.h> #include <sys/stat.h> #include <sys/select.h> #include <stdlib.h> #include <ctype.h> #include "http_parser.h" // 获取 MIME 类型 const char *get_mime_type(const char *path) { const char *ext = strrchr(path, '.'); if (!ext) return "text/plain"; ext++; if (strcasecmp(ext, "html") == 0) return "text/html"; if (strcasecmp(ext, "css") == 0) return "text/css"; if (strcasecmp(ext, "js") == 0) return "application/javascript"; if (strcasecmp(ext, "jpg") == 0 || strcasecmp(ext, "jpeg") == 0) return "image/jpeg"; if (strcasecmp(ext, "png") == 0) return "image/png"; if (strcasecmp(ext, "gif") == 0) return "image/gif"; if (strcasecmp(ext, "ico") == 0) return "image/x-icon"; return "application/octet-stream"; } // 路径安全检查 int is_valid_path(const char *path) { if (strstr(path, "../") || strstr(path, "..\\")) return 0; return 1; } // 新增函数:读取完整的 HTTP 请求 int read_http_request(int fd, char *buffer, size_t size) { ssize_t total = 0; ssize_t bytes_read; while ((bytes_read = read(fd, buffer + total, size - total - 1)) > 0) { total += bytes_read; buffer[total] = '\0'; if (strstr(buffer, "\r\n\r\n")) { // 请求头结束,检查是否还有 POST 数据 const char *content_length = strstr(buffer, "Content-Length:"); if (content_length) { int len = 0; sscanf(content_length, "Content-Length: %d", &len); size_t headers_end = strstr(buffer, "\r\n\r\n") - buffer + 4; size_t remaining = headers_end + len - total; if (remaining > 0) { while (remaining > 0 && (bytes_read = read(fd, buffer + total, remaining)) > 0) { total += bytes_read; remaining -= bytes_read; } } } break; } ssize_t max = (ssize_t)size - 1; if (total >= max) { return -1; // Buffer overflow } } buffer[total] = '\0'; return total > 0 ? 0 : -1; } // 解析 HTTP 请求 int parse_http_request(const char *raw, http_request *req) { sscanf(raw, "%15s %255s %15s", req->method, req->path, req->protocol); const char *header_start = strstr(raw, "\r\n") + 2; const char *body_start = strstr(header_start, "\r\n\r\n"); if (body_start) { size_t header_len = body_start - header_start; strncpy(req->headers, header_start, header_len < sizeof(req->headers) - 1 ? header_len : sizeof(req->headers) - 1); body_start += 4; strncpy(req->body, body_start, sizeof(req->body) - 1); } return 0; } // 处理请求 void process_request(http_request *req, int client_fd) { char file_path[1024]; if (!is_valid_path(req->path)) { dprintf(client_fd, "HTTP/1.1 403 Forbidden\r\n\r\n"); return; } if (strcmp(req->path, "/") == 0) { snprintf(file_path, sizeof(file_path), "./static/Index.html"); } else { snprintf(file_path, sizeof(file_path), "./static%s", req->path); } if (access(file_path, F_OK) == -1) { dprintf(client_fd, "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html\r\n\r\n" "<html><body><h1>404 Not Found</h1></body></html>"); return; } int fd = open(file_path, O_RDONLY); if (fd < 0) { char err[256]; snprintf(err, sizeof(err), "HTTP/1.1 500 Internal Server Error\r\n" "Content-Type: text/html\r\n\r\n" "<html><body><h1>500 Internal Server Error</h1>" "<p>Failed to open file: %s</p></body></html>", strerror(errno)); ssize_t bytes_written = write(client_fd, err, strlen(err)); if (bytes_written < 0) { perror("write failed"); } return; } struct stat st; if (fstat(fd, &st) < 0) { close(fd); dprintf(client_fd, "HTTP/1.1 500 Internal Server Error\r\n" "Content-Type: text/html\r\n\r\n" "<html><body><h1>500 Internal Server Error</h1>" "<p>Failed to get file size</p></body></html>"); return; } const char *mime_type = get_mime_type(file_path); dprintf(client_fd, "HTTP/1.1 200 OK\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n\r\n", mime_type, st.st_size); off_t offset = 0; ssize_t sent = sendfile(client_fd, fd, &offset, st.st_size); if (sent < 0 || sent != st.st_size) { char err[256]; snprintf(err, sizeof(err), "HTTP/1.1 500 Internal Server Error\r\n" "Content-Type: text/html\r\n\r\n" "<html><body><h1>500 Internal Server Error</h1>" "<p>File send error: %s</p></body></html>", strerror(errno)); ssize_t bytes_written = write(client_fd, err, strlen(err)); if (bytes_written < 0) { perror("write failed"); } } close(fd); } // 解析表单数据 // 解码 URL 编码的字符(如 %20 -> ' ') void url_decode(char *src, char *dest, size_t dest_size) { char *d = dest; char *end = dest + dest_size - 1; while (*src && d < end) { if (*src == '+') { *d++ = ' '; src++; } else if (*src == '%' && isxdigit(src[1]) && isxdigit(src[2])) { // 解码 %xx char hex[3] = {src[1], src[2], '\0'}; *d++ = (char)strtol(hex, NULL, 16); src += 3; } else { *d++ = *src++; } } *d = '\0'; } void parse_form_data(const char *body, char *name, char *email, char *message) { char *data = strdup(body); if (!data) return; char *saveptr; char *pair = strtok_r(data, "&", &saveptr); while (pair) { char *key = strtok(pair, "="); char *value = strtok(NULL, "="); if (key && value) { char decoded[2048]; url_decode(value, decoded, sizeof(decoded)); if (strcmp(key, "name") == 0) snprintf(name, 256, "%s", decoded); else if (strcmp(key, "email") == 0) snprintf(email, 256, "%s", decoded); else if (strcmp(key, "message") == 0) snprintf(message, 1024, "%s", decoded); } pair = strtok_r(NULL, "&", &saveptr); } free(data); } // 模拟处理联系表单并返回 JSON void handle_contact_form(http_request *req, int client_fd) { char name[256] = {0}; char email[256] = {0}; char message[1024] = {0}; parse_form_data(req->body, name, email, message); // 打印接收到的数据(可替换为写入文件或数据库) printf("Name: %s\n", name); printf("Email: %s\n", email); printf("Message: %s\n", message); // 模拟保存成功,返回 JSON 响应 dprintf(client_fd, "HTTP/1.1 200 OK\r\n" "Content-Type: application/json\r\n\r\n" "{ \"callback\": \"Thank you for contacting us!\" }"); } 第二个文件,#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/sendfile.h> #include "utils.h" #include "http_parser.h" #define MAX_THREADS 100 /* 最大并发线程数 */ sem_t thread_semaphore; /* 用于限制最大线程数 */ /* 传递给线程函数的参数结构体 */ typedef struct { int client_fd; /* 客户端的socket描述符 */ struct sockaddr_in client_addr; /* 客户端地址信息 */ } thread_args; /* 线程处理函数:处理客户端连接 */ static void *handle_client(void *arg) { thread_args *args = (thread_args *)arg; char buffer[BUFFER_SIZE]; /* 从客户端socket中读取数据 */ ssize_t bytes_read = read(args->client_fd, buffer, BUFFER_SIZE - 1); if (bytes_read <= 0) { if (bytes_read == 0) { printf("Client disconnected: %d\n", args->client_fd); } else { perror("read"); } close(args->client_fd); free(args); sem_post(&thread_semaphore); // 释放信号量 return NULL; } buffer[bytes_read] = '\0'; // 添加字符串结束符 // 检查是否超过缓冲区 if (bytes_read >= BUFFER_SIZE - 1) { dprintf(args->client_fd, "HTTP/1.1 413 Payload Too Large\r\n\r\n"); close(args->client_fd); free(args); sem_post(&thread_semaphore); return NULL; } http_request req; /* 定义http请求结构体 */ if (parse_http_request(buffer, &req) < 0) { dprintf(args->client_fd, "HTTP/1.1 400 Bad Request\r\n\r\n"); close(args->client_fd); } if (strcasecmp(req.method, "GET") == 0) { process_request(&req, args->client_fd); } else if (strcasecmp(req.method, "POST") == 0) { if (strcmp(req.path, "/data/contact.json") == 0) { handle_contact_form(&req, args->client_fd); } else { dprintf(args->client_fd, "HTTP/1.1 405 Method Not Allowed\r\n\r\n"); } } else { dprintf(args->client_fd, "HTTP/1.1 405 Method Not Allowed\r\n\r\n"); } close(args->client_fd); free(args); sem_post(&thread_semaphore); // 释放信号量 return NULL; } int main(int argc, char *argv[]) { int port = 80; // 默认端口 // 处理命令行参数 if (argc >= 2) { char *endptr; long input_port = strtol(argv[1], &endptr, 10); // 安全转换 // 验证端口格式和范围 if (*endptr != '\0' || input_port < 1 || input_port > 65535) { fprintf(stderr, "错误:无效端口号 '%s',使用默认端口80\n", argv[1]); } else { port = (int)input_port; } } // 初始化信号量 if (sem_init(&thread_semaphore, 0, MAX_THREADS) != 0) { perror("sem_init"); return EXIT_FAILURE; } int server_fd = create_listen_socket(port); /* 创建服务器socket并绑定到指定端口 */ /* 添加创建服务器socket失败的报错信息 */ if (server_fd < 0) { fprintf(stderr, "Failed to create listen socket\n"); return EXIT_FAILURE; } pthread_t thread_id; /* 用于创建线程 */ /* 持续监听客户端连接 */ while (1) { struct sockaddr_in client_addr; /* 客户端地址结构体 */ socklen_t addr_len = sizeof(client_addr); int client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_len); /* 接受客户端连接 */ /* 添加接受客户端连接失败的信息 */ if (client_fd < 0) { perror("accept"); continue; } thread_args *args = malloc(sizeof(thread_args)); /* 添加分配内存失败的报错信息 */ if (!args) { perror("malloc"); close(client_fd); continue; } args->client_fd = client_fd; args->client_addr = client_addr; /* 等待信号量,限制最大线程数 */ sem_wait(&thread_semaphore); pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); int result = pthread_create(&thread_id, &attr, handle_client, args); if (result != 0) { perror("pthread_create"); free(args); /* 创建失败时释放内存 */ close(client_fd); sem_post(&thread_semaphore); // 释放信号量 } pthread_attr_destroy(&attr); } close(server_fd); sem_destroy(&thread_semaphore); return 0; } 第三个文件,结合这三个文件,给出一个完整的日志输出机制,包含 DEBUG(调试信息)  INFO(正常请求记录)  WARN(异常情况)  ERROR(严重错误) 这几个等级,便于调式,输出的log文件名以包含main函数的文件名(去掉后缀)为准
最新发布
08-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值