nginx 訪問第三方服務(1)

nginx提供了兩種全異步方式來與第三方服務通訊,分別是upstream和subrequest。nginx

upstream:nginx爲代理服務器,做消息透傳。將第三方服務的內容原封不動的返回給用戶。服務器

subrequest:爲客戶請求建立子請求。訪問第三方服務只是爲了獲取某些信息,再根據這些信息構造響應返回給用戶。cookie

 

upstream的使用方法

ngx_http_request_t中有一個ngx_http_upstream_t類型的成員upstream框架

struct ngx_http_request_s {
    ...
    ngx_http_upstream_t              *upstream;
... }

nginx模塊啓動upstream機制的示意圖異步

upstream執行的通常流程以下:ui

ngx_http_upstream_t結構體以下,重點關注已經寫好註釋的幾個成員:
struct ngx_http_upstream_s {
    ngx_http_upstream_handler_pt     read_event_handler;
    ngx_http_upstream_handler_pt     write_event_handler;

    ngx_peer_connection_t            peer;

    ngx_event_pipe_t                *pipe;
    //決定發送什麼樣的請求給上游服務器
    ngx_chain_t                     *request_bufs;

    ngx_output_chain_ctx_t           output;
    ngx_chain_writer_ctx_t           writer;
    //upstream訪問時的限制性參數
    ngx_http_upstream_conf_t        *conf;

    ngx_http_upstream_headers_in_t   headers_in;
    //指定上游服務器地址
    ngx_http_upstream_resolved_t    *resolved;
    //存儲上游服務器發來的響應
    ngx_buf_t                        buffer;
    off_t                            length;

    ngx_chain_t                     *out_bufs;
    ngx_chain_t                     *busy_bufs;
    ngx_chain_t                     *free_bufs;

    ngx_int_t                      (*input_filter_init)(void *data);
    ngx_int_t                      (*input_filter)(void *data, ssize_t bytes);
    void                            *input_filter_ctx;

#if (NGX_HTTP_CACHE)
    ngx_int_t                      (*create_key)(ngx_http_request_t *r);
#endif
    //構造發往上游服務器的請求
    ngx_int_t                      (*create_request)(ngx_http_request_t *r);
    ngx_int_t                      (*reinit_request)(ngx_http_request_t *r);
    //收到上游服務器響應後的回調方法
    ngx_int_t                      (*process_header)(ngx_http_request_t *r);
    void                           (*abort_request)(ngx_http_request_t *r);
    //銷燬upstream請求時調用
    void                           (*finalize_request)(ngx_http_request_t *r,
                                         ngx_int_t rc);
    ngx_int_t                      (*rewrite_redirect)(ngx_http_request_t *r,
                                         ngx_table_elt_t *h, size_t prefix);
    ngx_int_t                      (*rewrite_cookie)(ngx_http_request_t *r,
                                         ngx_table_elt_t *h);

    ngx_msec_t                       timeout;

    ngx_http_upstream_state_t       *state;

    ngx_str_t                        method;
    ngx_str_t                        schema;
    ngx_str_t                        uri;

    ngx_http_cleanup_pt             *cleanup;

    unsigned                         store:1;
    unsigned                         cacheable:1;
    unsigned                         accel:1;
    unsigned                         ssl:1;
#if (NGX_HTTP_CACHE)
    unsigned                         cache_status:3;
#endif
    //向客戶端轉發上游服務器包體時纔有用,buffering=1表示使用多個緩衝區及磁盤文件轉發上游包體,buffering=0表示只使用緩衝區buffer轉發數據
    unsigned                         buffering:1;
    unsigned                         keepalive:1;

    unsigned                         request_sent:1;
    unsigned                         header_sent:1;
};
upstream有3種方式處理上游的包體,這由ngx_http_request_t中的subrequest_in_memory決定:

(1)subrequest_in_memory=1,upstream不轉發響應包體,由input_filter方法處理
(2)subrequest_in_memory=0,buffering=1  以多個緩衝區和磁盤文件轉發包體
(3)subrequest_in_memory=0,buffering=0  以固定的大小的緩衝區轉發包體

 upstream限制性參數ngx_http_upstream_conf_t,其中3個超時時間是必須設置的,以下:spa

typedef struct {
    ...//鏈接上游服務器的超時時間
    ngx_msec_t                       connect_timeout;
    //發送TCP包到上游服務器的超時時間
    ngx_msec_t                       send_timeout;
    //接收TCP包到上游服務器的超時時間
    ngx_msec_t                       read_timeout;
  ... }ngx_http_upstream_conf_t

第三方服務器地址設置3d

typedef struct {
    ngx_str_t                        host;
    in_port_t                        port;
    ngx_uint_t                       no_port; /* unsigned no_port:1 */
    //地址個數
    ngx_uint_t                       naddrs;
    
    in_addr_t                       *addrs;
    //地址
    struct sockaddr                 *sockaddr;
    socklen_t                        socklen;

    ngx_resolver_ctx_t              *ctx;
} ngx_http_upstream_resolved_t;

設置回調方法代理

包括3個必須實現的回調方法code

ngx_int_t                      (*create_request)(ngx_http_request_t *r);
ngx_int_t                      (*process_header)(ngx_http_request_t *r);
void                           (*finalize_request)(ngx_http_request_t *r, ngx_int_t rc);

5個可選的回調方法

ngx_int_t                      (*input_filter_init)(void *data);
ngx_int_t                      (*input_filter)(void *data, ssize_t bytes);
ngx_int_t                      (*reinit_request)(ngx_http_request_t *r);
void                           (*abort_request)(ngx_http_request_t *r);
ngx_int_t                      (*rewrite_redirect)(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix);

啓動upstream機制

直接執行ngx_http_upstream_init便可啓動upstream機制,例如:

static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
{
    ...
    r->main->count++;
    ngx_http_upstream_init(r);
    return NGX_DONE;
}

經過返回NGX_DONE讓HTTP框架停在執行請求的下一個階段。這裏執行r->main->count++是在告訴HTTP框架將當前請求的引用計數加1,暫時不要銷燬該請求。

回調方法執行場景時序圖以下:

 reinit_request回調方法

reinit_request被回調的緣由只有1個:向上遊服務器創建TCP鏈接失敗,根據conf中的參數再次重連上游服務器,而這時就會調用reinit_request方法。

 

finalize_request回調方法

使用ngx_http_upstream_init啓動upstream機制後,在各類緣由致使該請求被銷燬前,都會調用finalize_request中的方法。此方法必須實現。

process_header回調方法

用於解析上游服務器返回的基於HTTP的響應頭部的,若是process_header返回NGX_AGAIN,意味着還沒收到完整的頭部,下次仍會調用process_header;若是返回NGX_OK,process_header不會再次調用

 

input_filter_init和input_filter回調方法

都用於處理上游服務器的響應包體,由於處理響應包體前可能須要作一些初始化工做,能夠放在input_filter_init中。input_filter用於實際處理包體。如下場景比較適合從新實現input_filter_init和input_filter回調方法

(1)轉發上游響應到下游時,須要作一些特殊處理

(2)無須在上、下游之間轉發響應時,並不想徹底接受到響應包體後纔開始處理,但願能接受一部分就處理一部分,而後釋放部份內存。

相關文章
相關標籤/搜索