Skip to content
Database

pg_net:异步网络

pg_net 使 Postgres 可以在 SQL 中进行异步的 HTTP/HTTPS 请求。它与 http 扩展的不同之处在于,它默认就是异步的。这在阻塞函数(例如触发器)中非常有用。

它无需服务器不断轮询数据库的变化,而是让数据库主动通知外部资源重要事件。

🌐 It eliminates the need for servers to continuously poll for database changes and instead allows the database to proactively notify external resources about significant events.

启用扩展 #

🌐 Enable the extension

  1. 在仪表板中转到数据库页面。
  2. 点击侧边栏的 扩展。
  3. 搜索“pg_net”并启用这个扩展。

http_get#

创建一个 HTTP GET 请求并返回请求的 ID。HTTP 请求在事务提交之前不会启动。

🌐 Creates an HTTP GET request returning the request's ID. HTTP requests are not started until the transaction is committed.

签名 #

🌐 Signature [#get-signature]

net.http_get(
-- url for the request
url text,
-- key/value pairs to be url encoded and appended to the `url`
params jsonb default '{}'::jsonb,
-- key/values to be included in request headers
headers jsonb default '{}'::jsonb,
-- the maximum number of milliseconds the request may take before being canceled
timeout_milliseconds int default 2000
)
-- request_id reference
returns bigint
strict
volatile
parallel safe
language plpgsql

使用情况 #

🌐 Usage [#get-usage]

select
net.http_get('https://news.ycombinator.com')
as request_id;
request_id
----------
1
(1 row)

http_post#

创建一个带有 JSON 内容的 HTTP POST 请求,并返回请求的 ID。HTTP 请求只有在事务提交后才会开始。

🌐 Creates an HTTP POST request with a JSON body, returning the request's ID. HTTP requests are not started until the transaction is committed.

主体的字符集编码与数据库的 server_encoding 设置相匹配。

🌐 The body's character set encoding matches the database's server_encoding setting.

签名 #

🌐 Signature [#post-signature]

net.http_post(
-- url for the request
url text,
-- body of the POST request
body jsonb default '{}'::jsonb,
-- key/value pairs to be url encoded and appended to the `url`
params jsonb default '{}'::jsonb,
-- key/values to be included in request headers
headers jsonb default '{"Content-Type": "application/json"}'::jsonb,
-- the maximum number of milliseconds the request may take before being canceled
timeout_milliseconds int default 2000
)
-- request_id reference
returns bigint
volatile
parallel safe
language plpgsql

使用 #

🌐 Usage [#post-usage]

select
net.http_post(
url:='https://httpbin.org/post',
body:='{"hello": "world"}'::jsonb
) as request_id;
request_id
----------
1
(1 row)

http_delete#

创建一个 HTTP DELETE 请求,并返回请求的 ID。HTTP 请求直到事务提交后才会开始。

🌐 Creates an HTTP DELETE request, returning the request's ID. HTTP requests are not started until the transaction is committed.

签名 #

🌐 Signature [#post-signature]

net.http_delete(
-- url for the request
url text,
-- key/value pairs to be url encoded and appended to the `url`
params jsonb default '{}'::jsonb,
-- key/values to be included in request headers
headers jsonb default '{}'::jsonb,
-- the maximum number of milliseconds the request may take before being canceled
timeout_milliseconds int default 2000
)
-- request_id reference
returns bigint
strict
volatile
parallel safe
language plpgsql
security definer

使用 #

🌐 Usage [#delete-usage]

select
net.http_delete(
'https://dummy.restapiexample.com/api/v1/delete/2'
) as request_id;
----------
1
(1 row)

分析回应 #

🌐 Analyzing responses

等待的请求存储在 net.http_request_queue 表中。执行后,它们会被删除。

🌐 Waiting requests are stored in the net.http_request_queue table. Upon execution, they are deleted.

CREATE UNLOGGED TABLE
net.http_request_queue (
id bigint NOT NULL DEFAULT nextval('net.http_request_queue_id_seq'::regclass),
method text NOT NULL,
url text NOT NULL,
headers jsonb NOT NULL,
body bytea NULL,
timeout_milliseconds integer NOT NULL
)

一旦有响应返回,默认情况下,它会在 net._http_response 表中存储 6 个小时。

🌐 Once a response is returned, by default, it is stored for 6 hours in the net._http_response table.

CREATE UNLOGGED TABLE
net._http_response (
id bigint NULL,
status_code integer NULL,
content_type text NULL,
headers jsonb NULL,
content text NULL,
timed_out boolean NULL,
error_msg text NULL,
created timestamp with time zone NOT NULL DEFAULT now()
)

可以用以下查询来观察这些响应:

🌐 The responses can be observed with the following query:

select * from net._http_response;

这些数据也可以在 net 模式下通过 Supabase 仪表板的 SQL 编辑器 进行查看

🌐 The data can also be observed in the net schema with the Supabase Dashboard's SQL Editor

调试请求 #

🌐 Debugging requests

检查请求数据 #

🌐 Inspecting request data

Postman Echo API 会返回一个与请求内容相同的响应。你可以用它来查看发送的数据。

🌐 The Postman Echo API returns a response with the same body and content as the request. It can be used to inspect the data being sent.

向回声 API 发送一个 POST 请求

🌐 Sending a post request to the echo API

select
net.http_post(
url := 'https://postman-echo.com/post',
body := '{"key1": "value", "key2": 5}'::jsonb
) as request_id;

检查回声 API 响应内容,确保它包含正确的主体

🌐 Inspecting the echo API response content to ensure it contains the right body

select
"content"
from net._http_response
where id = <request_id>
-- returns information about the request
-- including the body sent: {"key": "value", "key": 5}

另外,通过将请求封装在一个数据库函数中,发送的行数据可以被记录或返回以供检查和调试。

🌐 Alternatively, by wrapping a request in a database function, sent row data can be logged or returned for inspection and debugging.

create or replace function debugging_example (row_id int)
returns jsonb as $$
declare
-- Store payload data
row_data_var jsonb;
begin
-- Retrieve row data and convert to JSON
select to_jsonb("<example_table>".*) into row_data_var
from "<example_table>"
where "<example_table>".id = row_id;
-- Initiate HTTP POST request to URL
perform
net.http_post(
url := 'https://postman-echo.com/post',
-- Use row data as payload
body := row_data_var
) as request_id;
-- Optionally Log row data or other data for inspection in Supabase Dashboard's Postgres Logs
raise log 'Logging an entire row as JSON (%)', row_data_var;
-- return row data to inspect
return row_data_var;
-- Handle exceptions here if needed
exception
when others then
raise exception 'An error occurred: %', SQLERRM;
end;
$$ language plpgsql;
-- calling function
select debugging_example(<row_id>);

检查失败的请求 #

🌐 Inspecting failed requests

查找所有失败的请求

🌐 Finds all failed requests

select
*
from net._http_response
where "status_code" >= 400 or "error_msg" is not null
order by "created" desc;

配置 #

🌐 Configuration

这个扩展被配置为可以可靠地每秒执行最多 200 个请求。响应消息只会存储 6 小时,以防不必要的堆积。默认行为可以通过重写配置变量来修改。

🌐 The extension is configured to reliably execute up to 200 requests per second. The response messages are stored for only 6 hours to prevent needless buildup. The default behavior can be modified by rewriting config variables.

获取当前设置 #

🌐 Get current settings

select
"name",
"setting"
from pg_settings
where "name" like 'pg_net%';

更改设置 #

🌐 Alter settings

你必须在系统级别更改 pg_net 设置。

🌐 You must change the pg_net settings at the system level.

一旦权限被分配,在系统级别应用设置并重启后台工作程序:

🌐 Once the privilege is assigned, apply the setting at the system level and restart the background worker:

alter system set pg_net.ttl to '24 hours';
select net.worker_restart();

示例 #

🌐 Examples

调用 Supabase Edge 函数 #

🌐 Invoke a Supabase Edge Function

向 Supabase Edge Function 发送带有认证头和 JSON 请求体的 POST 请求:

🌐 Make a POST request to a Supabase Edge Function with auth header and JSON body payload:

select
net.http_post(
url:='https://project-ref.supabase.co/functions/v1/function-name',
headers:='{"Content-Type": "application/json", "apikey": "<SUPABASE_PUBLISHABLE_KEY>"}'::jsonb,
body:='{"name": "pg_net"}'::jsonb
) as request_id;

用 pg_cron#

🌐 Call an endpoint every minute with pg_cron

pg_cron 扩展让 Postgres 可以变成自己的 cron 服务器。借助它,你可以以最小一分钟的精度定期调用接口。

🌐 The pg_cron extension enables Postgres to become its own cron server. With it you can schedule regular calls with up to a minute precision to endpoints.

select cron.schedule(
'cron-job-name',
'* * * * *', -- Executes every minute (cron syntax)
$$
-- SQL query
select "net"."http_post"(
-- URL of Edge function
url:='https://project-ref.supabase.co/functions/v1/function-name',
headers:='{"apikey": "<SUPABASE_PUBLISHABLE_KEY>"}'::jsonb,
body:='{"name": "pg_net"}'::jsonb
) as "request_id";
$$
);

在触发器中执行 pg_net #

🌐 Execute pg_net in a trigger

当触发事件发生时,向外部端点发起一次调用。

🌐 Make a call to an external endpoint when a trigger event occurs.

-- function called by trigger
create or replace function <function_name>()
returns trigger
language plpgSQL
as $$
begin
-- calls pg_net function net.http_post
-- sends request to postman API
perform "net"."http_post"(
'https://postman-echo.com/post'::text,
jsonb_build_object(
'old_row', to_jsonb(old.*),
'new_row', to_jsonb(new.*)
),
headers:='{"Content-Type": "application/json"}'::jsonb
) as request_id;
return new;
END $$;
-- trigger for table update
create trigger <trigger_name>
after update on <table_name>
for each row
execute function <function_name>();

一次发送多行表格 #

🌐 Send multiple table rows in one request

with "selected_table_rows" as (
select
-- Converts all the rows into a JSONB array
jsonb_agg(to_jsonb(<table_name>.*)) as JSON_payload
from <table_name>
-- good practice to LIMIT the max amount of rows
)
select
net.http_post(
url := 'https://postman-echo.com/post'::text,
body := JSON_payload
) AS request_id
FROM "selected_table_rows";

更多示例可以在扩展的GitHub页面上看到

🌐 More examples can be seen on the Extension's GitHub page

权限 #

🌐 Permissions

默认情况下,net 模式会授予 USAGE 给 PUBLIC。因此,anon 和 authenticated 会继承对 net.http_request_queue、net._http_response 及其相关序列的直接对象级访问权限(例如 SELECT)。

🌐 By default, the net schema grants USAGE to PUBLIC. As a result, anon and authenticated inherit direct object-level access (for example, SELECT) on net.http_request_queue, net._http_response, and their associated sequences.

这不会把请求数据暴露给未认证或客户端的用户,有两个原因:

🌐 This doesn't expose request data to unauthenticated or client-side users, for two reasons:

  • net 不能通过 Data API 访问,所以匿名/可公开的密钥无法通过 API 访问或修改它的对象。
  • anon 和 authenticated 是 NOLOGIN 角色,所以他们不能建立直接的数据库连接。

故障排除 #

🌐 Troubleshooting

安全顾问可能会报告 pg_net 已安装在 public 架构中。Postgres 将该扩展定义为不可迁移,所以 alter extension pg_net set schema extensions 不能移动它。相反,需要删除该扩展并在 extensions 架构中创建它:

🌐 The Security Advisor might report that pg_net is installed in the public schema. Postgres defines the extension as non-relocatable, so alter extension pg_net set schema extensions can't move it. Instead, drop the extension and create it in the extensions schema:

在 SQL 编辑器 中运行以下命令:

🌐 Run the following commands in the SQL Editor:

-- Ensure the target schema exists
create schema if not exists extensions;
-- Drop the existing extension
drop extension pg_net;
-- Re-create the extension in the extensions schema
create extension pg_net with schema extensions;

限制 #

🌐 Limitations

  • 为了提高速度和性能,请求和响应会存储在未记录表中,这些表在系统崩溃或非正常关闭时不会被保留。
  • 默认情况下,响应数据只会保存 6 小时
  • 只能使用 JSON 数据进行 POST 请求,不支持其他数据格式
  • 设计最多处理每秒200个请求。提高速率可能会导致不稳定
  • 不支持PATCH/PUT请求
  • 一次只能处理一个数据库。默认使用 postgres 数据库。

资源 #

🌐 Resources