EXT解决“HTTP/1.1 405 Method not allowed”问题

本文探讨了Apache、IIS、Nginx等Web服务器不允许静态文件响应POST请求的问题,导致出现405错误。通过将请求方法更改为GET解决了此问题,并详细介绍了如何在ExtTree组件中进行相应设置。

      Apache、IIS、Nginx等大多数web服务器,都不允许静态文件响应POST请求,否则会返回“HTTP/1.1 405 Method not allowed”错误。 即将出错页面表单的method=“post”改为“get”即可。

Ext Tree组件做一个东西,需要用到ajax对节点逐级加载,开始数据用的静态数据data.xml,访问提示“405错误”,原因是资源禁止访问.
在.NET里参数传递方式不对,IIS用GET接受数据,但请求用POST传递数据,因此就会出现这个问题.
解决方案:在TreeLoader里加一个requestMethod:'GET'就ok了。
Loader的代码大致是这样的:
// Our custom TreeLoader:
       loader: new Ext.app.BookLoader({
           dataUrl:'xml-tree-data.xml',
           requestMethod: 'GET'
       }),

"C:\Program Files\Java\jdk-1.8\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2024.1.2\lib\idea_rt.jar=55773:C:\Program Files\JetBrains\IntelliJ IDEA 2024.1.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk-1.8\jre\lib\charsets.jar;C:\Program Files\Java\jdk-1.8\jre\lib\deploy.jar;C:\Program Files\Java\jdk-1.8\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk-1.8\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk-1.8\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk-1.8\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk-1.8\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk-1.8\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk-1.8\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk-1.8\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk-1.8\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk-1.8\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk-1.8\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk-1.8\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk-1.8\jre\lib\javaws.jar;C:\Program Files\Java\jdk-1.8\jre\lib\jce.jar;C:\Program Files\Java\jdk-1.8\jre\lib\jfr.jar;C:\Program Files\Java\jdk-1.8\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk-1.8\jre\lib\jsse.jar;C:\Program Files\Java\jdk-1.8\jre\lib\management-agent.jar;C:\Program Files\Java\jdk-1.8\jre\lib\plugin.jar;C:\Program Files\Java\jdk-1.8\jre\lib\resources.jar;C:\Program Files\Java\jdk-1.8\jre\lib\rt.jar;D:\mycode\ElasticSearchJava\target\classes;D:\maven\repository\org\elasticsearch\elasticsearch\6.5.4\elasticsearch-6.5.4.jar;D:\maven\repository\org\elasticsearch\elasticsearch-core\6.5.4\elasticsearch-core-6.5.4.jar;D:\maven\repository\org\elasticsearch\elasticsearch-secure-sm\6.5.4\elasticsearch-secure-sm-6.5.4.jar;D:\maven\repository\org\elasticsearch\elasticsearch-x-content\6.5.4\elasticsearch-x-content-6.5.4.jar;D:\maven\repository\org\yaml\snakeyaml\1.17\snakeyaml-1.17.jar;D:\maven\repository\com\fasterxml\jackson\core\jackson-core\2.8.11\jackson-core-2.8.11.jar;D:\maven\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-smile\2.8.11\jackson-dataformat-smile-2.8.11.jar;D:\maven\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.8.11\jackson-dataformat-yaml-2.8.11.jar;D:\maven\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-cbor\2.8.11\jackson-dataformat-cbor-2.8.11.jar;D:\maven\repository\org\apache\lucene\lucene-core\7.5.0\lucene-core-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-analyzers-common\7.5.0\lucene-analyzers-common-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-backward-codecs\7.5.0\lucene-backward-codecs-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-grouping\7.5.0\lucene-grouping-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-highlighter\7.5.0\lucene-highlighter-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-join\7.5.0\lucene-join-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-memory\7.5.0\lucene-memory-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-misc\7.5.0\lucene-misc-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-queries\7.5.0\lucene-queries-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-queryparser\7.5.0\lucene-queryparser-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-sandbox\7.5.0\lucene-sandbox-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-spatial\7.5.0\lucene-spatial-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-spatial-extras\7.5.0\lucene-spatial-extras-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-spatial3d\7.5.0\lucene-spatial3d-7.5.0.jar;D:\maven\repository\org\apache\lucene\lucene-suggest\7.5.0\lucene-suggest-7.5.0.jar;D:\maven\repository\org\elasticsearch\elasticsearch-cli\6.5.4\elasticsearch-cli-6.5.4.jar;D:\maven\repository\net\sf\jopt-simple\jopt-simple\5.0.2\jopt-simple-5.0.2.jar;D:\maven\repository\com\carrotsearch\hppc\0.7.1\hppc-0.7.1.jar;D:\maven\repository\joda-time\joda-time\2.10.1\joda-time-2.10.1.jar;D:\maven\repository\com\tdunning\t-digest\3.2\t-digest-3.2.jar;D:\maven\repository\org\hdrhistogram\HdrHistogram\2.1.9\HdrHistogram-2.1.9.jar;D:\maven\repository\org\apache\logging\log4j\log4j-api\2.11.1\log4j-api-2.11.1.jar;D:\maven\repository\org\elasticsearch\jna\4.5.1\jna-4.5.1.jar;D:\maven\repository\org\elasticsearch\client\elasticsearch-rest-high-level-client\6.5.4\elasticsearch-rest-high-level-client-6.5.4.jar;D:\maven\repository\org\elasticsearch\client\elasticsearch-rest-client\6.5.4\elasticsearch-rest-client-6.5.4.jar;D:\maven\repository\org\apache\httpcomponents\httpclient\4.5.2\httpclient-4.5.2.jar;D:\maven\repository\org\apache\httpcomponents\httpcore\4.4.5\httpcore-4.4.5.jar;D:\maven\repository\org\apache\httpcomponents\httpasyncclient\4.1.2\httpasyncclient-4.1.2.jar;D:\maven\repository\org\apache\httpcomponents\httpcore-nio\4.4.5\httpcore-nio-4.4.5.jar;D:\maven\repository\commons-codec\commons-codec\1.10\commons-codec-1.10.jar;D:\maven\repository\commons-logging\commons-logging\1.1.3\commons-logging-1.1.3.jar;D:\maven\repository\org\elasticsearch\plugin\parent-join-client\6.5.4\parent-join-client-6.5.4.jar;D:\maven\repository\org\elasticsearch\plugin\aggs-matrix-stats-client\6.5.4\aggs-matrix-stats-client-6.5.4.jar;D:\maven\repository\org\elasticsearch\plugin\rank-eval-client\6.5.4\rank-eval-client-6.5.4.jar;D:\maven\repository\org\elasticsearch\plugin\lang-mustache-client\6.5.4\lang-mustache-client-6.5.4.jar;D:\maven\repository\com\github\spullara\mustache\java\compiler\0.9.3\compiler-0.9.3.jar;D:\maven\repository\org\apache\logging\log4j\log4j-to-slf4j\2.9.1\log4j-to-slf4j-2.9.1.jar;D:\maven\repository\org\slf4j\slf4j-api\1.7.24\slf4j-api-1.7.24.jar;D:\maven\repository\org\slf4j\slf4j-simple\1.7.21\slf4j-simple-1.7.21.jar;D:\maven\repository\log4j\log4j\1.2.12\log4j-1.2.12.jar" org.example.MovieRatings log4j:WARN No appenders could be found for logger (org.apache.http.impl.nio.client.MainClientExec). log4j:WARN Please initialize the log4j system properly. Exception in thread "main" ElasticsearchStatusException[Unable to parse response body]; nested: ResponseException[method [PUT], host [http://192.168.100.130:9100], URI [/movie_ratings?master_timeout=30s&timeout=30s], status line [HTTP/1.1 405 Method Not Allowed] ]; nested: ResponseException[method [PUT], host [http://192.168.100.130:9100], URI [/movie_ratings?master_timeout=30s&timeout=30s], status line [HTTP/1.1 405 Method Not Allowed] ]; at org.elasticsearch.client.RestHighLevelClient.parseResponseException(RestHighLevelClient.java:1773) at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1606) at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:1563) at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:1525) at org.elasticsearch.client.IndicesClient.create(IndicesClient.java:146) at org.example.MovieRatings.createIndex(MovieRatings.java:42) at org.example.MovieRatings.main(MovieRatings.java:25) Suppressed: java.lang.IllegalStateException: Elasticsearch didn't return the [Content-Type] header, unable to parse response body at org.elasticsearch.client.RestHighLevelClient.parseEntity(RestHighLevelClient.java:1786) at org.elasticsearch.client.RestHighLevelClient.parseResponseException(RestHighLevelClient.java:1769) ... 6 more Caused by: org.elasticsearch.client.ResponseException: method [PUT], host [http://192.168.100.130:9100], URI [/movie_ratings?master_timeout=30s&timeout=30s], status line [HTTP/1.1 405 Method Not Allowed] at org.elasticsearch.client.RestClient$SyncResponseListener.get(RestClient.java:926) at org.elasticsearch.client.RestClient.performRequest(RestClient.java:229) at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1593) ... 5 more Caused by: org.elasticsearch.client.ResponseException: method [PUT], host [http://192.168.100.130:9100], URI [/movie_ratings?master_timeout=30s&timeout=30s], status line [HTTP/1.1 405 Method Not Allowed] at org.elasticsearch.client.RestClient$1.completed(RestClient.java:546) at org.elasticsearch.client.RestClient$1.completed(RestClient.java:531) at org.apache.http.concurrent.BasicFuture.completed(BasicFuture.java:119) at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseCompleted(DefaultClientExchangeHandlerImpl.java:177) at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.processResponse(HttpAsyncRequestExecutor.java:436) at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.inputReady(HttpAsyncRequestExecutor.java:326) at org.apache.http.impl.nio.client.InternalRequestExecutor.inputReady(InternalRequestExecutor.java:83) at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:265) at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81) at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39) at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:114) at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162) at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337) at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315) at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276) at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104) at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:588) at java.lang.Thread.run(Thread.java:750)
06-06
请为我修改为标准的C语言注释、代码中大括号上下要对齐// // webserver.c — Minimal multithreaded HTTP static file server (Linux) // Build: gcc webserver.c -o webserver -lpthread // Run: ./webserver // Browse: http://localhost:8080/ // // Serves files under the WEB_ROOT directory. Defaults to "Index.html". // Supports keep-alive on GET, basic content-type mapping, and zero-copy sendfile. // #include <arpa/inet.h> #include <fcntl.h> #include <netinet/in.h> #include <pthread.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/sendfile.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #define PORT 8080 #define BUFFER_SIZE 8192 #define WEB_ROOT "web/" // ------------------------------- // Request structure & parsing // ------------------------------- typedef struct { char method[16]; char path[1024]; } Request; static Request parse_request(const char *buffer) { Request req; memset(&req, 0, sizeof(req)); strcpy(req.method, ""); // default empty strcpy(req.path, "/"); // default root // Very simple parse: METHOD PATH HTTP/1.1 // e.g., "GET /index.html HTTP/1.1" sscanf(buffer, "%15s %1023s", req.method, req.path); return req; } // ------------------------------- // Utilities // ------------------------------- static const char *guess_content_type(const char *path) { // crude extension check const char *ext = strrchr(path, '.'); if (!ext) return "text/html"; if (!strcmp(ext, ".html") || !strcmp(ext, ".htm")) return "text/html; charset=utf-8"; if (!strcmp(ext, ".css")) return "text/css; charset=utf-8"; if (!strcmp(ext, ".js")) return "application/javascript; charset=utf-8"; if (!strcmp(ext, ".json")) return "application/json; charset=utf-8"; if (!strcmp(ext, ".png")) return "image/png"; if (!strcmp(ext, ".jpg") || !strcmp(ext, ".jpeg")) return "image/jpeg"; if (!strcmp(ext, ".gif")) return "image/gif"; if (!strcmp(ext, ".svg")) return "image/svg+xml"; if (!strcmp(ext, ".ico")) return "image/x-icon"; if (!strcmp(ext, ".txt")) return "text/plain; charset=utf-8"; return "application/octet-stream"; } static bool contains_dotdot(const char *p) { return strstr(p, "..") != NULL; } // ------------------------------- // Client handler // ------------------------------- static void *handle_client(void *arg) { int client_fd = *((int *)arg); free(arg); int keep_alive = 1; // default keep-alive unless "Connection: close" char buffer[BUFFER_SIZE]; while (keep_alive) { memset(buffer, 0, sizeof(buffer)); ssize_t bytes_read = read(client_fd, buffer, sizeof(buffer) - 1); if (bytes_read <= 0) break; // closed or error // Basic keep-alive check if (strstr(buffer, "Connection: close")) { keep_alive = 0; } Request req = parse_request(buffer); // Only support GET/HEAD for static content; POST placeholder if (!strcmp(req.method, "GET") || !strcmp(req.method, "HEAD")) { char full_path[2048]; struct stat st; // Directory traversal guard if (contains_dotdot(req.path)) { const char *bad = "HTTP/1.1 400 Bad Request\r\n" "Content-Type: text/plain; charset=utf-8\r\n" "Connection: close\r\n\r\n" "Bad Request"; write(client_fd, bad, strlen(bad)); break; } if (!strcmp(req.path, "/")) { snprintf(full_path, sizeof(full_path), "%sIndex.html", WEB_ROOT); } else { // strip leading '/' for local file path const char *sub = req.path[0] == '/' ? req.path + 1 : req.path; snprintf(full_path, sizeof(full_path), "%s%s", WEB_ROOT, sub); } if (stat(full_path, &st) < 0 || S_ISDIR(st.st_mode)) { const char *not_found = "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html; charset=utf-8\r\n" "Connection: keep-alive\r\n\r\n" "<!doctype html><html><body><h1>404 Not Found</h1></body></html>"; write(client_fd, not_found, strlen(not_found)); continue; } else { const char *content_type = guess_content_type(full_path); // Headers char headers[512]; int n = snprintf(headers, sizeof(headers), "HTTP/1.1 200 OK\r\n" "Connection: keep-alive\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n\r\n", content_type, (long)st.st_size); write(client_fd, headers, (size_t)n); if (!strcmp(req.method, "HEAD")) { continue; // header only } int file_fd = open(full_path, O_RDONLY); if (file_fd != -1) { off_t offset = 0; size_t remaining = (size_t)st.st_size; while (remaining > 0) { ssize_t sent = sendfile(client_fd, file_fd, &offset, remaining); if (sent <= 0) break; remaining -= (size_t)sent; } close(file_fd); } } } else if (!strcmp(req.method, "POST")) { // Placeholder: echo 204 No Content (not implemented) char* contentLengthstr = strstr(buffer,"Content-Length"); if(!contentLengthstr) { printf("No content-length key\n"); } else { int contentLength; sscanf(contentLengthstr+14,":%d",&contentLength); char*payload = strstr(buffer, "\r\n\r\n"); for(int i=0;i<contentLength;i++) printf("%c",*(payload+4+i)); printf("\n"); } const char *resp = "HTTP/1.1 204 No Content\r\n" "Connection: keep-alive\r\n\r\n"; write(client_fd, resp, strlen(resp)); } else { const char *method_not_allowed = "HTTP/1.1 405 Method Not Allowed\r\n" "Allow: GET, HEAD, POST\r\n" "Connection: keep-alive\r\n\r\n"; write(client_fd, method_not_allowed, strlen(method_not_allowed)); } // Optional: break if the client sent only one request without keep-alive // (Most modern browsers default to keep-alive; we keep the loop.) } close(client_fd); return NULL; } // ------------------------------- // Main entry // ------------------------------- int main(void) { int server_fd; struct sockaddr_in address; int opt = 1; // Create socket if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket failed"); exit(EXIT_FAILURE); } // SO_REUSEADDR if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("setsockopt"); close(server_fd); exit(EXIT_FAILURE); } // Bind memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); close(server_fd); exit(EXIT_FAILURE); } // Listen if (listen(server_fd, 10) < 0) { perror("listen"); close(server_fd); exit(EXIT_FAILURE); } printf("WebServer running on port %d\n", PORT); printf("Access at: http://localhost:%d/\n", PORT); // Accept loop while (1) { int *client_fd = (int *)malloc(sizeof(int)); if (!client_fd) { perror("malloc"); continue; } struct sockaddr_in client_addr; socklen_t addr_len = sizeof(client_addr); *client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_len); if (*client_fd < 0) { perror("accept"); free(client_fd); continue; } // Client info (optional) char client_ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN); // printf("New connection from: %s:%d\n", client_ip, ntohs(client_addr.sin_port)); pthread_t thread_id; if (pthread_create(&thread_id, NULL, handle_client, client_fd) != 0) { perror("pthread_create"); close(*client_fd); free(client_fd); continue; } pthread_detach(thread_id); // resources auto-released when thread exits } // Not reached close(server_fd); return 0; }
08-15
#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
#define _GNU_SOURCE #include <strings.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <arpa/inet.h> #include <fcntl.h> #include <sys/stat.h> #define PORT 8080 #define BACKLOG 10 #define ROOT "web" #define BUF_SIZE 8192 static const char *mime(const char *ext) { if (!ext) return "application/octet-stream"; if (!strcasecmp(ext, "html") || !strcasecmp(ext, "htm")) return "text/html"; if (!strcasecmp(ext, "css")) return "text/css"; if (!strcasecmp(ext, "js")) return "application/javascript"; if (!strcasecmp(ext, "png")) return "image/png"; if (!strcasecmp(ext, "jpg") || !strcasecmp(ext, "jpeg")) return "image/jpeg"; return "text/plain"; } int main(int argc, char *argv[]) { int port = argc > 1 ? atoi(argv[1]) : PORT; int listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd < 0) { perror("socket"); exit(EXIT_FAILURE); } int opt = 1; setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); struct sockaddr_in addr = {0}; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(listenfd, (struct sockaddr *)&addr, sizeof(addr)) < 0 || listen(listenfd, BACKLOG) < 0) { perror("bind/listen"); exit(EXIT_FAILURE); } printf("GET/POST WebServer http://localhost:%d\n", port); while (1) { struct sockaddr_in cli; socklen_t len = sizeof(cli); int connfd = accept(listenfd, (struct sockaddr *)&cli, &len); if (connfd < 0) continue; char buf[BUF_SIZE] = {0}; ssize_t n = recv(connfd, buf, sizeof(buf) - 1, 0); if (n <= 0) { close(connfd); continue; } char method[8], path[256], proto[16]; sscanf(buf, "%7s %255s %15s", method, path, proto); char *cl = strcasestr(buf, "Content-Length:"); long body_len = cl ? atol(cl + 15) : 0; char body[BUF_SIZE] = {0}; if (body_len > 0 && body_len < sizeof(body)) recv(connfd, body, body_len, MSG_WAITALL); /* ========= 路由开始 ========= */ if (strcmp(method, "GET") == 0) { if (strcmp(path, "/") == 0) strcpy(path, "/Index.html"); if (strstr(path, "..")) { const char *rsp = "HTTP/1.1 400 Bad Request\r\n\r\n"; send(connfd, rsp, strlen(rsp), 0); close(connfd); continue; } char file_path[512]; snprintf(file_path, sizeof(file_path), "%s%s", ROOT, path); int fd = open(file_path, O_RDONLY); if (fd < 0) { const char *rsp = "HTTP/1.1 404 Not Found\r\n\r\n<h1>404</h1>"; send(connfd, rsp, strlen(rsp), 0); close(connfd); continue; } struct stat st; fstat(fd, &st); const char *ext = strrchr(file_path, '.'); const char *ct = mime(ext ? ext + 1 : NULL); char header[512]; int hd_len = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\nContent-Type: %s\r\n" "Content-Length: %ld\r\nConnection: close\r\n\r\n", ct, st.st_size); send(connfd, header, hd_len, 0); char file_buf[BUF_SIZE]; ssize_t bytes; while ((bytes = read(fd, file_buf, sizeof(file_buf))) > 0) send(connfd, file_buf, bytes, 0); close(fd); } else if (strcmp(method, "POST") == 0) { /* 只处理 /submit 路由 */ if (strcmp(path, "/submit") == 0) { int out = open("web/contact.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644); write(out, body, body_len); close(out); const char *rsp = "HTTP/1.1 303 See Other\r\n" "Location: /Index.html\r\n\r\n"; size_t left = strlen(rsp); while (left > 0) { ssize_t sent = send(connfd, rsp, left, 0); if (sent <= 0) break; rsp += sent; left -= sent; } } else { const char *rsp = "HTTP/1.1 404 Not Found\r\n\r\n"; send(connfd, rsp, strlen(rsp), 0); } } else { const char *rsp = "HTTP/1.1 405 Method Not Allowed\r\n\r\n"; send(connfd, rsp, strlen(rsp), 0); } /* ========= 路由结束 ========= */ close(connfd); } return 0; } <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <title>Contact</title> <link rel="stylesheet" type="text/css" href="css/style_mobile.css"> <script language="javascript" type="text/javascript" src="js/jquery-1.9.1.min.js"></script> <script language="javascript" type="text/javascript" src="js/action.js"></script> </head> <body> <div id="container"> <div id="header"> <div id="logo">David Lanham</div> <ul> <li><a href="Index.html">Blog</a></li> <li><a href="Work.html">Work</a></li> <li><a href="About.html">About</a></li> <li><a class="active" href="Contact.html">Contact</a></li> </ul> </div> <div id="content"> <p class="content_text">Contact</p> <div id="from"> <form action="/submit" method="POST"> <tr><p class="font">Name<font color="#FF0000">*</font></p></tr> <tr><input class="input" type="text" name="name" id="name" ></tr> <tr> <p class="font">Email<font color="#FF0000">*</font></p></tr> <tr><input class="input" type="text" name="email" id="email"></tr> <tr> <p class="font">Message<font color="#FF0000">*</font></p></tr> <tr><textarea class="msginput" type="text" name="message" id="message"></textarea></tr> <tr><button type="submit" class="button">SUBMIT</button></tr> </form> </div> </div> <div id="footer"> <div id="fttext"> <p>All illustrations on this site are from the very talented</p> <p> illustrator and designer David Lanham. Make sure to</p> <p>check out his work at <a href="#">DavidLanham.com.</a></p> </div> <div id="ftimage"> <a href="#"><img src="images/footer_baby.png"></a> </div> <div id="ft_text"> <p class="ftname">David Lanham</p> <p class="ftabout">I create beatufiul illustrations and designs.<a href="#">About me.</a></p> </div> <ul> <li><a href="#"><img src="images/footer_bird.png"></a></li> <li><a href="#"><img src="images/footer_ball.png"></a></li> <li><a href="#"><img src="images/footer_be.png"></a></li> <li><a href="#"><img src="images/footer_@.png"></a></li> <li><a href="#"><img src="images/footer_message.png"></a></li> </ul> </div> </div> </body> </html> 为什么我每次submit之后会卡住
08-12
我的全部代码如下,出现了访问index正常但无图片,其他html404./* Copyright(c) Lianzhou International Co.Ltd. * * file threaded_server.c * brief This is a simple muti-threade server. * * author Sun Haoming * version 1.0.0 * date 25Aug14 * * history * \arg 1.0.0, 25Aug14, Sun Haoming, Create the file. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/stat.h> #include <fcntl.h> #include <arpa/inet.h> #include <signal.h> #include <sys/wait.h> /**************************************************************************************************/ /* DEFINES */ /**************************************************************************************************/ #define PORT 80 #define BUFFER_SIZE 2048 /**************************************************************************************************/ /* TYPES */ /**************************************************************************************************/ /**************************************************************************************************/ /* EXTERN_PROTOTYPES */ /**************************************************************************************************/ /**************************************************************************************************/ /* LOCAL_PROTOTYPES */ /**************************************************************************************************/ const char *get_content_type(const char *path); void send_response(int client_fd, const char *path); /**************************************************************************************************/ /* VARIABLES */ /**************************************************************************************************/ /**************************************************************************************************/ /* LOCAL_FUNCTIONS */ /**************************************************************************************************/ /* 根据拓展名返回类型 */ const char *get_content_type(const char *path) { const char *ext = strrchr(path, '.'); /* strrchr从末尾查找至. */ if (ext) { if (strcmp(ext, ".html") == 0) return "text/html"; if (strcmp(ext, ".css") == 0) return "text/css"; if (strcmp(ext, ".js") == 0) return "application/javascript"; if (strcmp(ext, ".png") == 0) return "image/png"; if (strcmp(ext, ".jpg") == 0) return "image/jpeg"; } return "application/octet-stream"; /*默认返回二进制流*/ } /* 发送HTTP响应给客户端 */ void send_response(int client_fd, const char *path) { char header[BUFFER_SIZE]; /*响应头buffer*/ char buffer[BUFFER_SIZE]; /*内容buffer*/ struct stat st; /*文件状态*/ /* 文件不存在 */ if (stat(path, &st) == -1) { printf("该文件未找到:%s\n", path); /* 404 文件头 */ snprintf(header, BUFFER_SIZE, "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html\r\n" "\r\n" "<h1>404 Not Found</h1>"); send(client_fd, header, strlen(header), 0); return; } /*读取文件*/ int fd = open(path, O_RDONLY); if (fd < 0) { printf("打开该文件失败: %s\n", path); return; } /* 200 OK 文件头 */ snprintf(header, BUFFER_SIZE, "HTTP/1.1 200 OK\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n" "\r\n", get_content_type(path), st.st_size); send(client_fd, header, strlen(header), 0); printf("发送文件: %s (大小: %ld 字节)\n", path, st.st_size); /*发送给客户端*/ ssize_t bytes_read; while ((bytes_read = read(fd, buffer, BUFFER_SIZE)) > 0) { send(client_fd, buffer, bytes_read, 0); } close(fd); } /*客户端请求线程*/ void handle_client(int client_fd) { /*直接接受int*/ char buffer[BUFFER_SIZE]; char path[BUFFER_SIZE] = "./"; /* 默认./ */ char method[16] = {0}; /*存储请求方法*/ int content_length = 0; /* POST内容长度*/ /*读取客户端请求*/ ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1); if (bytes_read <= 0) { printf("读取客户端请求失败\n"); close(client_fd); return; } buffer[bytes_read] = '\0'; /* 获取客户端IP */ struct sockaddr_in addr;/*地址结构*/ socklen_t addr_len = sizeof(addr);/*地址长度*/ getpeername(client_fd, (struct sockaddr*)&addr, &addr_len);/*获取当前socket的对端地址*/ char client_ip[INET_ADDRSTRLEN];/*存储IP*/ inet_ntop(AF_INET, &addr.sin_addr, client_ip, sizeof(client_ip));/*将二进制IP转为字符串*/ printf("收到来自 %s 的请求:\n%.*s\n", client_ip, (int)bytes_read, buffer); /* 解析请求方法 */ sscanf(buffer, "%s %s", method, path + 2); /* path+2跳过./ */ /* 获取GET请求 */ if (strcmp(method, "GET") == 0) { if (strncmp(buffer, "GET ", 4) == 0) { char *start = buffer + 4; char *end = strchr(start, ' '); /* 查找空格结束 */ if (end) { *end = '\0'; /* 根目录 */ if (strcmp(start, "/") == 0) { strcat(path, "Index.html"); } else { /* 拼接根目录+路径 */ strncat(path, start, BUFFER_SIZE - strlen(path) - 1); } } } send_response(client_fd, path); } // 处理POST请求 (新增) else if (strcmp(method, "POST") == 0) { char *body_start = strstr(buffer, "\r\n\r\n"); if (body_start) { body_start += 4; // 跳过空行 char *content_len_ptr = strstr(buffer, "Content-Length: "); if (content_len_ptr) { sscanf(content_len_ptr, "Content-Length: %d", &content_length); } // 处理表单提交示例 if (strstr(path, "/submit") != NULL) { char response[BUFFER_SIZE]; snprintf(response, BUFFER_SIZE, "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\n\r\n" "<html><body>" "<h1>表单已提交</h1>" "<p>收到数据: %.*s</p>" "</body></html>", content_length, body_start); send(client_fd, response, strlen(response), 0); printf("处理POST数据: %.*s\n", content_length, body_start); } } } // 其他请求方法处理 else { const char *resp = "HTTP/1.1 405 Method Not Allowed\r\n\r\n"; send(client_fd, resp, strlen(resp), 0); } close(client_fd); printf("请求处理完成\n"); return; } int main() { signal(SIGPIPE, SIG_IGN); /*忽略SIGPIPE管道信号*/ printf("Web服务器启动,监听端口 %d \n", PORT); /*创建TCP套接字*/ int server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("创建套接字失败"); exit(EXIT_FAILURE); } /*允许快速重启,地址重用*/ int opt = 1; setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); /*配置服务器地址结构*/ struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(PORT), .sin_addr.s_addr = INADDR_ANY }; /* 绑定 */ if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("绑定端口失败"); exit(EXIT_FAILURE); } /* 监听 */ if (listen(server_fd, 10) < 0) { perror("监听失败"); exit(EXIT_FAILURE); } printf("服务器已启动\n"); /* 持续接收客户端连接*/ while (1) { struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); /*阻塞等到下一个客户端连接*/ int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len); if (client_fd < 0) { perror("接受连接失败"); continue; } /*非阻塞的回收僵尸进程,WNOHANG无子进程退出立即返回*/ while (waitpid(-1, NULL, WNOHANG) > 0); /*创建子进程处理客户端请求*/ pid_t pid = fork(); if (pid < 0) { perror("fork失败"); close(client_fd); } else if (pid == 0) { close(server_fd);/*子进程不用监听服务端*/ handle_client(client_fd); /*子进程处理客户端请求*/ exit(0); } else { close(client_fd); /*父进程不要客户端*/ } } close(server_fd); return 0; }
最新发布
08-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值