29.Nginx HTTP之请求行解析函数ngx_http_parse_request_line

2023-05-16

Nginx的HTTP模块中使用ngx_http_parse_request_line函数来对读取的请求行进行解析,HTTP请求行的格式不是很复杂,但是要注意HTTP 0.9与1.0、1.1之间的区别;另外,作为Nginx的第一个版本,里面支持的请求方法也只有GET、POST和HEAD。


/* http/ngx_http_parse.c */

/* 解析HTTP请求行
 * param r: 待处理的HTTP请求
 *       b: 存放请求行内容的缓冲区
 * return : 成功解析完整的请求行时返回NGX_OK;
 *          成功解析了部分请求行时返回NGX_AGAIN;
 *          否则返回其他
 */
ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
{
    // HTTP 0.9    请求行格式: [请求方法][空格..空格][URL](空格..空格)(回车符)[换行符]
    // HTTP >= 1.0 请求行格式: [请求方法][空格..空格][URL][空格..空格][协议版本][回车符][换行符]
    
    u_char  ch, *p, *m;
    
    enum {
        sw_start = 0,             // 初始状态
        sw_method,                // 解析请求方法
        sw_space_after_method,    // 解析请求方法后紧跟的一个空格
        sw_spaces_before_uri,     // 解析URL前可能存在的多余空格
        sw_schema,                // 解析schema(http/https)
        sw_schema_slash,          // 解析<schema>:后紧跟的一个/
        sw_schema_slash_slash,    // 解析<schema>:/后紧跟的一个/
        sw_host,                  // 解析<schema>://后紧跟的主机(域名/IP)
        sw_port,                  // 解析<schema>://<host>:后紧跟的端口
        sw_after_slash_in_uri,    // 解析URL路径中/后的内容
        sw_check_uri,             // ?
        sw_uri,                   // ?
        sw_http_09,               // 解析URL后紧跟空格后的内容
        sw_http_H,                // 解析协议版本的第二个字符T
        sw_http_HT,               // 解析协议版本的第三个字符T
        sw_http_HTT,              // 解析协议版本的第四个字符P
        sw_http_HTTP,             // 解析协议版本的第五个字符/
        sw_first_major_digit,     // 解析协议版本的主版本号的第一个数字
        sw_major_digit,           // 解析协议版本的主版本号第一个数字后的数字或者.
        sw_first_minor_digit,     // 解析协议版本的次版本号的第一个数字
        sw_minor_digit,           // 解析协议版本的次版本号第一个数字后的数字
        sw_almost_done,           // 解析结束的\n
        sw_done                   // 解析完成
    } state;                      // 枚举变量: HTTP请求行解析状态

    // 获取请求r的当前状态state
    state = r->state;
    // 获取缓冲区b的有效内容起始地址p
    p = b->pos;

    while (p < b->last && state < sw_done) {
        // p小于b->last时, 表明缓冲区内的有效内容不为空;
        // state小于sw_done, 表明未解析完成
        
        // ch指向缓冲区有效内容的第一个字符, p后移一位
        ch = *p++;

        switch (state) {

        /* HTTP methods: GET, HEAD, POST */
        case sw_start:
            // 当前状态为sw_start即起始状态
            
            // 置r->request_start为p-1, 也就是当前字符的位置
            r->request_start = p - 1;

            if (ch == CR || ch == LF) {
                // 如果当前字符为\r或者\n
                
                // 跳过
                break;
            }

            if (ch < 'A' || ch > 'Z') {
                // 如果当前字符不是大写字母
                
                // 请求方法必须是由大写字母组成的, 所以返回NGX_HTTP_PARSE_INVALID_METHOD,
                // 从字面上可以看出, 这个返回值表示无效的请求方法
                return NGX_HTTP_PARSE_INVALID_METHOD;
            }

            // 置state为sw_method, 表示解析请求方法
            state = sw_method;
            break;

        case sw_method:
            // 当前状态为解析请求方法
            
            if (ch == ' ') {
                // 如果当前字符为空格
                
                // 说明遇到了请求方法后面的空格了, p-2即为请求方法的最后一个字符
                // 置r->method_end为p-1, 记录请求方法的结束位置
                r->method_end = p - 1;
                // r->request_start此时指向的是请求方法的第一个字符
                m = r->request_start;

                if (r->method_end - m == 3) {
                    // 如果请求方法子字符串的长度为3

                    if (m[0] == 'G' && m[1] == 'E' && m[2] == 'T') {
                        // 如果请求方法子字符串为GET
                        
                        // 置r->method为NGX_HTTP_GET
                        r->method = NGX_HTTP_GET;
                    }

                } else if (r->method_end - m == 4) {
                    // 如果请求方法子字符串的长度为4

                    if (m[0] == 'P' && m[1] == 'O'
                        && m[2] == 'T' && m[3] == 'T')
                    {
                        // 如果请求方法子字符串为POST
                        
                        // 置r->method为NGX_HTTP_POST
                        r->method = NGX_HTTP_POST;

                    } else if (m[0] == 'H' && m[1] == 'E'
                               && m[2] == 'A' && m[3] == 'D')
                    {
                        // 如果请求方法子字符串为HEAD
                        
                        // 置r->method为NGX_HTTP_HEAD
                        r->method = NGX_HTTP_HEAD;
                    }
                }

                // 解析完请求方法, 置state为sw_spaces_before_uri, 表示解析URL前面的空格
                // 因为此处已经解析到一个请求方法后的空格, 所以跳过状态sw_space_after_method,
                state = sw_spaces_before_uri;
                break;
            }

            if (ch < 'A' || ch > 'Z') {
                // 如果当前字符不是大写字母
                
                // 返回NGX_HTTP_PARSE_INVALID_METHOD
                return NGX_HTTP_PARSE_INVALID_METHOD;
            }

            break;

        case sw_space_after_method:
            // 当前状态为解析请求方法后紧跟的一个空格
            
            switch (ch) {
            case ' ':
                // 如果当前字符为空格
                
                // 置state为sw_spaces_before_uri, URL前面可能还有空格
                state = sw_spaces_before_uri;
                break;
            default:
                // 如果当前字符为非空格的字符
                
                // 请求方法和URL之间至少需要一个空格,
                // 返回NGX_HTTP_PARSE_INVALID_METHOD
                return NGX_HTTP_PARSE_INVALID_METHOD;
            }
            break;

        case sw_spaces_before_uri:
            // 当前状态为解析URL前可能存在的多余空格
            
            switch (ch) {
            case '/':
                // 如果当前字符为/, 说明遇到URL的第一个字符
                
                // 置r->uri_start为p-1, 记录URL的起始位置
                r->uri_start = p - 1;
                // 置state为sw_after_slash_in_uri, 表示解析URL路径中/后的内容
                state = sw_after_slash_in_uri;
                break;
            case ' ':
                // 如果当前字符为空格
                
                // 直接跳过
                break;
            default:
                if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
                    // 如果当前字符为大小写字母, 说明遇到schema(http/https)的第一个字符了
                    
                    // 置r->schema_start为p-1, 记录schema的起始位置
                    r->schema_start = p - 1;
                    // 置state为sw_schema, 表示解析schema
                    state = sw_schema;
                    break;
                }
                // 当前字符为其他字符, 表示请求有误, 返回NGX_HTTP_PARSE_INVALID_REQUEST,
                // 即无效请求
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_schema:
            // 当前状态为解析schema
            
            switch (ch) {
            case ':':
                // 如果当前字符为:, 说明遇到schema的后一个字符了
                
                // 置r->schema_end为p-1, 记录schema的结束位置
                r->schema_end = p - 1;
                // 置state为sw_schema_slash, 表示解析<schema>:后紧跟的一个/
                state = sw_schema_slash;
                break;
            default:
                if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
                    // 如果当前字符是大小写字符, 说明是我们想要的
                    
                    // 直接跳过
                    break;
                }
                // 当前字符为其他字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_schema_slash:
            // 当前状态为解析<schema>:后紧跟的一个/
            switch (ch) {
            case '/':
                // 如果当前字符正是/
                
                // 置state为sw_schema_slash_slash, 解析紧跟的一个/
                state = sw_schema_slash_slash;
                break;
            default:
                // 当前字符不为/, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_schema_slash_slash:
            // 当前状态为解析<schema>:/后紧跟的一个/
            
            switch (ch) {
            case '/':
                // 如果当前字符正是/
                
                // 置r->host_start为p-1, 记录URL中主机的起始位置
                r->host_start = p - 1;
                // 置state为sw_host, 表示解析<schema>://后紧跟的主机
                state = sw_host;
                break;
            default:
                // 当前字符不为/, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_host:
            // 当前状态为解析<schema>://后紧跟的主机
            
            switch (ch) {
            case ':':
                // 如果当前字符为:, 说明遇到主机后紧跟的一个:了
                
                // 置r->host_end为p-1, 记录主机的结束位置
                r->host_end = p - 1;
                // 置state为sw_port, 因为遇到主机后紧跟的:了, 那么此:后需要跟着端口号
                state = sw_port;
                break;
            case '/':
                // 如果当前字符是/, 因为主机后的:<port>不是必须的,
                // 说明遇到主机后紧跟的一个/了
                
                // 置r->host_end为p-1, 记录主机的结束位置
                r->host_end = p - 1;
                // 置r->uri_start为p-1, 记录URL中路径的起始地址
                r->uri_start = p - 1;
                // 置state为sw_after_slash_in_uri, 表示解析URL路径中/后的内容
                state = sw_after_slash_in_uri;
                break;
            default:
                if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')
                    || (ch >= '0' && ch <= '9') || ch == '.' || ch == '-')
                {
                    // 如果当前字符为大小写字母、数字、.、-, 说明是主机(域名/IP)的有效字符
                    
                    // 直接跳过
                    break;
                }
                // 当前字符为其他字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_port:
            // 当前状态为解析<schema>://<host>:后紧跟的端口
            switch (ch) {
            case '/':
                // 如果当前字符为/, 说明遇到端口后紧跟的一个/了
                
                // 置r->port_end为p-1, 记录端口的结束位置
                r->port_end = p - 1;
                // 置r->uri_start为p-1, 记录URL中路径的起始位置
                r->uri_start = p - 1;
                // 置state为sw_after_slash_in_uri, 表示解析URL路径中/后的内容
                state = sw_after_slash_in_uri;
                break;
            default:
                if (ch < '0' && ch > '9') {
                    // 如果当前字符不为数字, 端口必须由数字组成, 说明是非法字符
                    // 返回NGX_HTTP_PARSE_INVALID_REQUEST
                    return NGX_HTTP_PARSE_INVALID_REQUEST;
                }
                break;
            }
            break;

        case sw_after_slash_in_uri:
            // 当前状态为解析URL路径中/后的内容
            switch (ch) {
            case CR:
                // 如果当前字符为\r, 说明可能是HTTP 0.9
                
                // 置r->uri_end为p-1, 记录URL中路径的结束位置
                r->uri_end = p - 1;
                // 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_almost_done, 表示解析结束的\n
                state = sw_almost_done;
                break;
            case LF:
                // 如果当前字符为\n, 说明可能是HTTP 0.9
                
                // 置r->uri_end为p-1, 记录URL中路径的结束位置
                r->uri_end = p - 1;
                // 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_done, 表示解析完成
                state = sw_done;
                break;
            case ' ':
                // 如果当前字符为空格, 表示遇到URL(或者路径)后紧跟的一个空格
                
                // 置r->uri_end为p-1, 记录URL中路径的结束位置
                r->uri_end = p - 1;
                // 置state为sw_http_09, 表示解析URL后紧跟空格后的内容
                state = sw_http_09;
                break;
            case '.':
            case '%':
                // 如果当前字符为.或者%, 说明是复杂的URL
                
                // 置r->complex_uri为1
                r->complex_uri = 1;
                // 置state为sw_uri
                state = sw_uri;
                break;
            case '/':
                // 如果当前字符为/
                
                // 置r->complex_uri为1
                // 因为仍要解析/后的内容, 因此state不变
                r->complex_uri = 1;
                break;
            case '?':
                // 如果当前字符为?, 说明遇到了URL中的参数
                
                // 置r->args_start为p, 记录参数的起始位置
                r->args_start = p;
                // 置state为sw_uri
                state = sw_uri;
                break;
            default:
                // 如果当前字符为其他字符
                // 置state为sw_check_uri
                state = sw_check_uri;
                break;
            }
            break;

        case sw_check_uri:
            // 当前状态为sw_check_uri
            
            switch (ch) {
            case CR:
                // 如果当前字符为\r, 说明遇到了URL后紧跟的\r
                
                // 置r->uri_end为p-1, 记录URL的结束位置
                r->uri_end = p - 1;
                // 显然是HTTP 0.9, 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_almost_done, 表示解析结束的\n
                state = sw_almost_done;
                break;
            case LF:
                // 如果当前字符为\n, 说明遇到了URL后紧跟的\n
                
                // 置r->uri_end为p-1, 记录URL的结束位置
                r->uri_end = p - 1;
                // 显然是HTTP 0.9, 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_done, 表示解析完成
                state = sw_done;
                break;
            case ' ':
                // 如果当前字符为空格, 表明遇到URL后紧跟的一个空格
                
                // 置r->uri_end为p-1, 记录URL的结束位置
                r->uri_end = p - 1;
                // 置state为sw_http_09, 表示解析URL后紧跟空格后的内容
                state = sw_http_09;
                break;
            case '.':
                // 如果当前字符为., 表明遇到扩展名
                
                // 置r->uri_ext为p, 记录扩展名的起始位置
                r->uri_ext = p;
                break;
            case '/':
                // 如果当前字符为/ 
                
                // 那么之前记录的"扩展名"其实不是真的扩展名, 置r->uri_ext为空
                r->uri_ext = NULL;
                // 置state为sw_after_slash_in_uri, 因为仍在解析URL且遇到了/
                state = sw_after_slash_in_uri;
                break;
            case '%':
                // 如果当前字符为%, 表明是复杂的URL
                
                // 置r->complex_uri为1
                r->complex_uri = 1;
                // 置state为sw_uri
                state = sw_uri;
                break;
            case '?':
                // 如果当前字符为?, 表明遇到了参数
                
                // 置r->args_start为p, 记录参数的起始位置
                r->args_start = p;
                // 置state为sw_uri
                state = sw_uri;
                break;
            }
            break;

        case sw_uri:
            // 当前状态为sw_uri
            
            switch (ch) {
            case CR:
                // 如果当前字符为\r, 说明遇到了URL后紧跟的\r
                
                // 置r->uri_end为p-1, 记录URL的结束位置
                r->uri_end = p - 1;
                // 显然是HTTP 0.9, 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_almost_done, 表示解析结束的\n
                state = sw_almost_done;
                break;
            case LF:
                // 如果当前字符为\n, 说明遇到了URL后紧跟的\n
                
                // 置r->uri_end为p-1, 记录URL的结束位置
                r->uri_end = p - 1;
                // 显然是HTTP 0.9, 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_done, 表示解析完成
                state = sw_done;
                break;
            case ' ':
                // 如果当前字符为空格, 表明遇到URL后紧跟的一个空格
                
                // 置r->uri_end为p-1, 记录URL的结束位置
                r->uri_end = p - 1;
                // 置state为sw_http_09, 表示解析URL后紧跟空格后的内容
                state = sw_http_09;
                break;
            }
            break;

        case sw_http_09:
            // 当前状态为解析URL后紧跟空格后的内容
            
            switch (ch) {
            case ' ':
                // 如果当前字符为空格, 直接跳过
                break;
            case CR:
                // 如果当前字符为\r, 说明是HTTP 0.9
                
                // 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_almost_done, 表示解析结束的\n
                state = sw_almost_done;
                break;
            case LF:
                // 如果当前字符为\n, 说明是HTTP 0.9
                
                // 置r->http_minor为9
                r->http_minor = 9;
                // 置state为sw_done, 表示解析完成
                state = sw_done;
                break;
            case 'H':
                // 如果当前字符是H, 说明是HTTP >= 1.0
                
                // 置state为sw_http_H, 表示解析协议版本的第二个字符T
                state = sw_http_H;
                break;
            default:
                // 当前字符为其他字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_http_H:
            // 当前状态为解析协议版本的第二个字符T
            switch (ch) {
            case 'T':
                // 如果当前字符正是T
                
                // 置state为sw_http_HT
                state = sw_http_HT;
                break;
            default:
                // 当前字符不为T, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_http_HT:
            // 当前状态为解析协议版本的第三个字符T
            
            switch (ch) {
            case 'T':
                // 如果当前字符正是T
                
                // 置state为sw_http_HTT
                state = sw_http_HTT;
                break;
            default:
                // 当前字符不为T, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_http_HTT:
            // 当前状态为解析协议版本的第四个字符P
            
            switch (ch) {
            case 'P':
                // 如果当前字符正是P
                
                // 置state为sw_http_HTTP
                state = sw_http_HTTP;
                break;
            default:
                // 当前字符不为P, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_http_HTTP:
            // 当前状态为解析协议版本的第五个字符/
            
            switch (ch) {
            case '/':
                // 如果当前字符正是/
                
                // 置state为sw_first_major_digit
                state = sw_first_major_digit;
                break;
            default:
                // 当前字符不为/, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_first_major_digit:
            // 当前状态为解析协议版本的主版本号的第一个数字
            if (ch < '1' || ch > '9') {
                // 如果当前字符不为数字1-9, 说明是无效字符;
                // 协议版本应该是在HTTP 1.0后才有的, 因此主版本号应该不小于1;
                // 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            // 置r->http_major为ch-'0', 记录主版本号
            r->http_major = ch - '0';
            // 置state为sw_major_digit, 表示解析协议版本的主版本号第一个数字后的数字或者.
            state = sw_major_digit;
            break;

        case sw_major_digit:
            // 当前状态为解析协议版本的主版本号第一个数字后的数字或者.
            
            if (ch == '.') {
                // 如果当前字符为., 说明遇到主版本号后紧跟的.了
                // 置state为sw_first_minor_digit, 表示解析次版本号的第一个数字
                state = sw_first_minor_digit;
                break;
            }

            if (ch < '0' || ch > '9') {
                // 如果当前字符不为数字, 说明是非法字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            // 更新主版本号r->http_major
            r->http_major = r->http_major * 10 + ch - '0';
            break;

        case sw_first_minor_digit:
            // 当前状态为解析协议版本的次版本号的第一个数字
            
            if (ch < '0' || ch > '9') {
                // 如果当前字符不为数字, 说明是非法字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            // 置r->http_minor为ch-'0', 记录次版本号
            r->http_minor = ch - '0';
            // 置state为sw_minor_digit, 表示解析协议版本的次版本号第一个数字后的数字
            state = sw_minor_digit;
            break;

        case sw_minor_digit:
            // 当前状态为解析协议版本的次版本号第一个数字后的数字
            
            if (ch == CR) {
                // 如果当前字符为\r, 说明遇到次版本号后紧跟的\r
                // 置state为sw_almost_done, 表示解析结束的\n
                state = sw_almost_done;
                break;
            }

            if (ch == LF) {
                // 如果当前字符为\n, 说明遇到次版本号后的\n
                // 置state为sw_done, 表示解析完成
                state = sw_done;
                break;
            }

            if (ch < '0' || ch > '9') {
                // 如果当前字符不为数字, 说明是非法字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            // 更新次版本号r->http_minor
            r->http_minor = r->http_minor * 10 + ch - '0';
            break;

        case sw_almost_done:
            // 当前状态为解析结束的\n
            
            // 置r->request_end为p-2, 记录请求行有效内容的结束位置
            r->request_end = p - 2;
            switch (ch) {
            case LF:
                // 如果当前字符正是\n
                
                // 置state为sw_done, 表示解析完成
                state = sw_done;
                break;
            default:
                // 如果当前字符不是\n, 那么就是非法字符, 返回NGX_HTTP_PARSE_INVALID_REQUEST
                return NGX_HTTP_PARSE_INVALID_REQUEST;
            }
            break;

        case sw_done:
            // 当前状态为解析完成, 直接退出循环
            break;
        }
    }

    // 置缓冲区的pos为p
    b->pos = p;

    if (state == sw_done) {
        // 如果state为sw_done, 表明解析完成
        
        if (r->request_end == NULL) {
            // 如果r->request_end为空
            
            // 置r->request_end为p-1, p-1即为请求行的结束位置
            r->request_end = p - 1;
        }

        // 求取HTTP版本, 规则为: 主版本号*1000+次版本号
        // 所以,0.9->9, 1.0->1000, 1.1->1001
        r->http_version = r->http_major * 1000 + r->http_minor;
        // 重置请求r的state为sw_start
        r->state = sw_start;

        if (r->http_version == 9 && r->method != NGX_HTTP_GET) {
            // 如果为HTTP 0.9且请求方法不为GET
            
            // 返回NGX_HTTP_PARSE_INVALID_09_METHOD, 说明HTTP 0.9只支持GET方法
            return NGX_HTTP_PARSE_INVALID_09_METHOD;
        }

        return NGX_OK;

    } else {
        // 没有解析完
        
        // 记录当前解析状态
        r->state = state;
        // 返回NGX_AGAIN
        return NGX_AGAIN;
    }
}





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

29.Nginx HTTP之请求行解析函数ngx_http_parse_request_line 的相关文章

  • HTTP请求压缩

    一般用例 想象一下一个正在上传大量 JSON 的客户端 内容类型应保留application json因为这描述了实际数据 Accept Encoding 和 Transfer Encoding 似乎是为了告诉服务器应该如何格式化响应 看起
  • 通过 http 的私有 git 存储库

    你能推荐任何简单的解决方案来设置可通过http s cleutus建议的 访问的git存储库吗 我有自己的 http 服务器 我想用它来托管一些小型私人项目 在家里我可以通过 ssh 连接 但在工作中防火墙阻止我这样做 有没有免费的方法来设
  • 使用 Django 管理界面的 Node.js 应用程序

    我想使用 node js 构建一个新应用程序 但它需要相当多的后端管理 而我宁愿不必构建 我在 django 中有一些现有代码 并且非常喜欢用于处理后端管理的内置管理界面 我是否可以使用 nginx 之类的东西将所有流量定向到我的 node
  • 使用 nginx 将 PATCH 请求代理为 POST

    我尝试使用 nginx 将 HTTP PATCH 请求重定向到 HTTP POST 请求 我还尝试了以下配置 但它不起作用 我收到 400 错误请求 http map request method my method default req
  • 是否有管理 __utma、__utmz 等 cookie 的标准?

    无论我登录 Facebook 还是 Twitter 我都会受到以下名称的 cookie 轰炸 utma utmb utmc utmv 它们的功能是什么 是否有一个标准来管理这些在服务器端的使用方式 这些 cookie 通常与谷歌分析 htt
  • 您可以从 AuthorizeAttribute 返回 HTTP 响应而不引发异常吗?

    我在各种控制器上使用 AuthorizeAttribute 可能需要根据请求本身的某些属性返回 403 或 429 请求过多 我完全在自定义 OnAuthorization 实现中实现了它 然后在必要时抛出一个带有适当响应代码的新 Http
  • HttpRequest PUT内容到poco库中

    我想使用 HTTP PUT 请求将一些数据从 C 应用程序发送到服务器 我在用poco http pocoproject org我的应用程序中的网络库 我正在使用这个代码片段 HTTPClientSession session uri ge
  • Perl:LWP::UserAgent 对于重定向 URL 始终返回代码 200

    我有一个简单的 url 它执行 302 临时错误 移至另一页 我尝试在 URL 返回代码 200 表示 OK 时检索它 并在返回 200 以外的其他内容时停止 My code my ua LWP UserAgent gt new env p
  • 是否可以修改 $_SESSION 变量?

    恶意用户是否可以将 SESSION 在 php 中 变量设置为他想要的任何值 很大程度上取决于您的代码 有一点非常明显 SESSION username REQUEST username
  • 强制 nginx 立即关闭连接

    如何让nginx在请求完成后立即关闭tcp连接 我刚刚找到了解决方案 location ip keepalive timeout 0
  • 以 RESTful 方式增加资源计数器:PUT 与 POST

    我有一个带有计数器的资源 为了举例 我们将该资源称为profile 计数器是数量views对于该配置文件 Per the 休息维基 http rest blueoxen net cgi bin wiki pl HttpMethods PUT
  • 使用 nginx 在云上部署 django 和 React

    我有一个 digitalocean 服务器 并且已经使用 Gunicorn 和 nginx 部署了 Django 后端服务器 如何在同一台服务器上部署 React 应用程序 您可以构建 React 应用程序并使用 Nginx 提供其静态文件
  • HTTP代理服务器

    我开始研究一个用 C 编写的非常基本的 HTTP 代理服务器 Edit 只是转发我的请求的东西 此时我很难理解如何继续 任何帮助都会有益的 看一眼micro proxy http acme com software micro proxy
  • 返回重定向作为对 Ajax(fetch、XHR 等)请求的响应

    如果浏览器收到对 ajax 请求的重定向响应 会发生什么 如果浏览器收到对 ajax 请求的重定向响应 会发生什么 如果服务器发送重定向 又名 302 响应加上 Location 标头 浏览器将自动遵循重定向 对此的回应second请求 假
  • Django 响应总是用 text/html 分块无法设置内容长度

    在我的Django应用程序的views py中 我在尝试设置以下HTTP标头字段后返回一个HttpResponse对象 Create a Response Object with the content to return response
  • nginx - 禁用特定 URL 的 HTTPS 重定向

    我将 nginx 设置为将所有 HTTP 请求重定向到 HTTPS 如下所示 Redirect every request to HTTPS server listen 80 listen 80 server name sub exampl
  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 浏览器显示 clojure 环中不存在 access-control-allow-origin 标头

    我通过客户端浏览器向服务器发出请求 如下所示https example com bar https example com bar 但出现错误 Access to XMLHttpRequest at https example com ba
  • 过滤条件的查询字符串与资源路径

    背景 我有2个资源 courses and professors A course具有以下属性 ID topic 学期号 年 部分 教授 id A professor具有以下属性 ID 学院 超级用户 名 姓 所以 你可以说一门课程有一位教
  • Kubernetes - 一个 Ingress 中的多个配置

    我在同一个 Kubernetes 集群中运行不同的应用程序 我希望多个域能够访问我的 Kubernetes 集群 并根据域进行重定向 对于每个域 我想要不同的注释 配置 如果没有注释 我的入口部署如下 apiVersion networki

随机推荐

  • ROS | 话题通信的编程实现

    ROS 话题通信的编程实现 1 创建功能包2 节点编程与消息定义2 1 案例说明2 2 话题消息的定义2 3 创建 cpp文件2 4 话题发布者编程2 5 话题订阅者编程 3 配置与编译3 1 在CMaKeLists txt中添加编译选项3
  • Cocos2dx 3.0配置环境

    3 15 cocos2dx 3 0rc0 终于放出来了 在这里不得不吐槽一件事 xff0c 3 0版本从Alpha xff0c 到beta xff0c 再到rc xff0c 三个版本竟然都有各自创建项目的方式 xff0c 这样真的不会被人打
  • linux 开机运行应用程序

    把运行应用程序的脚本放在 etc rc local里面 xff0c 如果没有 etc rc local xff0c 需要执行前面的3条指令新建这个文件 注意执行应用最好要在后台执行 xff08 后面加个 amp xff09 xff0c 否则
  • arm linux游戏手柄(joystick)驱动移植

    在arm linux中移植usb joystick驱动 xff0c 参考了如下经验 xff1a Linux系统中使用Xbox360手柄 知 行 博客园 cnblogs com 使用BlueZ连接蓝牙手柄 Dokin丶的博客 CSDN博客 蓝
  • linux ubuntu下网络调试助手(GUI)工具

    mNetAssist这个工具在ubuntu下可以运行 xff0c 是个带界面的tcp调试工具 1 UDP通讯 xff1b 2 可做 TCP客户端 xff1b 3 可做 TCP服务器 xff1b 4 可以 十六进制 传送接收数据 5 可以传送
  • fft的通俗解释

    FFT是离散傅立叶变换的快速算法 xff0c 可以将一个信号变换 到频域 有些信号在时域上是很难看出什么特征的 xff0c 但是如 果变换到频域之后 xff0c 就很容易看出特征了 这就是很多信号 分析采用FFT变换的原因 另外 xff0c
  • linux 字符驱动完整框架(poll,async,waitqueue,nonblock等)

    一个linux内核驱动的完整框架 xff0c 包含了能遇到的大部分内容 xff0c 例如timer poll async waitqueue nonblock等等 xff0c 不过基本上没啥大用 xff0c 就是用来熟悉基础的 xff0c
  • vscode远程调试Linux CUDA程序

    参考了 xff1a CUDA 01 第一个程序 知乎 zhihu com 1 本地安装插件 xff1a remote ssh xff0c Microsoft C C 43 43 与NVIDIA Nsight Visual Studio Co
  • 移植MQTT-C库(附源码)

    Software mqtt org 中mqtt客户端的c库里面有一个叫MQTT C的库 xff0c 就2个实现文件 xff0c 算比较简单的了 xff0c 实现了基本的mqtt客户端功能 xff0c 移植一下试试 我的移植代码放在我的资源里
  • TCP协议的滑动窗口和流量控制算法(转)

    目录 滑动窗口 流量控制 操作系统缓冲区与滑动窗口的关系 窗口关闭 糊涂窗口综合症 拥塞控制 慢启动 拥塞避免算法 拥塞发生 快速恢复 拥塞算法示意图 引入 窗口概念的原因 我们都知道 TCP 是每发送一个数据 xff0c 都要进行一次确认
  • linux应用中的时间处理

    参考下 xff1a Linux下有关时间的函数 xff1a time times clock gettimeofday等 linux time函数 见牛羊的博客 CSDN博客 下面的代码基本涵盖了获取时间和操作计时的一些函数使用 xff1a
  • 从旋转向量到欧拉角的六种计算方法

    利用SolvePNP解出旋转向量 xff0c 旋转向量通过罗德里格斯公式解出旋转矩阵 xff0c 然后通过下面六种公式计算即可 xff0c 欧拉角有十二种 xff0c 六种是相对于自身参考系 xff0c 六种是相对于惯性参考系 xff0c
  • ROS | 服务通信的编程实现

    ROS 服务通信的编程实现 1 创建功能包2 节点编程与服务数据定义2 1 案例说明2 2 服务数据的定义2 3 创建 cpp文件2 4 客户端编程2 5 服务器编程 3 配置与编译3 1 在CMaKeLists txt中添加编译选项3 2
  • HTTP基础验证

    HTTP 内置基础验证 浏览器收到401状态码响应后 xff0c 弹出要求输入信息的对话框 通过验证则显示内容 xff0c 不通过不显示需要验证身份的内容 1 xff1b 手动HTTP基础验证 xff1a header 39 http 1
  • 位域,段域,联合体,结构体操作寄存器

    include lt stdio h gt typedef int Uint16 struct SCICCR BITS bit description Uint16 SCICHAR 3 2 0 Character length contro
  • C++ 网络编程之使用socket + epoll 模拟http 的请求与响应

    为了更好的理解http协议 xff0c 笔者使用了C 43 43 socket模拟了一个http服务器 xff0c 其中的服务器使用了epoll的方式 xff0c 并针对每一个新的连接开启新线程处理 大致分为三个部分 xff0c 具体代码可
  • 【Nova】nova-scheduler过滤称重

    在上一篇 nova scheduler调度过程分析 中 xff0c 对过滤称重的过程一笔带过了 xff0c 这篇着重介绍一下 首先 xff0c 我们声明一下host为主机 xff0c node为节点 xff0c 在OpenStack中一个h
  • 1.通过tcp从daytime服务器获取时间

    最近愈发觉得在学习源代码或者看书的时候 xff0c 做下读书笔记 xff0c 不仅能加深印象和理解 xff0c 同时也方便日后进行回顾 xff0c 所以就写下UNP UNIX网络编程 卷1的读书笔记 xff0c 涉及到的代码基本都是原作者提
  • 4.IPv4和IPv6地址长度

    IPv4地址的二进制形式长度为32 xff0c 使用我们常用的点分十进制形式进行表示那么最长长度为15 xff0c 例如 255 255 255 255 所以在posix的 lt netinet in h gt 中定义的IPv4地址字符串形
  • 29.Nginx HTTP之请求行解析函数ngx_http_parse_request_line

    Nginx的HTTP模块中使用ngx http parse request line函数来对读取的请求行进行解析 xff0c HTTP请求行的格式不是很复杂 xff0c 但是要注意HTTP 0 9与1 0 1 1之间的区别 xff1b 另外