nginx提供了两种全异步方式来与第三方服务通信,分别是upstream和subrequest。

upstream:nginx为代理服务器,作消息透传。将第三方服务的内容原封不动的返回给用户。

subrequest:为客户请求创建子请求。访问第三方服务只是为了获取某些信息,再根据这些信息构造响应返回给用户。

upstream的使用方法

ngx_http_request_t中有一个ngx_http_upstream_t类型的成员upstream

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

nginx模块启动upstream机制的示意图

upstream执行的一般流程如下:

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:;
unsigned cacheable:;
unsigned accel:;
unsigned ssl:;
#if (NGX_HTTP_CACHE)
unsigned cache_status:;
#endif
//向客户端转发上游服务器包体时才有用,buffering=1表示使用多个缓冲区及磁盘文件转发上游包体,buffering=0表示只使用缓冲区buffer转发数据
unsigned buffering:;
unsigned keepalive:; unsigned request_sent:;
unsigned header_sent:;
};
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个超时时间是必须设置的,如下:

typedef struct {
...//连接上游服务器的超时时间
ngx_msec_t connect_timeout;
//发送TCP包到上游服务器的超时时间
ngx_msec_t send_timeout;
//接收TCP包到上游服务器的超时时间
ngx_msec_t read_timeout;
  ...
}ngx_http_upstream_conf_t

第三方服务器地址设置

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个必须实现的回调方法

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)无须在上、下游之间转发响应时,并不想完全接受到响应包体后才开始处理,希望能接受一部分就处理一部分,然后释放部分内存。

nginx 访问第三方服务(1)的更多相关文章

  1. Nginx:访问第三方服务

    参考资料<深入理解Nginx> Nginx可以当做一个强大的反向代理服务器,其反向代理模块是基于upstream方式实现的. upstream的使用方式 HTTP模块在处理任何一个请求时都 ...

  2. 《深入理解Nginx》阅读与实践(三):使用upstream和subrequest访问第三方服务

    本文是对陶辉<深入理解Nginx>第5章内容的梳理以及实现,代码和注释基本出自此书. 一.upstream:以向nginx服务器的请求转化为向google服务器的搜索请求为例 (一)模块框 ...

  3. Nginx模块开发(4)————使用subrequest访问第三方服务

    该模块可以完成如下的功能,当我们输入http://你的ip/lcw?s_sh000001时,会使用subrequest方式得到新浪服务器上的上证指数,代码如下: //start from the ve ...

  4. Nginx模块开发(3)————使用upstream访问第三方服务

    该模块可以完成如下的功能,当我们输入http://你的ip/lcwupstream时,会使用upstream方式访问淘宝搜索,打开淘宝搜索的主页面,代码如下: //start from the ver ...

  5. 使用upstream和subrequest访问第三方服务

    本文是对陶辉<深入理解Nginx>第5章内容的梳理以及实现,代码和注释基本出自此书. 一.upstream:以向nginx服务器的请求转化为向google服务器的搜索请求为例 (一)模块框 ...

  6. SAP云平台上的ABAP编程环境里如何消费第三方服务

    在ABAP On-Premises环境下,使用ABAP编程消费第三方服务,相信很多ABAP顾问都已经非常熟悉了,无非就是使用CL_HTTP_CLIENT或者CL_REST_HTTP_CLIENT来发送 ...

  7. 基于Docker + Consul + Nginx + Consul-Template的服务负载均衡实现(转)

    转:https://www.jianshu.com/p/fa41434d444a 前言 上一篇文章使用 Consul 和 Registrator 在 docker 的容器环境中搭建了服务注册和发现集群 ...

  8. windows+nginx+iis+redis+Task.MainForm构建分布式架构 之 (nginx+iis构建服务集群)

    本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,由标题就能看出此内容不是一篇分享文章能说完的,所以我打算分几篇分享文章来讲解,一步一步实现分 ...

  9. Windows下将nginx安装为服务运行

    今天看到nginx这个小服务器软件正式版更新到了1.4.2,想玩下它.这个服务器软件虽小,但功能强大,是开源软件,有着良好的性能,被很多个人.企业,甚至大型企业所使用! 由于是在Windows下,所以 ...

随机推荐

  1. WHY学习python?

    1.python更容易上手 2.功能库很多,不用重复造轮子 3.能干的事情很多(网站开发,爬虫,自动化运维,数据分析,游戏开发,人工智能) 网站开发:豆瓣,知乎 网站框架:django (姜狗) py ...

  2. LCD驱动分析【转】

    转自:http://blog.csdn.net/hanmengaidudu/article/details/21559153 1.S3C2440上LCD驱动 (FrameBuffer)实例开发讲解 其 ...

  3. 147.Insertion Sort List---链表排序(直接插入)

    题目链接 题目大意:对链表进行插入排序. 解法:直接插入排序.代码如下(耗时40ms): public ListNode insertionSortList(ListNode head) { List ...

  4. BZOJ - Problem 3622 - 已经没有什么好害怕的了

    题意: 给定两个序列$a$和$b$,让它们进行匹配,求出使得$a_i > b_j$的个数比$a_i < b_j$的个数恰好多$k$,求这样的匹配方法数 题解: 这题的各种表示有一点相似又截 ...

  5. C++中stringstream样例

    包含头文件 #include <sstream> 初始化可以使用 clear(). str( ) 赋值: 这里的clear方法,实际上是清空stringstream的状态(比如出错等),清 ...

  6. 查找网页元素对应的js代码

    按F12打开调试窗口,切换到Sources选项卡,最右边的Event Listener Breakpoints里勾选Mouse下的mouseover即可,当鼠标移动到图片上时触发mouseover事件 ...

  7. Redis实战(四)

    配置好了web.config程序,并且能通过C#代码来读取和管理以上配置信息. 接下来,就可以进行Redis的数据写入了.Redis中可以用Store和StoreAll分别保存单条和多条数据,C#中具 ...

  8. linux java环境变量设置

    下载JRE或者JDK后解压,设置以下环境变量 JAVA_HOME=/home/zm/jdk1.8.0_181JRE_HOME=/home/zm/jdk1.8.0_181/jreCLASSPATH=.: ...

  9. yum使用

    一.使用yum安装和卸载软件,有个前提是yum安装的软件包都是rpm格式的.安装的命令是,yum install ~,yum会查询数据库,有无这一软件包,如果有,则检查其依赖冲突关系,如果没有依赖冲突 ...

  10. jquery 美化弹出提示 漂亮的Dialog 对话框

    三个不同的效果,分别是普通的警告,确认/取消,带一个输入框 本例用了jquery.alertify.js,请到演示页面查看 css文件也请到演示页面查看 JavaScript Code <scr ...