Как опубликовать перспективный API в SvelteKit?

Я знаю, что, возможно, для этого лучше подойдет выделенный сервер, однако я не знаком с серверными платформами. Но я очень хорошо знаком с маршрутами API SvelteKit. Я решил создать маршрут с именем «/API», где у меня есть класс-обработчик, который будет определять, какой метод запускать на сервере, на основе строки, переданной в качестве параметра 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.info(await response.json());
            } catch (error) {
            console.error('There was a problem with the fetch operation: ', error);
            }
    
    })
</script>

После интенсивного использования второго пилота для решения этой проблемы, а также поиска в Интернете, я не смог найти решение через несколько часов. Вот предложения, которые дал мне второй пилот

  1. Создайте файл vercel.json.
  2. Создайте файлook.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:;"
          }
        ]
      }
    ]
  }

крючок.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 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));

Вот еще одна ошибка почтальона

Вот журналы с моего сервера Vercel. Как видите, данные из coingecko работают нормально, однако не удается завершить их из-за межсайтового запроса POST. Я изменил свой файл перехватчиков в соответствии с руководством, и вот как он выглядит, но он все еще не работает в почтальоне.

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/

🤔 А знаете ли вы, что...
Svelte позволяет создавать маленькие и быстрые приложения без лишнего кода.


99
1

Ответ:

Решено

Благодаря помощи пользователя Peppe L-G мне удалось найти способ это исправить. Я не уверен, необходим ли для этого файлooks.server.ts, а также файл vercel.json и метатег. Но что, наконец, заставило это работать, так это изменение атрибута csrf внутри атрибута kit файла svelte.config.js.

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;

Это позволяет вам отправлять межсайтовый POST-запрос к API вашего сервера. Это полезно, если вы пытаетесь создать общедоступный API в SvelteKit. Причина, по которой у меня возникла эта проблема, заключалась в том, что coingecko блокирует сигналы, поступающие с серверов Google. Поэтому при попытке использовать их API через URLFetchApp.fetch он не принял запрос. Поэтому вместо этого я создал этот прокси-сервер в SvelteKit для триангуляции выборки, и теперь он работает. Вот рабочий пример.

Пожалуйста, не пытайтесь получить доступ к моему серверу, поскольку Middlewares отклонит ваш запрос.