从 Obsidian 向 Discourse 发布时遇到 CORS 问题

我开始使用 Obsidian 进行写作,所以我想为我的 Discourse 论坛创建一个 Obsidian 插件 来发布内容。理论上这很容易做到,但我的第一次尝试的响应是:

Access to fetch at 'http://localhost:4200/posts.json' from origin 'app://obsidian.md' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

请求是从客户端发出的,但客户端是用户的设备。如果我理解正确的话,这是安全的:

import DiscoursePlugin from "./main";
import { TFile } from "obsidian";

export async function publishToDiscourse(
	plugin: DiscoursePlugin,
	activeFile: TFile
): Promise<{ message: string }> {
	try {
		const content = await plugin.app.vault.read(activeFile);
		const baseUrl = plugin.settings.baseUrl;
		const apiKey = plugin.settings.apiKey;

		const headers = new Headers({
			"Content-Type": "application/json",
			"Api-Key": apiKey,
			"Api-Username": "scossar", // this needs to be a setting
		});
		const body = JSON.stringify({
			title: activeFile.name,
			raw: content, // TODO: parse the content to fix internal links
			category: 1, // this needs to be a setting
		});
		// TODO: check to see if the note has already been published
		const url = `${baseUrl}/posts.json`;

		const response = await fetch(url, { method: "POST", headers, body });

		if (!response.ok) {
			console.error("Error publishing to Discourse:", response.status);
			return { message: "Error publishing to Discourse" };
		}
        
		const jsonResponse = await response.json();
		// TODO: use the response to add a discoursePostId file property
		console.log(`jsonResponse: ${JSON.stringify(jsonResponse, null, 2)}`);
		return { message: "success" };
	} catch (error) {
		console.error("Error publishing to Discourse:", error);
		return { message: `Error: ${error.message}` };
	}
}

也许有一个明显的解决方法我忽略了。如果没有,Discourse 有办法让它工作吗?一个 Obsidian Discourse 插件似乎很有用。(一个真正的实现会比我上面发布的更复杂。)

3 个赞

我一开始很困惑,但现在明白了,你已经用你的密钥配置了自己的 Obsidian 应用,只有你才能访问它。这并不是在浏览器中发生的,所以互联网上的人无法获取你的密钥。

我有一个 Discourse 插件,可以处理任意表单(你可以在 https://www.formhoster.com/ 上使用它)。我想让它能够作为当前用户工作,如果用户登录到处理表单的网站,并且我遇到了我认为是相同的 CORS 问题,然后很快就放弃了。我的情况是在浏览器中,而不是像 Obsidian 这样的应用程序,但我认为问题可能类似。

说了这么多,我可能没有什么好主意,但我希望其他人会有。 :person_shrugging:

1 个赞

是的,Obsidian 是一个在本地运行的 Electron 应用。它使用本地存储,所以 API 密钥会保留在用户的设备上。

事实证明,CORS 问题有一个解决方案。我目前只在我的台式电脑上测试过。另外,Discourse 很棒!

上面我发布的代码需要修改为:

import DiscoursePlugin from "./main";
import { requestUrl, TFile } from "obsidian";

//...

		const response = await requestUrl({
			url: url,
			method: "POST",
			contentType: "application/json",
			body,
			headers,
		});
//...

下一个问题将是关于允许用户从应用请求用户 API 密钥,但这属于另一个问题。

3 个赞

这是您正在开发的插件吗?我有一位用户(包括我自己)非常希望能够使用它。我可以尝试重新创建您所做的,但如果有什么更简单的方法……

这是某个东西的开始。出于我自己的目的,我更感兴趣的是一个命令行(CLI)应用程序,它允许 Obsidian Vault 与 Discourse 论坛同步。CLI 应用程序可以更轻松地处理整个 vault 或子目录的同步,处理 Notes 中的内部链接,处理上传等。CLI 应用程序方法也符合我正在进行的其他一些工作,因此我从中学习到了一些有用的东西。

CLI 应用程序的一个主要缺点是,任何使用它的人都需要在他们的计算机上安装 Ruby。它也只能在台式电脑上运行。在 Windows 计算机上使用它会存在一些技术挑战。

一旦应用程序准备好分享,我就会在这里发布一个指向该应用程序的链接。

如果有人对 Obsidian Discourse 插件(而不是 CLI 应用程序)感兴趣,我将来会再次考虑它。有可能其他人会比我先做到这一点。我没有把它做得比上面发布的代码示例更进一步。

1 个赞

如果这就是你目前为止所做的,那看起来相当简单。我想知道它在这一点上将如何处理图像。我很乐意尝试一下。我以前从未为 Obsidian 写过插件,但从我看到的情况来看(随意看了看其他插件),它看起来并不太复杂。

1 个赞

这是起点:Build a plugin。我想链接到我所做的,但这是我上周在重新安装计算机操作系统之前为数不多的(但愿是唯一)未推送到 - Developer Documentation Github 的项目之一。

你必须弄清楚如何用 Node 来做。这里有一个很好的 Ruby 示例:discourse_api/examples/upload_file.rb at main · discourse/discourse_api · GitHub

可以分享这部分吗?

嗯,丢失那段代码有点鲁莽。据我回忆,我正在将 main.ts 中定义的 DiscoursePlugin 导入到一个处理 this.addCommand 调用的文件中。要开始,你可以在 main.ts 中完成所有操作。我只是按照入门示例插件的指南进行操作。先尝试一下,看看能不能做出点什么。我知道我用那个插件作为我插件的模板。

这里也有一些很好的例子:https://github.com/devbean/obsidian-wordpress/tree/main/src。

1 个赞

好吧,我现在要搁置这个了。我已经取得了相当大的进展,但有几件事我不太喜欢。

  • API 密钥以明文形式存储(非常糟糕)
  • 图片未上传,还有一些我尚未探索的配置设置。但我不喜欢设置 AWS S3 存储桶。我稍后会研究一下。
  • 一些风格选择可以更好,但我想先实现功能
  • README 需要更新。但同样,我只想先实现功能并发布。
1 个赞

我想知道是否有办法解决这个问题。在 CLI 应用程序中,我使用密码对其进行加密。用户必须在任何使用 API 密钥的操作之前提供密码。

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.