我知道也许专用服务器会更好,但是我不熟悉仅服务器框架。但我对 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解决这个问题并在网上查找后,几个小时后我无法找到解决方案。这是副驾驶给我的建议
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));
这是邮递员的另一个错误
这是我的 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
感谢用户 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 中创建了这个代理服务器来对获取进行三角测量,现在它可以工作了。这是工作示例。
请不要尝试获取我的服务器,因为中间件将拒绝您的请求