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的安装部署 主机: ...
随机推荐
- Zabbix Agent日志路径定位
Zabbix Agent的日志一般记录在zabbix_agentd.log中,那么如何定位.找到Zabbix Agent的日志路径呢? 下面从Linux操作系统和Windows系统来简单总结一下,方便 ...
- Java里一个线程两次调用start()方法会出现什么情况
Java的线程是不允许启动两次的,第二次调用必然会抛出IllegalThreadStateException,这是一种运行时异常,多次调用start被认为是编程错误. 如果业务需要线程run中的代码再 ...
- console线和RJ45
123 前言 一直以为console口和RJ45是同一种接口,but后来我发现我错了~ RJ45 先介绍一下RJ45吧 什么是RJ45? RJ45是一种接口 我们家用的网线的接口 其实就是RJ45 r ...
- ES ElasticSearch 7.x 下动态扩大索引的shard数量
ES ElasticSearch 7.x 下动态扩大索引的shard数量 背景 在老版本的ES(例如2.3版本)中, index的shard数量定好后,就不能再修改,除非重建数据才能实现. 从ES6. ...
- 3.AVPacket使用
1.使用注意 AVPacket需要用户通过av_packet_allc()创建好空间后.才能供给fimpeg进行获取解码前帧数据,由于解码前帧数据大小是不固定的(比如I帧数据量最大)所以ffmpeg会 ...
- IDEA创建新空项目
IDEA创建新空项目 File -> New -> Project -> Empty Project -> 然后OK 这个是什么都不能做的,然后我们创建Module. File ...
- axios+Qs请求数据转表单格式
import axios from 'axios' import qs from 'qs' axios.post('http://localhost:8888/baseitem/update', qs ...
- 第3章 02 python字符串类型及操作
字符串切片 取字符串从结尾到开头,相当于字符串逆序 转义符 转义符表达特定字符的本意 转义符 \“ ----> ” 字符串操作符 例子: 获取星期字符串 定义星期 获取用户 ...
- 关于弹性布局flex
什么时候使用flex布局? 当页面排版涉及左右浮动.垂直居中等时,应使用flex布局来避免传统的盒式布局带来的一些Bug. 如何使用flex布局? 在目标元素的父元素设置csss属性.display: ...
- python中yield的用法详解——最简单,最清晰的解释(转载)
原文链接 首先我要吐槽一下,看程序的过程中遇见了yield这个关键字,然后百度的时候,发现没有一个能简单的让我懂的,讲起来真TM的都是头头是道,什么参数,什么传递的,还口口声声说自己的教程是最简单的, ...