【问题标题】:Sapper/Svelte: how to fetch a local json file to retrieve dataSapper/Svelte:如何获取本地 json 文件以检索数据
【发布时间】:2020-09-03 09:04:17
【问题描述】:

在我的 sapper 应用程序中,我将一些数据存储在 src/data/videoslist.json 的 json 文件中,这是一个 json 格式的对象数组。

我需要检索索引页面中的数据以将其传递给组件。这是我在 src/routes/index.svelte 顶部的代码

<script context="module">
    export async function preload() {
        const response = await this.fetch('../data/videoslist.json');
        const responseJson = await response.json();
        return {
            videos: responseJson
        }
    }
</script>

我收到错误 500

invalid json response body at http://127.0.0.1:3000/data/videoslist.json reason: Unexpected token < in JSON at position 0

文件是纯json,没有别的。意外的令牌

你知道我做错了什么吗?我尝试了很多路径变体 ../ ./ 或将文件移动到路由文件夹,但没有任何效果。

PS:我仍然是 js 和框架方面的新手,对于更了解的人来说,我可能错过了一些非常基本的东西 :)(就像你无法使用 fetch 检索本地文件)。

【问题讨论】:

  • 如果是本地json文件,为什么还要使用fetch?制作一个javascript文件,导出json并以“正常”方式导入它不是更简单吗?
  • 是的,我想到了,但是json文件的内容是由fs.writeFileSync生成的,每次收集到新数据时都会覆盖整个内容
  • 好的,不可能在它前面硬编码这样的东西:module.exports = { jsonFile: // the json file 使用 fs 函数?
  • 它使用 fetch 因为它只是服务器上的一个本地文件,一旦代码被捆绑并发送到客户端,它就不再是“本地的”。如果您使用这种方法,则每次更改 json 文件时都必须重新捆绑您的应用程序。
  • 是的,我确认 Stephane 所说的。我最初尝试在

标签: json fetch local svelte sapper


【解决方案1】:

在 Sapper 中,当您尝试获取一个 json 文件时,它实际上会查找名称为 videoslist.json.js 的路由/文件,您必须创建该文件,并让它返回 json。您可以在此处的文档中找到一个示例:https://sapper.svelte.dev/docs#Server_routes

【讨论】:

  • json 文件的内容是由 fs.writeFileSync 生成的,每次写入新内容时它都会被完全覆盖,而且我没有找到保留 javascript 行以返回 json 的方法。
  • 您将创建一个文件videoslist.json.js,并在该文件中编写一个返回videoslist.json 内容的函数
  • 如此简单而精彩!我会试一试,让你知道。谢谢
  • 嗨,stephane,我尝试了您的建议,但我没有得到正确的解决方案,我无法弄清楚如何正确编码此解决方案。由于我是初学者,服务器路由对我来说仍然很不清楚。在尝试编码之前,我应该先了解一般节点概念。感谢您的建议,当我对路由有更好的了解时,我会回复它。
  • @StephaneVanraes fs 在使用相对路径时不起作用,例如:./_videolist.json,因为 Sapper 似乎没有编译那些文件,然后它不会在编译的东西中找到它(它在__sapper__ 文件夹内寻找)。使其工作的唯一方法是使用绝对路径,但它不是用于部署等的非常便携的解决方案。只是想知道在不使用数据库的情况下管理数据(服务器端)的最佳做法是什么。
【解决方案2】:

将 JSON 文件写入static 文件夹,为static/data/videoslist.json

【讨论】:

  • 谢谢 Rich,我会试一试告诉你
【解决方案3】:

Rich 的解决方案效果很好。

我刚刚将 json 文件移动到静态文件夹中,下面的代码现在可以工作了。

<script context="module">
    export async function preload() {
        const response = await this.fetch('videoslist.json');
        const responseJson = await response.json();
        return {
            videos: responseJson
        }
    }
</script>

此解决方案无需处理服务器路由和路径即可直接访问文件。

【讨论】:

  • 这样数据就可以公开访问,并且不会被服务器过滤。
  • 鉴于问题是询问如何将videoslist.json 中的数据获取到客户端,这显然不是问题。
  • @RichHarris 会是一个非常有趣的更安全的解决方案,如果有的话。
【解决方案4】:

我注意到以下情况:

<script context="module">
    export async function preload({ params: { id } }) {
       return await (await this.fetch(`/route/${id}/details.json`)).json();
    });
</script>

...SSR 代码将尝试加载 https://127.0.0.1/route/id/details.json - 在我的主机上失败。如果我指定一个完全限定的绝对 URL(外部可访问),例如

this.fetch(`https://hostname.tld/route/${id}/details.json`)

..它工作正常。我设置了details.json.js 服务器路由,当通过https://hostname.tld/route/id/details.json 直接访问 URL 时,它按预期工作

Sapper 显然在服务器 500 之后在客户端运行相同的代码,所以页面仍然可以工作,但有点混乱。

由于托管服务提供商因缺少引荐来源网址而阻塞(导致 403),我在预加载脚本中遇到了类似的相对路径问题,可以通过以下方式缓解:

this.fetch(`/route/${id}/details.json`, { referrerPolicy: "origin" })

...但是,在这种情况下,这似乎没有帮助。

我显然可以将 URL 更改为绝对 URL,但我宁愿不将它绑定到主机,搞砸本地开发,并且显然会强制 SSR 代码离开本地网络。我想我不清楚服务器端获取如何对 localhost 起作用,因此可能不是特定于工兵的问题。

注意我可以利用预加载页面参数中的“主机”来构造一个绝对 URL(必须是 http 而不是 https):

<script context="module"> 
   export async function preload({ host, params: { id } }) { 
      return await (await this.fetch(`http://{host}/route/${id}/details.json`)).json(); 
   });
</script>

...它适用于托管 - 但担心它不直观,并且不像文档所暗示的那样。


【讨论】:

    猜你喜欢
    • 2020-09-04
    • 2019-11-24
    • 1970-01-01
    • 2020-02-19
    • 2020-02-13
    • 1970-01-01
    • 2020-09-30
    • 2014-09-19
    • 1970-01-01
    相关资源
    最近更新 更多