nginx的脚本引擎(一)
nginx的脚本的语法和shell是很像的,我大致看了一下觉得挺有意思的,就想写写记录一下。我没看过shell脚本的引擎,不知道nginx脚本引擎和shell脚本引擎像不像,但是我觉得nginx的脚本引擎有点像C和汇编。

ngx_http_script_engine_t这个结构就代表了一段脚本,ip指向的是编译好的脚本,sp指向的是一块内存用来存储脚本运行的时候产生的一些中间值。ip/sp从名字看就已经很像汇编了instruction pointer/stack pointer指令寄存器和栈寄存器呀,当然是我瞎猜的,有时间的话可以查一下官方文档。代码段里的各个指令长度不一定相同。
再来说说编译过程,编译过程是在nginx_http_script_engine_t建立之前执行的,我先画出了整个图是为了更好理解。举个set指令编译的的例子,比如你在脚本里有这样的代码set $foo helloworld,脚本编译的步骤如下:
第一步:首先在cmcf->variables_keys和cmcf->variables里增加一个变量foo,这个变量是可写的。我之前写的nginx的变量系统里只说了变量的读取方法,差别不大。
第二步:把ngx_http_script_value_code_t指令放到代码段里(code字段是一个回调函数,赋值成ngx_http_script_value_code),把ngx_http_script_var_code_t指令放到代码段里(code字段是一个回调函数,赋值成ngx_http_script_set_var_code)。
第三步:http请求来的时候会在rewrite阶段按顺序执行ip指向的这一段代码,也就是执行ngx_http_script_value_code和ngx_http_script_set_var_code函数。
我们看一下这两个函数做了什么
void
ngx_http_script_value_code(ngx_http_script_engine_t *e)
{
ngx_http_script_value_code_t *code; code = (ngx_http_script_value_code_t *) e->ip; e->ip += sizeof(ngx_http_script_value_code_t); e->sp->len = code->text_len;
e->sp->data = (u_char *) code->text_data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script value: \"%v\"", e->sp); e->sp++;
}
void
ngx_http_script_set_var_code(ngx_http_script_engine_t *e)
{
ngx_http_request_t *r;
ngx_http_script_var_code_t *code; code = (ngx_http_script_var_code_t *) e->ip; e->ip += sizeof(ngx_http_script_var_code_t); r = e->request; e->sp--; r->variables[code->index].len = e->sp->len;
r->variables[code->index].valid = 1;
r->variables[code->index].no_cacheable = 0;
r->variables[code->index].not_found = 0;
r->variables[code->index].data = e->sp->data;
}
第一条指令把“helloworld”这个字符串放到了sp里,第二条指令把值从sp里取出来存到了变量系统的foo变量里,任务完成,看起来很简单。
set指令还可以这样用set $foo $x$y,这就是所谓的变量插值,过程和上面这个类似,只不过第一条指令是先从变量系统里取出$x和$y的值,再放入sp里。
其他指令和set指令的执行过程类似,把我看到的也写一下吧
if指令:同样举个最简单的例子if( $host = "www.foo.com" ),编译的时候依次把ngx_http_script_var_code/ngx_http_script_value_code_t/ngx_http_script_equal_code/ngx_http_script_if_code四条指令放到代码段里。脚本运行的时候这几条指令的工作分别是ngx_http_script_var_code把变量host的值取出来放到sp里。ngx_http_script_value_code_t把字符串“www.foo.com”放到sp里。ngx_http_script_equal_code比较sp里存的两个值是否相等并把两个值清除掉,相等就在sp里写入“1”,不相等就写入“0”(比较完以后这两个值就没用了,清除掉这两个值并且写入结果很像C里函数调用的过程)。ngx_http_script_if_code检查sp里的值是不是“0”,不是“0”说明条件为真继续执行之后的脚本,是“0”说明条件为假就会跳过这一段代码执行ngx_http_script_if_code_t结构里next偏移之后的代码。所有的代码都是在一个代码段里,不会因为有if把代码做嵌套,只不过会用next跳来跳去。
有一点需要注意如果if在location里if体里可以做一些location的配置,比如root之类的。当NGX_HTTP_REWRITE_PHASE阶段执行脚本的时候会把新的loc_conf赋值给r->loc_conf,这个一定要注意是NGX_HTTP_REWRITE_PHASE阶段而不是NGX_HTTP_FIND_CONFIG_PHASE阶段,设置loc_conf一般情况是在NGX_HTTP_FIND_CONFIG_PHASE阶段,但是这次不是。
void
ngx_http_script_if_code(ngx_http_script_engine_t *e)
{
ngx_http_script_if_code_t *code; code = (ngx_http_script_if_code_t *) e->ip; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script if"); e->sp--; if (e->sp->len && (e->sp->len != 1 || e->sp->data[0] != '0')) {
if (code->loc_conf) {
e->request->loc_conf = code->loc_conf;
ngx_http_update_location_config(e->request);
} e->ip += sizeof(ngx_http_script_if_code_t);
return;
} ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script if: false"); e->ip += code->next;
}
return指令:这个是比较简单的,脚本执行到这个指令就直接返回了,参数了可以带数据,例如return 200 helloworld,此外还可以重定向return 302 http://www.nginx.org。
break指令:粗暴的结束目前的脚本,但是有一点要注意,如果break指令在location里面,他并不会影响location其他字段的设置,因为他们在不同的阶段执行。比如说设置如下的配置文件
location / {
root html;
break;
index index.html;
}
这一点都不会影响你的index指令,他们不在同一阶段,index是在NGX_HTTP_FIND_CONFIG_PHASE阶段,break是在NGX_HTTP_REWRITE_PHASE阶段,就像if指令里说的那样。
rewrite指令:这个略显麻烦,但是道理是一样的,休息,明天接着写。
nginx的脚本引擎(一)的更多相关文章
- nginx的脚本引擎(二)rewrite
其实rewrite指令和上一篇说的if/set/return/break之类的没多大差别,但是rewrite用起来相对复杂,我就把他单独放到了这里.想要弄懂nginx的脚本引擎需要先明白处理reque ...
- Java 8 的 Nashorn 脚本引擎教程
本文为了解所有关于 Nashorn JavaScript 引擎易于理解的代码例子. Nashorn JavaScript 引擎是Java SE 8的一部分,它与其它像Google V8 (它是Goog ...
- 【开源】.Net 动态脚本引擎NScript
开源地址: https://git.oschina.net/chejiangyi/NScript 开源QQ群: .net 开源基础服务 238543768 .Net 动态脚本引擎 NScript ...
- [No00007A]没有文件扩展".js"的脚本引擎 解决办法
在命令行运行JScript脚本时,遇到如下的错误提示: “输入错误: 没有文件扩展“.js”的脚本引擎.” 这样的错误,原因是因为JS扩展名的文件被其他软件关联了,需要取消关联. 如系统中安装了ULT ...
- 使用Lua脚本语言开发出高扩展性的系统,AgileEAS.NET SOA中间件Lua脚本引擎介绍
一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...
- linux nginx 启动脚本
linux nginx 启动脚本 [root@webtest76 ~]# vi /etc/init.d/nginx #!/bin/bash # nginx Startup script for the ...
- cocos2dx的build_win32.dat出现问题以及install-template-msvc.dat出现.js没有脚本引擎
关于cocos2dx-2.x.x版本当中出现build_win32.bat执行失败 (针对VS2013)应当在VS的安装路径查找msbuild的文件夹,再其中查找msbuild.exe文件找到四个东西 ...
- c# 动态执行脚本,相关的几个脚本引擎.
Jint 嵌入式的javascript脚本支持引擎,一直都在更新,对各种方法支持也比较好,可以 C# 交互. https://github.com/sebastienros/jint Jurass ...
- Nginx+Keepalived(带Nginx监控脚本)
转载于:http://www.itxuexiwang.com/a/liunxjishu/2016/0220/151.html?1456381460 Keepalived+ nginx的安装部署 主机: ...
随机推荐
- [Failed]Tomcat cluster方案共享session配置出错,sigh....
后继发展:https://www.cnblogs.com/xiandedanteng/p/12134300.html 参考网文一:多个Tomcat之间实现Session共享 参考网文二:Tomcat官 ...
- cookie和session讲解
1.cookie是什么? 保存在浏览器本地上的一组组键值对 2.session是什么? 保存在服务器上的一组组键值对 3.为什么要有cookie? HTTP是无协议状态,每次请求都是互相独立的,没有办 ...
- vue项目前端导出word文件(bug解决)
摘要:之前项目中导出价格表是由后端实现,前端只需要调用接口下载word即可,后来业务改变比较大,word模版需要一直改动,后端改起来相对麻烦,后来直接前端自己定义模版,实现下载word文档. 一.需要 ...
- meta生成器 —— 表单元素组件
手写代码? meta(json)需要手写吗?别闹,手写多麻烦呀,我这么懒怎么可能手写,这辈子都别想,所以要弄个工具出来,咱们说干就干. 这个工具,说白了本身就是一个表单,一个meta属性对应一个met ...
- pyhton:操作redis
一.redis介绍 redis是一种非关系型数据库:没有表结构,没有字段,没有sql语句.只是用get获取数据,set插数据,类似字典.比如mangodb,redis redis的数据全存在内存,re ...
- [算法]美团春招笔试题C-求有趣子序列数(DP)
题目 输入n,以及长度为n的数组元素 输出数组的非空子序列中有多少个"有趣序列"mod 998244353,有趣序列指所有元素满足arr[i]%i == 0, i从0记. 例: 输 ...
- 基于k8s的集群稳定架构
前言 我司的集群时刻处于崩溃的边缘,通过近三个月的掌握,发现我司的集群不稳定的原因有以下几点: 1.发版流程不稳定 2.缺少监控平台[最重要的原因] 3.缺少日志系统 4.极度缺少有关操作文档 5.请 ...
- hystrix(5) 延时检测
hystrix在执行命令的同事,会对执行延时进行检测,如果超过设置的延时时间,那么将停止执行,并返回fallback执行结果. if (properties.executionTimeoutEnabl ...
- 1.8HDFS细节
- Python推导式(列表推导式、元组推导式、字典推导式和集合推导式)
列表表达式 a_range = range(10) # 对a_range执行for表达式 a_list = [x * x for x in a_range] # a_list集合包含10个元素 pri ...