Я знаю, что, возможно, для этого лучше подойдет выделенный сервер, однако я не знаком с серверными платформами. Но я очень хорошо знаком с маршрутами 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>
После интенсивного использования второго пилота для решения этой проблемы, а также поиска в Интернете, я не смог найти решение через несколько часов. Вот предложения, которые дал мне второй пилот
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 позволяет создавать маленькие и быстрые приложения без лишнего кода.
Благодаря помощи пользователя 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 отклонит ваш запрос.