NGINX 从 proxy_pass 响应中读取正文
NGINX read body from proxy_pass response
我有两台服务器:
- NGINX(它将文件 ID 交换为文件路径)
- Golang(它接受文件 ID 和 return 它的路径)
例如: 当浏览器客户端向 https://example.com/file?id=123
发出请求时,NGINX 应该将此请求代理到 Golang 服务器 https://go.example.com/getpath?file_id=123
,后者将 return对 NGINX 的回应:
{
data: {
filePath: "/static/..."
},
status: "ok"
}
然后 NGINX 应该从 filePath 和 return file 从该位置获取值。
所以问题是如何在 NGINX 中读取响应(获取文件路径)?
看起来您想要 api 调用数据以反对 运行 决策和逻辑。这不是代理的全部内容。
nginx 的核心代理能力并不是为您的目的而设计的。
可能的解决方法:扩展 nginx...
Nginx + PHP
您的 php 代码可以解决问题。
作为客户端连接到 Golang 服务器并对响应应用附加逻辑。
<?php
$response = file_get_contents('https://go.example.com/getpath?file_id='.$_GET["id"]);
preg_match_all("/filePath: \"(.*?)\"/", $response, $filePath);
readfile($filePath[1][0]);
?>
location /getpath {
try_files /getpath.php;
}
这只是让它滚动的伪代码示例。
一些杂项观察/评论:
- Golang 响应看起来无效 json,如果有效,请将 preg_match_all 替换为 json_decode。
- readfile 效率不高。考虑通过 302 响应发挥创意。
Nginx + Lua
已启用站点:
lua_package_path "/etc/nginx/conf.d/lib/?.lua;;";
server {
listen 80 default_server;
listen [::]:80 default_server;
location /getfile {
root /var/www/html;
resolver 8.8.8.8;
set $filepath "/index.html";
access_by_lua_file /etc/nginx/conf.d/getfile.lua;
try_files $filepath =404;
}
}
测试 lua 是否按预期运行:
getfile.lua (v1)
ngx.var.filepath = "/static/...";
将 Golang 响应主体简化为 return 一个平淡的路径,然后用它来设置文件路径:
getfile.lua (v2)
local http = require "resty.http"
local httpc = http.new()
local query_string = ngx.req.get_uri_args()
local res, err = httpc:request_uri('https://go.example.com/getpath?file_id=' .. query_string["id"], {
method = "GET",
keepalive_timeout = 60,
keepalive_pool = 10
})
if res and res.status == ngx.HTTP_OK then
body = string.gsub(res.body, '[\r\n%z]', '')
ngx.var.filepath = body;
ngx.log(ngx.ERR, "[" .. body .. "]");
else
ngx.log(ngx.ERR, "missing response");
ngx.exit(504);
end
mkdir -p /etc/nginx/conf.d/lib/resty
wget "https://raw.githubusercontent.com/ledgetech/lua-resty-http/master/lib/resty/http_headers.lua" -P /etc/nginx/conf.d/lib/resty
wget "https://raw.githubusercontent.com/ledgetech/lua-resty-http/master/lib/resty/http.lua" -P /etc/nginx/conf.d/lib/resty
我假设您是软件开发人员并且您可以完全控制您的应用程序,因此无需在此处强行将方钉插入圆孔。
不同类型的反向代理支持ESI(Edge Side Includes)技术,允许开发者用静态文件内容或响应替换响应的不同部分body来自上游服务器的正文。
Nginx也有这样的技术。它被称为 SSI(服务器端包含)。
location /file {
ssi on;
proxy_pass http://go.example.com;
}
您的上游服务器可以生成内容为 <!--# include file="/path-to-static-files/some-static-file.ext" -->
的 body 并且 nginx 会将此 in-body 指令替换为文件 的内容。
但是你提到了流媒体...
这意味着文件将具有任意大小并且使用 SSI 构建响应肯定会占用宝贵的 RAM 资源,因此我们需要一个 计划 #B.
有 "good enough" 方法可以将大文件提供给客户端而不向客户端显示文件的静态位置。
您可以使用 nginx 的错误处理程序根据上游服务器提供的信息来处理静态文件。
例如,上游服务器可以发送回重定向 302,其中 Location header 字段包含文件的真实文件路径。
此响应未到达客户端并被馈送到错误处理程序中。
配置示例如下:
location /file {
error_page 302 = @service_static_file;
proxy_intercept_errors on;
proxy_set_header Host $host;
proxy_pass http://go.example.com;
}
location @service_static_file {
root /hidden-files;
try_files $upstream_http_location 404.html;
}
使用此方法,您将能够在没有 over-loading 系统的情况下提供文件,同时可以控制您将文件提供给谁。
为此,您的上游服务器应以状态 302 和典型的 "Location:" 字段进行响应,nginx 将使用位置内容在 "new" 根目录中查找静态文件的文件。
这个方法之所以是"good enough"类型的(而不是完美的)是因为它不支持部分请求(即Range: bytes ...)
我有两台服务器:
- NGINX(它将文件 ID 交换为文件路径)
- Golang(它接受文件 ID 和 return 它的路径)
例如: 当浏览器客户端向 https://example.com/file?id=123
发出请求时,NGINX 应该将此请求代理到 Golang 服务器 https://go.example.com/getpath?file_id=123
,后者将 return对 NGINX 的回应:
{
data: {
filePath: "/static/..."
},
status: "ok"
}
然后 NGINX 应该从 filePath 和 return file 从该位置获取值。
所以问题是如何在 NGINX 中读取响应(获取文件路径)?
看起来您想要 api 调用数据以反对 运行 决策和逻辑。这不是代理的全部内容。
nginx 的核心代理能力并不是为您的目的而设计的。
可能的解决方法:扩展 nginx...
Nginx + PHP
您的 php 代码可以解决问题。
作为客户端连接到 Golang 服务器并对响应应用附加逻辑。
<?php
$response = file_get_contents('https://go.example.com/getpath?file_id='.$_GET["id"]);
preg_match_all("/filePath: \"(.*?)\"/", $response, $filePath);
readfile($filePath[1][0]);
?>
location /getpath {
try_files /getpath.php;
}
这只是让它滚动的伪代码示例。
一些杂项观察/评论:
- Golang 响应看起来无效 json,如果有效,请将 preg_match_all 替换为 json_decode。
- readfile 效率不高。考虑通过 302 响应发挥创意。
Nginx + Lua
已启用站点:
lua_package_path "/etc/nginx/conf.d/lib/?.lua;;";
server {
listen 80 default_server;
listen [::]:80 default_server;
location /getfile {
root /var/www/html;
resolver 8.8.8.8;
set $filepath "/index.html";
access_by_lua_file /etc/nginx/conf.d/getfile.lua;
try_files $filepath =404;
}
}
测试 lua 是否按预期运行:
getfile.lua (v1)
ngx.var.filepath = "/static/...";
将 Golang 响应主体简化为 return 一个平淡的路径,然后用它来设置文件路径:
getfile.lua (v2)
local http = require "resty.http"
local httpc = http.new()
local query_string = ngx.req.get_uri_args()
local res, err = httpc:request_uri('https://go.example.com/getpath?file_id=' .. query_string["id"], {
method = "GET",
keepalive_timeout = 60,
keepalive_pool = 10
})
if res and res.status == ngx.HTTP_OK then
body = string.gsub(res.body, '[\r\n%z]', '')
ngx.var.filepath = body;
ngx.log(ngx.ERR, "[" .. body .. "]");
else
ngx.log(ngx.ERR, "missing response");
ngx.exit(504);
end
mkdir -p /etc/nginx/conf.d/lib/resty
wget "https://raw.githubusercontent.com/ledgetech/lua-resty-http/master/lib/resty/http_headers.lua" -P /etc/nginx/conf.d/lib/resty
wget "https://raw.githubusercontent.com/ledgetech/lua-resty-http/master/lib/resty/http.lua" -P /etc/nginx/conf.d/lib/resty
我假设您是软件开发人员并且您可以完全控制您的应用程序,因此无需在此处强行将方钉插入圆孔。
不同类型的反向代理支持ESI(Edge Side Includes)技术,允许开发者用静态文件内容或响应替换响应的不同部分body来自上游服务器的正文。
Nginx也有这样的技术。它被称为 SSI(服务器端包含)。
location /file {
ssi on;
proxy_pass http://go.example.com;
}
您的上游服务器可以生成内容为 <!--# include file="/path-to-static-files/some-static-file.ext" -->
的 body 并且 nginx 会将此 in-body 指令替换为文件 的内容。
但是你提到了流媒体...
这意味着文件将具有任意大小并且使用 SSI 构建响应肯定会占用宝贵的 RAM 资源,因此我们需要一个 计划 #B.
有 "good enough" 方法可以将大文件提供给客户端而不向客户端显示文件的静态位置。 您可以使用 nginx 的错误处理程序根据上游服务器提供的信息来处理静态文件。 例如,上游服务器可以发送回重定向 302,其中 Location header 字段包含文件的真实文件路径。 此响应未到达客户端并被馈送到错误处理程序中。
配置示例如下:
location /file {
error_page 302 = @service_static_file;
proxy_intercept_errors on;
proxy_set_header Host $host;
proxy_pass http://go.example.com;
}
location @service_static_file {
root /hidden-files;
try_files $upstream_http_location 404.html;
}
使用此方法,您将能够在没有 over-loading 系统的情况下提供文件,同时可以控制您将文件提供给谁。
为此,您的上游服务器应以状态 302 和典型的 "Location:" 字段进行响应,nginx 将使用位置内容在 "new" 根目录中查找静态文件的文件。
这个方法之所以是"good enough"类型的(而不是完美的)是因为它不支持部分请求(即Range: bytes ...)