如何在 SvelteKit 中发布前向 API?

问题描述 投票:0回答:1

我知道也许专用服务器会更好,但是我不熟悉仅服务器框架。但我对 SvelteKit api 路由非常熟悉。我决定创建一个名为“/API”的路由,其中我有一个处理程序类,它将根据作为 post 请求中的 func 参数传递的字符串确定在服务器中运行哪个方法。当我使用 svelte 客户端时,这确实会正确返回数据。但是,将文件发布到 Vercel 后,无法获取数据。我将在最后添加错误消息,因为它很长。 这是“/API/+server.ts”文件

import { json, type RequestEvent } from '@sveltejs/kit';


  export async function POST({request}:RequestEvent){
    const body = await request.json()
    const handler = new API_service(body.func);
    const params =body.params
    let data;
    if (Array.isArray(params)) {
        data = await handler.function_handler(params);
    } else {
        // Handle the case where body.params is not an array
        throw new Error("No parameters array")
    }
    
    return json( data );
}



class API_service{
    private func:string;
    private config = {
        api_key:"&x_cg_demo_api_key=Your coingecko API Key", //<--- Change accordingly
        base_url:"https://api.coingecko.com/api/v3",
        currency:"?vs_currency=usd",
        ids:"&ids=bitcoin",
        days:"&days=30"
      }
    
      
    private coins_endpoint = {
        markets:"/coins/markets",
    
      }
      
    private root_endpoint = {
        ping:"/ping"
      }



    constructor(func:string){
        this.func=func
    }
    public function_handler(params:any[]){
        switch(this.func){
            case "get_btc_ohlc":
                return this.get_btc_ohlc(params[0])

        }

    }
    private async get_btc_ohlc(id:string){
        const response = await fetch(this.config.base_url+`/coins/${id}/ohlc`+this.config.currency+this.config.days)
        return await response.json()
    }
}

我使用以下客户端代码测试了端点,并得到了预期的响应

<script>
    import {onMount} from "svelte";
    onMount(async ()=>{
        try {
            const response = await fetch('/API',{
                method:"POST",
                body:JSON.stringify({
                    func:"get_btc_ohlc",
                    params:["bitcoin"]
                })
            })
            if(!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            console.log(await response.json());
            } catch (error) {
            console.error('There was a problem with the fetch operation: ', error);
            }
    
    })
</script>

在广泛使用copilot解决这个问题并在网上查找后,几个小时后我无法找到解决方案。这是副驾驶给我的建议

  1. 创建 vercel.json 文件
  2. 创建hook.server.ts文件
  3. 在app.html中创建元标记 他们在这里

vercel.json

{
    "headers": [
      {
        "source": "/(.*)",
        "headers": [
          {
            "key": "Content-Security-Policy",
            "value": "default-src *; connect-src 'self' https://private-coingecko-api.vercel.app; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;"
          }
        ]
      }
    ]
  }

hook.server.ts

import type { Handle, RequestEvent } from '@sveltejs/kit';

export const handle: Handle = async ({ event, resolve } ) => {
  const response = await resolve(event);

  // Ensure response.headers exists
  if (response.headers) {
    response.headers.set(
      'Content-Security-Policy',
      "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' https://private-coingecko-api.vercel.app;"
    );
  }

  return response;
};

app.html 中的 Meta 标签

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' https://private-coingecko-api.vercel.app;">

以下代码片段是对我的端点的实际提取,它返回后面的错误(我从默认边缘空白页面的控制台运行此代码)

await fetch("https://private-coingecko-api.vercel.app/API",{
    method:"POST",
    body:JSON.stringify({
        func:"get_btc_ohlc",
        params:["bitcoin"],
        apikey: "Your api key" //<-- I removed the middleware in the previous snippet but its still there in production
    })
})
.catch(error => console.error('Error:', error));

Error caused by fetch from the console

这是邮递员的另一个错误

Postman error message from production api

这是我的 vercel 服务器的日志。正如您所看到的,来自 coingecko 的数据工作正常,但由于跨站点 POST 请求而无法完成。我根据教程修改了我的钩子文件,它的外观如下,但它仍然无法在邮递员上工作。 Vercel http request logs

import type { Handle } from '@sveltejs/kit';

export const handle: Handle = async ({ resolve, event }) => {

  // Apply CORS header for API routes
  if (event.url.pathname.startsWith('/API')) {
    // Required for CORS to work
    if(event.request.method === 'OPTIONS') {
      return new Response(null, {
        headers: {
          'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Headers': '*',
        }
      });
    }
  }

  const response = await resolve(event);
  if (event.url.pathname.startsWith('/API')) {
        response.headers.append('Access-Control-Allow-Origin', `*`);
  }
  return response;
};

编辑: 我正在读这篇文章,到目前为止似乎很有用,但我还没弄清楚 https://www.programonaut.com/cross-site-post-form-submissions-are-forbidden-in-sveltekit/

这里是有关此主题的更详细文档 https://kit.svelte.dev/docs/adapter-node

此信息似乎也相关 https://snippets.khromov.se/configure-cors-in-sveltekit-to-access-your-api-routes-from-a- different-host/

fetch-api svelte sveltekit public
1个回答
0
投票

感谢用户 Peppe L-G 的帮助,我找到了解决此问题的方法。我不确定 hooks.server.ts 文件以及 vercel.json 文件和元标记是否对于此工作至关重要。但最终使它起作用的是更改 svelte.config.js 文件的 kit 属性内的 csrf 属性。

import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

/** @type {import('@sveltejs/kit').Config} */
const config = {
    preprocess: vitePreprocess(),

    kit: {  
        
        adapter: adapter(),
        csrf:{
            checkOrigin:false //<--- Add this line
        }
    }
};

export default config;

这允许您向服务器的 API 发出跨站点 POST 请求。如果您尝试在 SvelteKit 中构建面向公众的 API,这非常有用。我一开始遇到这个问题的原因是 coingecko 阻止了来自 Google 服务器的信号。因此,当尝试通过 URLFetchApp.fetch 使用他们的 API 时,它不会接受请求。因此,我在 SvelteKit 中创建了这个代理服务器来对获取进行三角测量,现在它可以工作了。这是工作示例。

Fetching data from coingecko using Google App Scripts and a proxy

请不要尝试获取我的服务器,因为中间件将拒绝您的请求

© www.soinside.com 2019 - 2024. All rights reserved.