Supabase边缘函数运行两次,但只有一个调用。

huangapple go评论66阅读模式
英文:

Supabase edge function running twice, but just one call

问题

我有一个在Supabase中用TypeScript编写的相对简单的边缘函数,它连接到我们的PostgreSQL数据库并运行查询。该函数通过HTML按钮调用。在CLI本地运行或通过部署后的生产环境,不管哪种情况,该边缘函数都会运行两次。查询运行两次,但控制台日志显示整个函数都运行了两次。然而,在浏览器控制台日志中,只显示在按钮点击时调用了一次函数。有什么建议吗?

以下是HTML代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Invoke Supabase Function</title>
  </head>
  <body>
    <button id="invoke-button">Invoke Function</button>
    <script language="Javascript">
      const apiKey = XXXXX
      const functionEndPoint = 'http://localhost:54321/functions/v1/';

      const inputData = { name: 'Blah' };
      
      const invokeFunction = () => {
        console.log('Called invokeFunction');
        fetch(`${functionEndPoint}`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${apiKey}`
          },
          body: JSON.stringify(inputData)
        })
          .then(response => response.json())
          .then(data => {            
            console.log(data);
          })
          .catch(error => {
            console.error(error);
          });
      };
      
      document.getElementById('invoke-button').addEventListener('click', invokeFunction);
    </script>
  </body>
</html>

以下是函数代码:

import * as postgres from 'https://deno.land/x/postgres@v0.14.2/mod.ts';
import { serve } from 'https://deno.land/std@0.177.0/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@1.33.1';
import { corsHeaders } from '../_shared/cors.ts';

const databaseUrl = "postgresql://XXXXX"
const pool = new postgres.Pool(databaseUrl, 3, true)

serve(async (_req) => {
  
  try {
    // 从池中获取连接
    const connection = await pool.connect()

    try {
      // 运行查询(实际上是一个非确定性的存储过程)
      console.log("inbound startgame request...")
      const result = await connection.queryObject`SELECT public."newGame"();`
      const rr = result.rows
      console.log(rr)

      // 将结果编码为漂亮格式的JSON
      const body = JSON.stringify(
        rr,
        (key, value) => (typeof value === 'bigint' ? value.toString() : value),
        2
      )

      // 返回带有正确内容类型标头的响应
      return new Response(
        JSON.stringify(rr),
        { 
          headers: { ...corsHeaders, "Content-Type": "application/json" },
          status: 200,
        },
      )

    } finally {
      // 将连接释放回池中
      connection.release()
    }
  } catch (err) {
    console.error(err)
    return new Response(String(err?.message ?? err), { status: 500 })
  }
})
英文:

I have a relatively simple edge function in typescript at Supabase that connects to our postgres db and runs a query. The function is invoked via an html button. When run locally in the cli, or via production, once deployed, it both cases, the edge function runs twice. The query is running twice, but console logging shows the entire function is running twice. However, in the browser console logging only shows one call to the function on the button click. Any ideas?

Here's the html:

&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot;&gt;
    &lt;title&gt;Invoke Supabase Function&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;button id=&quot;invoke-button&quot;&gt;Invoke Function&lt;/button&gt;
    &lt;script language=&quot;Javascript&quot;&gt;
      const apiKey = XXXXX
      const functionEndPoint = &#39;http://localhost:54321/functions/v1/&#39;;

      const inputData = { name: &#39;Blah&#39; };
      
      const invokeFunction = () =&gt; {
        console.log(&#39;Called invokeFunction&#39;);
        fetch(`${functionEndPoint}`, {
          method: &#39;POST&#39;,
          headers: {
            &#39;Content-Type&#39;: &#39;application/json&#39;,
            &#39;Authorization&#39;: `Bearer ${apiKey}`
          },
          body: JSON.stringify(inputData)
        })
          .then(response =&gt; response.json())
          .then(data =&gt; {            
            console.log(data);
          })
          .catch(error =&gt; {
            console.error(error);
          });
      };
      
      document.getElementById(&#39;invoke-button&#39;).addEventListener(&#39;click&#39;, invokeFunction);
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;

Here's the function:

import * as postgres from &#39;https://deno.land/x/postgres@v0.14.2/mod.ts&#39;
import { serve } from &#39;https://deno.land/std@0.177.0/http/server.ts&#39;
import { createClient } from &#39;https://esm.sh/@supabase/supabase-js@1.33.1&#39;
import { corsHeaders } from &#39;../_shared/cors.ts&#39;

const databaseUrl = &quot;postgresql://XXXXX&quot;
const pool = new postgres.Pool(databaseUrl, 3, true)

serve(async (_req) =&gt; {
  
  
  try {
    // Grab a connection from the pool
    const connection = await pool.connect()

    try {
      // Run a query (its actually a non-deterministic fb function/stored proc)
      console.log(&quot;inbound startgame request...&quot;)
      const result = await connection.queryObject`SELECT public.&quot;newGame&quot;();`
      const rr = result.rows
      console.log(rr)

      // Encode the result as pretty printed JSON
      const body = JSON.stringify(
        rr,
        (key, value) =&gt; (typeof value === &#39;bigint&#39; ? value.toString() : value),
        2
      )

      // Return the response with the correct content type header
      return new Response(
        JSON.stringify(rr),
        { 
          headers: { ...corsHeaders, &quot;Content-Type&quot;: &quot;application/json&quot; },
          status: 200,
        },
      )

    } finally {
      // Release the connection back into the pool
      connection.release()
    }
  } catch (err) {
    console.error(err)
    return new Response(String(err?.message ?? err), { status: 500 })
  }

答案1

得分: 2

Eureka! 边缘函数需要这个:

  if (req.method === 'OPTIONS') {
    return new Response('ok', { headers: corsHeaders })
  }

显然,浏览器会发送一个预检请求到该函数,以查看它是否支持跨域资源共享(CORS)。如果你不正确处理这个请求,监听函数会在预检查期间正常运行,然后再在主要调用期间运行。由于上面的代码返回了CORS标头,因此浏览器的两次运行都成功了。

英文:

Eureka! The edge function needs this:

  if (req.method === &#39;OPTIONS&#39;) {
    return new Response(&#39;ok&#39;, { headers: corsHeaders })
  }

Apparently browsers send a pre-flight request to the function to see if it supports CORs. If you don't handle this properly, the listening function just runs normally during the pre-flight check, and then again during the main call. Since the code above was returning CORs headers, both runs were successful from the browser.

huangapple
  • 本文由 发表于 2023年3月12日 06:42:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/75710032.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定