Перейти к содержанию

link: Динамическая компоновка приложения с Nginx

Установка

Вы можете установить этот модуль в любом дистрибутиве на базе RHEL, включая, но не ограничиваясь:

  • RedHat Enterprise Linux 7, 8, 9 и 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 и Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-link
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-link

Активируйте модуль, добавив следующее в начало файла /etc/nginx/nginx.conf:

load_module modules/ngx_http_link_func_module.so;

Этот документ описывает nginx-module-link v3.2.4, выпущенный 13 октября 2020 года.


Логотип функции ссылки nginx

nginx-link-function

Динамическая компоновка приложения с Nginx

Введение

nginx-link-function — это модуль nginx, который предоставляет динамическую компоновку для вашего приложения в контексте сервера и вызывает функцию вашего приложения в директиве location. Вы можете напрямую связать ваше приложение на C/C++ (или любое другое, которое поддерживает динамическую компоновку) с сервером nginx.

Как это работает

Изображение nginx-link-function

Использование

## nginx.conf

server {
  listen 8888;
  ...
  ngx_link_func_lib "/path/to/your/libcfuntest.so";
  ...
  ...
  location = /testCFunGreeting {
      ngx_link_func_call "my_app_simple_get_greeting"; 
  }
}

server {
  listen 8989;
  aio threads;
  ...
  ngx_link_func_lib "/path/to/your/libcfuntest.so"; # совместное использование памяти с сервером 1, если пути совпадают
  ...
  ...
  location = /testCFunGreeting {
      ngx_link_func_call "my_app_simple_get_greeting" 
  }
}

server {
  listen 8999;
  aio threads;
  ...
  ngx_link_func_lib "/path/to/your/libcfuntest2.so"; # другое приложение
  ...
  ...
  location = /testPost {
      add_header Allow "GET, POST, HEAD" always;
      if ( $request_method !~ ^(POST)$ ) {
        return 405;
      }
      ngx_link_func_call "my_2nd_app_simple_get_token";
  }
}

server {
  listen 9888;
  aio threads;
  ...
  ## Загрузите приложение из облачного репозитория, например, ngx_link_func_download_link_lib <download_link> <dest_link_file>
  ngx_link_func_download_link_lib "http://abc.com/repos/libcfuntest.so" "/etc/nginx/libcfuntest3.so"
  ...
  ...
  location = /testPost {
      add_header Allow "GET, POST, HEAD" always;
      if ( $request_method !~ ^(POST)$ ) {
        return 405;
      }
      ngx_link_func_call "my_3rd_app_simple_get_token";
  }
}

server {
  listen 9898;
  aio threads;
  ...
  ## Загрузите приложение из облачного репозитория с дополнительным заголовком, например, ngx_link_func_download_link_lib <download_link> <headers> <dest_link_file>
  ngx_link_func_download_link_lib "https://abc.com/repos/libcfuntest.so" "Accept-Language:en_US\r\nAuthorization:Bearer KA.eyJ2ZXJzaadlasdlaldhjHJ2h3ldjklsjaklcjkljasdklcmasaskdaJxdkL3ftjM\r\n" "/etc/nginx/libcfuntest4.so"
  ...
  ...
  location = /testPost {
      add_header Allow "GET, POST, HEAD" always;
      if ( $request_method !~ ^(POST)$ ) {
        return 405;
      }
      ngx_link_func_call "my_other_app_simple_get_token";
  }
}

Интерфейс, предоставляемый клиентскому приложению

Это интерфейс, который вы можете использовать для получения более подробной информации от сервера nginx, он находится в файле ngx_link_func_module.h.

#define ngx_link_func_content_type_plaintext "text/plain"
#define ngx_link_func_content_type_html "text/html; charset=utf-8"
#define ngx_link_func_content_type_json "application/json"
#define ngx_link_func_content_type_jsonp "application/javascript"
#define ngx_link_func_content_type_xformencoded "application/x-www-form-urlencoded"

typedef struct {
  char *req_args; // Uri Args
  u_char *req_body; // Тело запроса
  size_t req_body_len; // длина тела
  void *shared_mem;

  /* внутренние */
  void* __r__;
  void* __pl__;
  void* __log__;
} ngx_link_func_ctx_t;

extern void ngx_link_func_log_debug(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_log_info(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_log_warn(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_log_err(ngx_link_func_ctx_t *ctx, const char* msg);
extern u_char* ngx_link_func_get_header(ngx_link_func_ctx_t *ctx, const char*key);
extern void* ngx_link_func_get_query_param(ngx_link_func_ctx_t *ctx, const char *key);
extern void* ngx_link_func_palloc(ngx_link_func_ctx_t *ctx, size_t size);
extern void* ngx_link_func_pcalloc(ngx_link_func_ctx_t *ctx, size_t size);

extern void ngx_link_func_write_resp(
    ngx_link_func_ctx_t *ctx,
    uintptr_t status_code,
    const char* status_line,
    const char* content_type,
    const char* resp_content,
    size_t resp_len
);


// Общая память и область кэша
extern void ngx_link_func_shmtx_lock(void *shared_mem);
extern void ngx_link_func_shmtx_unlock(void *shared_mem);
extern void* ngx_link_func_shm_alloc(void *shared_mem, size_t size);
extern void ngx_link_func_shm_free(void *shared_mem, void *ptr);
extern void* ngx_link_func_cache_get(void *shared_mem, const char* key);
extern void* ngx_link_func_cache_put(void *shared_mem, const char* key, void* value);
extern void* ngx_link_func_cache_new(void *shared_mem, const char* key, size_t size);
extern void ngx_link_func_cache_remove(void *shared_mem, const char* key);

Подробности интерфейса

malloc/calloc из пула nginx

void* ngx_link_func_palloc(ngx_link_func_ctx_t *ctx, size_t size);
void* ngx_link_func_pcalloc(ngx_link_func_ctx_t *ctx, size_t size);

получение параметра заголовка запроса

extern u_char* ngx_link_func_get_header(ngx_link_func_ctx_t *ctx, const char*key);

получение аргументов uri

ctx->req_args;

получение параметра запроса

extern void* ngx_link_func_get_query_param(ngx_link_func_ctx_t *ctx, const char *key);

получение тела запроса

ctx->req_body;

получение длины тела запроса

ctx->req_body_len;

логирование на сервер nginx

extern void ngx_link_func_log_debug(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_log_info(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_log_warn(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_log_err(ngx_link_func_ctx_t *ctx, const char* msg);

Ответ

extern void ngx_link_func_write_resp(
    ngx_link_func_ctx_t *ctx,
    uintptr_t status_code, // Код состояния
    const char* status_line, // Строка состояния
    const char* content_type, // Тип содержимого ответа
    const char* resp_content, // Содержимое ответа
    size_t resp_len // Длина содержимого ответа
);

Разработка примера приложения

Не стесняйтесь клонировать пример проекта на

Простой проект с cmake

направление функции ссылки google linkfunc-jwt-auth

#include <stdio.h>
#include <ngx_link_func_module.h>

/*** соберите программу как .so библиотеку и скопируйте в предпочтительное место для связи nginx с этой библиотекой ***/
/*** gcc -shared -o libcfuntest.so -fPIC cfuntest.c ***/
/*** cp libcfuntest.so /etc/nginx/ ***/

int is_service_on = 0;

void ngx_link_func_init_cycle(ngx_link_func_cycle_t* cycle) {
    ngx_link_func_cyc_log(info, cycle, "%s", "запуск приложения");

    is_service_on=1;
}

void my_app_simple_get_greeting(ngx_link_func_ctx_t *ctx) {
    ngx_link_func_log_info(ctx, "Обратный вызов и логирование из my_app_simple_get");

    ngx_link_func_write_resp(
        ctx,
        200,
        "200 OK",
        "text/plain",
        "приветствие от тестирования ngx_link_func",
        sizeof("приветствие от тестирования ngx_link_func")-1
    );
}

void my_app_simple_get_args(ngx_link_func_ctx_t *ctx) {
    ngx_link_func_log_info(ctx, "Обратный вызов и логирование из my_app_simple_get_args");

    if(ctx->req_args) {
        ngx_link_func_write_resp(
            ctx,
            200,
            "200 OK",
            "text/plain",
            ctx->req_args,
            strlen(ctx->req_args)
        );
    } else {
        ngx_link_func_write_resp(
            ctx,
            204,
            "",
            "text/plain",
            NULL,
            0
        );
    }
}

void my_app_simple_get_token_args(ngx_link_func_ctx_t *ctx) {
    ngx_link_func_log_info(ctx, "Обратный вызов и логирование из my_app_simple_get_token_args");

    char * tokenArgs = (char*)ngx_link_func_get_query_param(ctx, "token");
    if (! tokenArgs) {
        ngx_link_func_write_resp(
            ctx,
            401,
            "401 unauthorized",
            "text/plain",
            "Токен не найден",
            sizeof("Токен не найден")-1
        );
    } else {
        ngx_link_func_write_resp(
            ctx,
            401,
            "401 unauthorized",
            "text/plain",
            tokenArgs,
            strlen(tokenArgs)
        );
    }
}

void my_app_simple_post(ngx_link_func_ctx_t *ctx) {
    ngx_link_func_log_info(ctx, "Обратный вызов и логирование из my_app_simple_post");

    ngx_link_func_write_resp(
        ctx,
        202,
        "202 Accepted and Processing",
        "text/plain",
        NULL,
        0
    );
}

void my_app_simple_get_no_resp(ngx_link_func_ctx_t *ctx) {
    ngx_link_func_log_info(ctx, "Обратный вызов и логирование из my_app_simple_get_no_resp");

    //  вернуть 404 
}

void ngx_link_func_exit_cycle(ngx_link_func_cycle_t* cyc) {
    ngx_link_func_cyc_log(info, cyc, "%s\n", "Остановка/перезагрузка приложения");

    is_service_on = 0;
}

Примечание:

Функции инициализации и завершения цикла являются зарезервированными функциями, которые вызываются при запуске nginx, они вызывают функцию инициализации цикла, а при остановке/перезагрузке nginx вызывается функция завершения цикла.

void ngx_link_func_init_cycle(ngx_link_func_cycle_t* cyc){}
void ngx_link_func_exit_cycle(ngx_link_func_cycle_t* cyc){}
ссылки: хуки инициализации и завершения цикла в прикладном слое

Уровень логирования

Логирование может быть вызвано, записанное сообщение будет храниться там, где вы настроите error log в nginx.conf

ngx_link_func_log_info(ctx, "Это информационное прямое сообщение");
ngx_link_func_log(info, ctx, "%s", "Это информация с форматированным сообщением");
ngx_link_func_log_debug(ctx, "Это отладочное прямое сообщение");
ngx_link_func_log(debug, ctx, "%s", "Это отладка с форматированным сообщением");

ngx_link_func_log_info(ctx, "%s", "Это информация с форматированным сообщением"); // Неверный формат
ngx_link_func_log_debug(ctx, "%s", "Это информация с форматированным сообщением"); // Неверный формат

предоставьте ca-cert для загрузки вашего приложения (.so)? Пожалуйста, встроите это в контекст сервера вашего nginx.conf.

ngx_link_func_ca_cert "/etc/ssl/certs/ca-cert.crt"
ngx_link_func_download_link_lib "https://abc.com/repos/libcfuntest.so" "/etc/nginx/libcfuntest4.so"

предоставьте ca-cert и дополнительный заголовок для загрузки вашего приложения (.so)? Пожалуйста, встроите это в контекст сервера вашего nginx.conf.

ngx_link_func_ca_cert "/etc/ssl/certs/ca-cert.crt"
ngx_link_func_download_link_lib "https://abc.com/repos/libcfuntest.so" "Accept-Language:en_US\r\nAuthorization:Bearer KA.eyJ2ZXJzaadlasdlaldhjHJ2h3ldjklsjaklcjkljasdklcmasaskdaJxdkL3ftjM\r\n" "/etc/nginx/libcfuntest4.so"

Тестирование

Это зависит от библиотек тестового набора nginx, пожалуйста, обратитесь к test-nginx для установки.

cd /path/to/nginx-link-function
export PATH=/path/to/nginx-dirname:$PATH 
sudo prove -r t/

Поддержка

Пожалуйста, создайте issue, и я исправлю это как можно скорее.

В качестве альтернативы вы можете написать на электронную почту minikawoon2017@gmail.com.

Wiki

Посмотрите wiki для получения дополнительных деталей.

GitHub

Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-link.