Openresty学习(二):通过子请求完成Mysql的操作(增、删、改、查)

在上一篇文章(Openresty学习一)的基础上,完成mysql的增加、删除、修改、查询操作。


配置文件:

        upstream backend {
                drizzle_server localhost:3306 dbname=test password=xxxx user=root protocol=mysql;
                drizzle_keepalive max=100 mode=single overflow=reject;
        }


        location /mysql_test{
            client_body_in_single_buffer on;
            sub_request_mysql test;
        }

 location /mysql {
           set_unescape_uri $valid_query_string $query_string;
           drizzle_query $valid_query_string;
           drizzle_pass backend;
           drizzle_connect_timeout    500ms; # default 60s
           drizzle_send_query_timeout 2s;    # default 60s
           drizzle_recv_cols_timeout  1s;    # default 60s
           drizzle_recv_rows_timeout  1s;    # default 60s
           rds_json on;
}

 location /mysql_query {
            set_unescape_uri $name $arg_name;
            set $args 'select * from student where name="$name";';
            proxy_pass http://localhost/mysql;
}

       location /mysql_add {
            set_unescape_uri $name $arg_name;
            set_unescape_uri $age $arg_age;
            set $args 'insert into student(name,age) values("$name", "$age")';
            proxy_pass http://localhost/mysql;
}

        location /mysql_update {
            set_unescape_uri $name $arg_name;
            set_unescape_uri $age $arg_age;
            set $args 'update student set age="$age" where name="$name"';
            proxy_pass http://localhost/mysql;
        }

        location /mysql_delete {
            set_unescape_uri $name $arg_name;
            set $args 'delete from student where name="$name"';
            proxy_pass http://localhost/mysql;
        }


测试结果:

root@iZ2ze3uk97m2bfv681kyx4Z:~# curl -i -X POST -H "'Content-type':'application/json'" -d '{"cmd":"add","name":"maqi",tage":"32"}' http://47.93.228.87:80/mysql_test
HTTP/1.1 200 OK
Server: openresty/1.13.6.1
Date: Sat, 12 May 2018 04:09:26 GMT
Content-Type: text/plain; charset=GBK
Content-Length: 46
Connection: keep-alive

{"errcode":0,"insert_id":26,"affected_rows":1}root@iZ2ze3uk97m2bfv681kyx4Z:~# 

curl -i -X POST -H "'Content-type':'application/json'" -d '{"cmd":"query","name":"maqi"}' http://47.93.228.87:80/mysql_test

HTTP/1.1 200 OK
Server: openresty/1.13.6.1
Date: Sat, 12 May 2018 04:21:38 GMT
Content-Type: text/plain; charset=GBK
Content-Length: 34
Connection: keep-alive

[{"id":27,"name":"maqi","age":35}]

root@iZ2ze3uk97m2bfv681kyx4Z:~# curl -i -X POST -H "'Content-type':'application/json'" -d '{"cmd":"update","name":"maqi","age":"35"}' http://47.93.228.87:80/mysql_test
HTTP/1.1 200 OK
Server: openresty/1.13.6.1
Date: Sat, 12 May 2018 04:10:46 GMT
Content-Type: text/plain; charset=GBK
Content-Length: 83
Connection: keep-alive

{"errcode":0,"errstr":"Rows matched: 1 Changed: 1 Warnings: 0","affected_rows":1}

root@iZ2ze3uk97m2bfv681kyx4Z:~# curl -i -X POST -H "'Content-type':'application/json'" -d '{"cmd":"delete","name":"maqi","age":"35"}' http://47.93.228.87:80/mysql_test
HTTP/1.1 200 OK
Server: openresty/1.13.6.1
Date: Sat, 12 May 2018 04:19:57 GMT
Content-Type: text/plain; charset=GBK
Content-Length: 31
Connection: keep-alive

{"errcode":0,"affected_rows":1}


源码:

#include 
#include 
#include 

#include "cJSON.h"

typedef struct {
    ngx_str_t output_words;
    ngx_uint_t flag;
} ngx_http_sub_request_mysql_loc_conf_t;

static char* ngx_http_sub_request_mysql(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);

static void* ngx_http_sub_request_mysql_create_loc_conf(ngx_conf_t* cf);

static char* ngx_http_sub_request_mysql_merge_loc_conf(ngx_conf_t* cf, void* parent, void* child);

static ngx_command_t ngx_http_sub_request_mysql_commands[] = {
    {
        ngx_string("sub_request_mysql"), // The command name
        NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
        ngx_http_sub_request_mysql, // The command handler
        NGX_HTTP_LOC_CONF_OFFSET,
        offsetof(ngx_http_sub_request_mysql_loc_conf_t, output_words),
        NULL
    },

    ngx_null_command
};

// Structure for the HelloWorld context
static ngx_http_module_t ngx_http_sub_request_mysql_module_ctx = {
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    ngx_http_sub_request_mysql_create_loc_conf,
    ngx_http_sub_request_mysql_merge_loc_conf
};

// Structure for the HelloWorld module, the most important thing
ngx_module_t ngx_http_sub_request_mysql_module = {
    NGX_MODULE_V1,
    &ngx_http_sub_request_mysql_module_ctx,
    ngx_http_sub_request_mysql_commands,
    NGX_HTTP_MODULE,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NGX_MODULE_V1_PADDING
};

typedef struct {
    ngx_str_t name;
    ngx_str_t db_request_data;
} ngx_http_extern_request_mysql_ctx_t;

static void extern_db_request_post_handler(ngx_http_request_t *r)
{
    ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                                "%s: status[%d]",__FUNCTION__, r->headers_out.status); 

    if (r->headers_out.status != NGX_HTTP_OK)
    {
        ngx_http_finalize_request(r, r->headers_out.status);
        return;
    }

    ngx_http_extern_request_mysql_ctx_t *my_ctx = ngx_http_get_module_ctx(r,
            ngx_http_sub_request_mysql_module);

    int bodylen = my_ctx->db_request_data.len;
    r->headers_out.content_length_n = bodylen;

    ngx_buf_t *b = ngx_create_temp_buf(r->pool,bodylen);
    ngx_snprintf(b->pos, bodylen, (char *)my_ctx->db_request_data.data);
    b->last = b->pos + bodylen;
    b->last_buf = 1;

    ngx_chain_t out;
    out.buf = b;
    out.next = NULL;

    static ngx_str_t type = ngx_string("text/plain; charset=GBK");
    r->headers_out.content_type= type;
    r->headers_out.status =NGX_HTTP_OK; 

    r->connection->buffered |= NGX_HTTP_WRITE_BUFFERED;
    ngx_int_t ret = ngx_http_send_header(r);
    ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
            "%s: send header ret[%d]", __FUNCTION__, ret);
    ret = ngx_http_output_filter(r,&out);

    ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
            "%s: send body ret[%d]", __FUNCTION__, ret); 

    ngx_http_finalize_request(r,ret);
}

static ngx_int_t extern_db_sub_req_post_handler(ngx_http_request_t *r,
        void *data, ngx_int_t rc)
{
    ngx_str_t response_data;
    ngx_http_request_t *pr = r->parent;

    ngx_http_extern_request_mysql_ctx_t *my_ctx = ngx_http_get_module_ctx(pr,
            ngx_http_sub_request_mysql_module);
    pr->headers_out.status = r->headers_out.status;

    ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                                "%s: %d",__FUNCTION__, r->headers_out.status); 

    if (r->headers_out.status == NGX_HTTP_OK)
    {
        ngx_buf_t *sub_recv_buf = &r->upstream->buffer;

        response_data.data = sub_recv_buf->pos;
        response_data.len = ngx_buf_size(sub_recv_buf);

        ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                "data: %d, %V", response_data.len,
                &response_data);
        my_ctx->db_request_data.len = response_data.len;
        my_ctx->db_request_data.data = response_data.data;
    }

    pr->write_event_handler = extern_db_request_post_handler;

    return NGX_OK;
}

static void ngx_http_sub_request_mysql_client_body_handler_pt(ngx_http_request_t *r)
{
    ngx_int_t rc = NGX_OK;
    char log_buf[32] = {0};
    u_char body_buf[256] = {0};
    ngx_buf_t *p_body_buf = NULL;
    cJSON *root = NULL;
    cJSON *name = NULL;
    cJSON *command = NULL;
    cJSON *age = NULL;

    ngx_http_sub_request_mysql_loc_conf_t* hlcf = NULL;
    hlcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_request_mysql_module);
    if (NULL == hlcf)
    {
    }

    ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                          "%s", log_buf);

    p_body_buf = r->request_body->bufs->buf;
    ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                          "length:%d", ngx_buf_size(p_body_buf));
    
    ngx_snprintf(body_buf, sizeof(body_buf), "%*s",
            ngx_buf_size(p_body_buf), p_body_buf->pos);

    ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
            "main: receive body:%s", body_buf);

    root = cJSON_Parse((char *)body_buf);
    if (NULL == root)
    {
        return;
    }

    command = cJSON_GetObjectItemCaseSensitive(root, "cmd");
    if (NULL == command)
    {
        return;
    }
    
    name = cJSON_GetObjectItemCaseSensitive(root, "name");
    if (NULL == name)
    {
        return;
    }

    ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                          "parse cmd: %s, name: %s",
                          command->valuestring,
                          name->valuestring);    

    ngx_http_extern_request_mysql_ctx_t *my_ctx = ngx_http_get_module_ctx(r,
            ngx_http_sub_request_mysql_module);
    if (NULL == my_ctx)
    {
        my_ctx = ngx_palloc(r->pool, sizeof(ngx_http_extern_request_mysql_ctx_t));
        if (NULL == my_ctx)
        {
            return;
        }

        ngx_http_set_ctx(r, my_ctx, ngx_http_sub_request_mysql_module);
    }

    ngx_http_post_subrequest_t *my_sub_req = ngx_palloc(r->pool,
            sizeof(ngx_http_post_subrequest_t));
    if (NULL == my_sub_req)
    {
        return;
    }

    my_sub_req->handler = extern_db_sub_req_post_handler;

    my_sub_req->data = my_ctx;

    ngx_str_t sub_uri;
    ngx_str_t sub_args;

    if (0 == ngx_strncmp(command->valuestring, "query", strlen("query")))
    {
        sub_uri.len = ngx_strlen("/mysql_query");
        sub_uri.data = ngx_palloc(r->pool,sub_uri.len);
        ngx_snprintf(sub_uri.data, sub_uri.len, "%s",
               "/mysql_query");

        sub_args.len = ngx_strlen("name=") + ngx_strlen(name->valuestring);
        sub_args.data = ngx_palloc(r->pool,sub_args.len);
        ngx_snprintf(sub_args.data, sub_args.len, "%s%s",
               "name=", name->valuestring);
    }
    else if (0 == ngx_strncmp(command->valuestring, "add", strlen("add")))
    {
        age = cJSON_GetObjectItemCaseSensitive(root, "age");
        if (NULL == age)
        {
            return;
        }
        sub_uri.len = ngx_strlen("/mysql_add");
        sub_uri.data = ngx_palloc(r->pool,sub_uri.len);
        ngx_snprintf(sub_uri.data, sub_uri.len, "%s",
               "/mysql_add");

        sub_args.len = ngx_strlen("name=") + ngx_strlen(name->valuestring)
                + ngx_strlen("age=") + ngx_strlen(age->valuestring) + 1;
        sub_args.data = ngx_palloc(r->pool,sub_args.len);
        ngx_snprintf(sub_args.data, sub_args.len, "%s%s&%s%s",
               "name=", name->valuestring, "age=", age->valuestring);
    }
    else if (0 == ngx_strncmp(command->valuestring, "delete", strlen("delete")))
    {
        sub_uri.len = ngx_strlen("/mysql_delete");
        sub_uri.data = ngx_palloc(r->pool,sub_uri.len);
        ngx_snprintf(sub_uri.data, sub_uri.len, "%s",
               "/mysql_delete");

        sub_args.len = ngx_strlen("name=") + ngx_strlen(name->valuestring);
        sub_args.data = ngx_palloc(r->pool,sub_args.len);
        ngx_snprintf(sub_args.data, sub_args.len, "%s%s",
               "name=", name->valuestring);
    }
    else if (0 == ngx_strncmp(command->valuestring, "update", strlen("update")))
    {
        age = cJSON_GetObjectItemCaseSensitive(root, "age");
        if (NULL == age)
        {
            return;
        }
        sub_uri.len = ngx_strlen("/mysql_update");
        sub_uri.data = ngx_palloc(r->pool,sub_uri.len);
        ngx_snprintf(sub_uri.data, sub_uri.len, "%s",
               "/mysql_update");

        sub_args.len = ngx_strlen("name=") + ngx_strlen(name->valuestring)
                + ngx_strlen("age=") + ngx_strlen(age->valuestring) + 1;
        sub_args.data = ngx_palloc(r->pool,sub_args.len);
        ngx_snprintf(sub_args.data, sub_args.len, "%s%s&%s%s",
               "name=", name->valuestring, "age=", age->valuestring);
    }
    else
    {

    }

    ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                          "sub request uri: %V, args: %V",
                          &sub_uri, &sub_args);

    ngx_http_request_t *sr = NULL;
    rc = ngx_http_subrequest(r, &sub_uri, &sub_args,
            &sr, my_sub_req, NGX_HTTP_SUBREQUEST_IN_MEMORY);
    if (rc != NGX_OK)
    {
        return;
    }

    return;
}

static int ngx_response_info(ngx_http_request_t* r)
{
    ngx_int_t rc = NGX_OK;
    ngx_buf_t* b = NULL;
    ngx_chain_t out[2];
    cJSON *root = NULL;
    char json_buf[256] = {0};

    root = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "res-info",
    cJSON_CreateString("no account info in body"));

    r->headers_out.content_type.len = sizeof("application/json; charset=utf-8") - 1;
    r->headers_out.content_type.data = (u_char*)"application/json; charset=utf-8";

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));

    out[0].buf = b;
    out[0].next = NULL;

    snprintf(json_buf, sizeof(json_buf), "%s", cJSON_Print(root));
    ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
            "%s,length:%d", json_buf, strlen(json_buf));
    b->pos = (u_char*)cJSON_Print(root);
    b->last = b->pos + strlen(json_buf);

    b->memory = 1;
    b->last_buf = 1;

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = strlen(json_buf);
    rc = ngx_http_send_header(r);
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        return rc;
    }

    rc = ngx_http_output_filter(r, &out[0]);
    ngx_http_finalize_request(r,rc);

    cJSON_Delete(root);

    return rc;
}

static ngx_int_t ngx_http_sub_request_mysql_handler(ngx_http_request_t* r) {
    ngx_int_t rc = NGX_OK;
    int no_content_flag = 0;

    if (r->headers_in.content_length)
    {
        ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                                  "%s: content length is %d", __FUNCTION__,
                                  ngx_atoi(r->headers_in.content_length->value.data, r->headers_in.content_length->value.len));
    }
    else
    {
        no_content_flag = 1;
        ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                              "no content");
    }

    if (0 == no_content_flag && ngx_atoi(r->headers_in.content_length->value.data, r->headers_in.content_length->value.len) <= 0)
    {
       ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                              "in: content length is %d",
                              ngx_atoi(r->headers_in.content_length->value.data, r->headers_in.content_length->value.len));
        no_content_flag = 1;
        ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                              "no content");
    }

    ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                          "no content flag:%d", no_content_flag);
    if (no_content_flag)
    {
        return ngx_response_info(r);
    }

    rc = ngx_http_read_client_request_body(r,
            ngx_http_sub_request_mysql_client_body_handler_pt);

    if (rc >= NGX_HTTP_SPECIAL_RESPONSE)
    {
        ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
                          "%s", "unknown respone");
        return rc;
    }

    return NGX_DONE;
}

static void* ngx_http_sub_request_mysql_create_loc_conf(ngx_conf_t* cf) {
    ngx_http_sub_request_mysql_loc_conf_t* conf;

    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sub_request_mysql_loc_conf_t));
    if (conf == NULL) {
        return NGX_CONF_ERROR;
    }
    conf->output_words.len = 0;
    conf->output_words.data = NULL;

    conf->flag = NGX_CONF_UNSET;

    return conf;
}

static char* ngx_http_sub_request_mysql_merge_loc_conf(ngx_conf_t* cf, void* parent, void* child) {
    ngx_http_sub_request_mysql_loc_conf_t* prev = parent;
    ngx_http_sub_request_mysql_loc_conf_t* conf = child;

    ngx_conf_merge_str_value(conf->output_words, prev->output_words, "Nginx");
    ngx_conf_merge_uint_value(conf->flag, prev->flag,
            1);
    return NGX_CONF_OK;
}

static char* ngx_http_sub_request_mysql(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) {
    ngx_http_core_loc_conf_t* clcf;

    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    clcf->handler = ngx_http_sub_request_mysql_handler;
    ngx_conf_set_str_slot(cf, cmd, conf);

    return NGX_CONF_OK;
}



你可能感兴趣的:(Nginx&Redis&Lua)