nginx openresty lua-resty-http 使用的一些问题记录

需求背景

需求是使用 nginx 做一个 https 服务的代理

nginx 收到 http 请求后,需要修改 body 中的某些参数值,然后将修改后的数据发送到目标服务器(https)

本来以为很简单的需求,结果中间出现了不少岔子,这里记录一下

知识点汇总

  1. location = xxx {} 是精确匹配,location xxx {} 是前缀匹配。
  2. 用 lua 脚本处理请求时,如果脚本找不到,客户端看到的是 404 not found,和路由配置错了一个样。
  3. lua-resty-http 模块管理员权限直接安装就行(不需要和 nginx 一起编译)。
  4. httpc:request_uri 请求时,必要的配置是 resolver(做 dns 解析);https 请求时,加上 ssl_verify = false 可以避免 https 证书带来的问题(python requests 包也有这个参数,但是不推荐使用,不安全)。
  5. 像这种靠近底层的工具如果修改了 http 请求的 body 时,一定要关注是否已经设置过 Content-Length 这个 header 了,可以去掉或者重新设置。否则可能造成的问题是 数据异常截断 或者 莫名奇妙的等待

详细问题

问题1:配置了 location 但是显示 404

代码如下

location = /aigw {content_by_lua_file conf/lua/aigw.lua;
}

这个代码先后改了两次,实际有两个原因客户端都会显示 404

  1. location = 是精确匹配,请求有后缀就找不到了
  2. 如果 conf/lua/aigw.lua 文件找不到,也不会提示内部错误信息,客户端看到的也是 404 问题

问题 2:module 'resty.http' not found:

使用如下命令安装,注意必须是 sudo 权限下,否则不行

sudo apt-get update
sudo apt-get install -y luarocks
sudo luarocks install lua-resty-http

问题 3:no resolver defined to resolve "xxxxx"

问题代码如下,这个错误是下面 err 的值

local res, err = httpc:request_uri(forwardUrl, {
...
})

解决方案:这个错误表明 NGINX 没有配置 DNS 解析器来解析 xxxxx 域名。你需要在 NGINX 配置文件中添加一个 resolver 指令来指定 DNS 服务器。

在 nginx.conf 文件的 http 或 server 块中添加以下内容:

http {resolver 8.8.8.8 8.8.4.4 valid=300s;resolver_timeout 5s;# 其他配置...
}

8.8.8.8 和 8.8.4.4 是 Google 的公共 DNS 服务器,你也可以使用其他 DNS 服务器。

添加后,重新加载 NGINX 配置:

sudo nginx -s reload

问题 4:unable to get local issuer certificate

这也是发送请求时的错误信息。

这个错误表明 NGINX 无法验证目标 HTTPS 服务器的 SSL 证书。下面是两种解决方案,我才用了第一种

  1. 忽略 SSL 证书验证(不推荐用于生产环境): 在 httpc:request_uri 调用中添加 ssl_verify = false 参数。

    local res, err = httpc:request_uri(forwardUrl, {method = ngx.req.get_method(),body = body_data,headers = ngx.req.get_headers(),ssl_verify = false  -- 这里是新增加的参数
    })
    
  2. 指定 CA 证书: 下载并指定一个可信的 CA 证书文件。(我没试过)
    首先,下载 CA 证书文件(例如 ca-certificates.crt),然后在 httpc:request_uri 调用中指定 ssl_ca_cert 参数。

    local res, err = httpc:request_uri(forwardUrl, {method = ngx.req.get_method(),body = body_data,headers = ngx.req.get_headers(),ssl_ca_cert = "/path/to/ca-certificates.crt"
    })
    

问题 5:修改请求 body 值之后,请求就卡住了

代码依旧是这个代码

local res, err = httpc:request_uri(forwardUrl, {method = ngx.req.get_method(),body = body_data,headers = ngx.req.get_headers(),ssl_verify = false
})

当我把 body_data 转为 json,修改其中的值,又转为字符串之后,这个网络请求就莫名奇妙的卡住了。

废了很大的力气查了很多资料也没有结果。自己调试打印了两组数据,对比了数据类型,还是没找到原因。

最后我打印了 ngx.req.get_method() 发现其中有一个头信息是

content-length: 216

猛然想到:因为我把 body 改小了,但是 content-length 值很大,这个 client 就会一直等着剩余的数据传输,所以就会一直卡着不动了。

修改方案是:

local new_headers = ngx.req.get_headers()
-- 删除 Content-Length 头,否则会导致 http client 卡住
new_headers["Content-Length"] = nil
new_headers["content-length"] = nillocal res, err = httpc:request_uri(forwardUrl, {method = ngx.req.get_method(),body = new_body,headers = new_headers,ssl_verify = false
})

问题 6:最终返回给客户端的数据是截断的

问题代码如下


-- res 是 httpc:request_uri 的返回值
ngx.status = res.status
for k, v in pairs(res.headers) doif k ~= "Transfer-Encoding" thenngx.header[k] = vend
end-- 将 body 中的 model 替换回去
local ok, res_body_json = pcall(cjson.decode, res.body)
if not ok thenngx.log(ngx.ERR, "Failed to decode JSON: ", res.body)ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
endres_body_json.model = model_prefix .. model_suffix
local new_res_body = cjson.encode(res_body_json)ngx.print(new_res_body)
ngx.exit(ngx.HTTP_OK)

上面的代码返回的 json 数据,一直只有一部分。

这个答案也很简单,和之前卡住的问题一样,因为我修改了返回的 body 值,而 ngx 在最开始逐一设置了 resheader 值,显然又把 Content-Length 带进去了。加上这么两句以后,问题解决:

ngx.header["Content-Length"] = #new_res_body
ngx.header["content-length"] = #new_res_body

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/60577.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue2+ element ui 集成pdfjs-dist

目录 1. 下载Pdf.js1.1 下载1.2 修改配置1.2.1 将pdfjs-3.8.162-dist复制到项目中1.2.2 解决跨域问题1.2.3 将pdf.worker.js文件复制到public目录下1.2.4 安装 pdfjs-dist1.2.5 前端vue代码(示例) 3. 参考资料 1. 下载Pdf.js 1.1 下载 下载链接(官方)需…

「Mac玩转仓颉内测版2」入门篇2 - 编写第一个Cangjie程序

本篇详细介绍在Mac系统上创建首个Cangjie项目并编写、运行第一个Cangjie程序的全过程。内容涵盖项目创建、代码编写、程序运行与调试,以及代码修改后的重新运行。通过本篇,掌握Cangjie项目的基本操作,进一步巩固开发环境的配置,迈…

@ComponentScan 和 @SpringBootApplication 同时使用出现问题

1 同时使用ComponentScan和SpringBootApplication,会导致SpringBootApplication所带的注解失效,请注意这个问题。我在使用mybatis时出现了找不到bean的问题,使用了ComponentScan导致Controller没有扫描到。 2 在springboot下使用mybatis时&a…

接单渠道,程序员看这篇就够了。

接单、兼职,有团队没单子?僧多粥少,苦矣。 很多程序员,有时间、有技术,有steam(咳咳,不对,是team)。但是,可能还是挣不到什么钱,何也&#xff1f…

【深度学习】使用硬件加速模型训练速度

一、 单机器单GPU 特点 配置简单:无需多 GPU 或分布式环境的复杂配置,适合资源有限的场景。适合小规模模型:对于计算量不大的模型(如中小型 CNN、RNN),单 GPU 可以处理大多数常见任务。 优势 简单易用&…

CSS:导航栏三角箭头

用CSS实现导航流程图的样式。可根据自己的需求进行修改,代码精略的写了一下。 注:场景一和场景二在分辨率比较低的情况下会有一个1px的缝隙不太优雅,自行处理。有个方法是直接在每个外面包一个DIV,用动态样式设置底色。 场景一、…

Qt_day4_Qt_UI设计

目录 Qt_UI设计 1. Designer 设计师(掌握) 2. Layout 布局(重点) 2.1 基本使用 2.2 高级用法 2.3 代码布局(了解) 3. Designer与C的关系(熟悉) 4. 基本组件(掌握…

sql专题 之 count()区别

文章目录 count(1)count(*)count(列名)比较 count(1) count(1) 是对结果集中的每一行计数,不关注具体的列,只是计数行数。 每一行都计为常数1 等同于 count(*),性能上基本一致,但有时…

嵌入式课程day14-C语言指针进阶

目录 10.3指针进阶 10.3.1数组指针 10.3.2指针数组 10.3.3函数指针 10.3.4指针函数 10.3.5函数指针的实际应用案例qsort函数: 10.3指针进阶 10.3.1数组指针 是指针 --- 指向对象的类型是 数组 int [3] 数组指针一般用于指向二维数组里面的一行,…

蓝桥杯模拟

【问题描述】 如果一个数 p 是个质数,同时又是整数 a 的约数,则 p 称为 a 的一个质因数。 请问 2024 有多少个质因数。 【答案提交】 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只…

Ruby编程语言全景解析:从基础到进阶

Ruby是一种动态的、面向对象的编程语言,以其优雅的语法和强大的功能而闻名于世。自从1995年由日本程序员松本行弘(Yukihiro Matsumoto)发布以来,Ruby便迅速成为了开发者中颇受欢迎的编程语言之一。无论是构建简单的脚本还是复杂的…

数据结构的时间复杂度和空间复杂度

目录 时间复杂度 空间复杂度 时间复杂度 基本操作的执行次数,为时间复杂度。 我们使用大O的渐进表示法来表示时间复杂度。 怎么使用? 先看例子: 在这个例子中, 基本操作为变量 count 的 加加 操作,并且,执行…

Ubuntu20.04 解决一段时间后键盘卡死 输入延迟很大的问题 ubuntu

Ubuntu20.04 解决一段时间后键盘卡死 输入延迟很大的问题 为了确保您能顺利通过双击快捷方式来重启 IBus,下面详细描述了从脚本创建到快捷方式设置的每一步,包括具体的命令行操作和必要的说明,以确保您能够按步骤成功执行。 步骤 1: 创建并…

解决Oracle DECODE函数字符串截断问题的深度剖析20241113

解决Oracle DECODE函数字符串截断问题的深度剖析 在使用Oracle数据库进行开发时,开发者可能会遇到一些令人困惑的问题。其中,在使用DECODE函数时,返回的字符串被截断就是一个典型的案例。本文将以学生管理系统为背景,深入探讨这个…

【Chapter 3】Machine Learning Classification Case_Prediction of diabetes-XGBoost

文章目录 1、XGBoost Algorithm2、Comparison of algorithm implementation between Python code and Sentosa_DSML community edition(1) Data reading and statistical analysis(2)Data preprocessing(3)Model Training and Evaluation(4)Model visualization 3、summarize 1…

Rust Struct 属性初始化

结构体是用户定义的数据类型,其中包含定义特定实例的字段。结构有助于实现更容易理解的抽象概念。本文介绍几种初始化结构体对象的方法,包括常规方法、Default特征、第三方包实现以及构建器模式。 Struct声明与初始化 struct Employee {id: i32,name: …

AI大模型微调:Qwen2大模型微调入门实战(完整代码)

简介: 该教程介绍了如何使用Qwen2,一个由阿里云通义实验室研发的开源大语言模型,进行指令微调以实现文本分类。微调是通过在(指令,输出)数据集上训练来改善LLMs理解人类指令的能力。教程中,使用…

树莓派(Raspberry Pi)Pico 2 C_C++开发环境配置(Docker+SDK)

树莓派(Raspberry Pi)Pico 2 C_C开发环境配置(DockerSDK) 开发环境容器系统环境配置配置 Raspberry Pi Pico 2 C/C 开发环境编译构建 Blink 示例程序下载 pico-sdk 和 pico-examples构建 Blink 链接 文章介绍了在容器中配置Raspbe…

剑指offer第二版(PDF+源码)

通过百度网盘分享的文件:剑指offer第二版(PDF源码).zip 链接:https://pan.baidu.com/s/11chsELiBIgjLR1mW7M8j1g?pwd1pq7 提取码:1pq7 《剑指Offer》第二版:开启求职编程之路的宝藏资源 在编程学习与求职准备的征程中&#xf…

Mac打开time machine(时间机器)备份特殊文件

Mac 打开time machine(时间机器)备份特殊文件 设置“时间机器”的作用具体操作办法 前言:今天在使用Nas同步文件时发现有部分重要文件没有同步,为了省事手动拖拽复制文件,导致其中一份非常重要的文件丢失,尝…