尝试从客户端的 Medium API 访问公共故事时出错

Posted

技术标签:

【中文标题】尝试从客户端的 Medium API 访问公共故事时出错【英文标题】:Error while trying to access public stories from Medium API on client side 【发布时间】:2018-05-25 08:17:26 【问题描述】:

我正在尝试访问 Medium 的 API 以获取用户的公开故事列表。但是,当我尝试在客户端访问它时出现 CORS 错误。这是代码

axios.get(`http://medium.com/@ev/latest`).then((res)=>
  console.log(res.data)
)
.catch((error)=>
  console.log(error)
)

我做了一些研究,发现了这个github issue,但找不到任何解决方法。有没有办法让这个请求在客户端工作?

【问题讨论】:

【参考方案1】:

使用此Medium API,您可以轻松获取特定用户编写的article_ids 列表(使用他们的user_id)。

使用端点GET /user/user_id/articles

它将返回一个 JSON 响应,如下所示:


 "associated_articles": [
    "*hash_id_of_article_1*",
    "*hash_id_of_article_2*",
    "*hash_id_of_article_3*",
    .
    .
    .
]

然后,您可以使用此article_ids 列表来获取单个文章的信息或内容。像这样:

注意:article_id 指的是与每个 Medium Story/Article 相关联的唯一哈希 id。您可以在帖子 URL 的末尾看到它。

基本网址: https://medium2.p.rapidapi.com

GET /article/article_id

此端点将返回与文章相关的信息,例如标题、副标题、拍手、投票者、标签、主题、作者(user_id)、发布日期等……


  "id": "*article_id*",
  "title": "*article_title*",
  "subtitle": "*article_subtitle*",
  "claps": "*claps_count*",
  "voters": "*voters_count*",
  "published_at": "*date_of_publishing*",
  "word_count": "*word_count*"
  .
  .
  .

GET /article/article_id/content

此端点将返回文章的文本内容。


  "content": "This is the article's textual content. Blah, blah, blah ..."


更详细的解释可以查看这个页面:https://medium.com/p/fcdb1576558a

文档:https://nishu-jain.medium.com/medium-apis-documentation-3384e2d08667

用于测试 api:https://rapidapi.com/nishujain1997.19@gmail.com/api/medium2/

【讨论】:

【参考方案2】:

您可以通过 CORS 代理发出请求,从 https://medium.com/@ev/latest 获取 html,可以是您自己设置的代理,也可以使用像 https://cors-anywhere.herokuapp.com/ 这样的公共开放 CORS 代理。以下是使用标准 Fetch API 的方法:

fetch("https://cors-anywhere.herokuapp.com/https://medium.com/@ev/latest")
  .then(res => res.text())
  .then(text => document.querySelector("div").innerHTML = text)
  .catch(error => console.log(error))
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div></div>

有关更多详细信息 - 包括如何在几分钟内在 Heroku 上设置您自己的 CORS 代理,请参阅如何使用 CORS 代理解决“No Access-Control-Allow-Origin header”问题 在 No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API 的答案中。


顺便说一句,如果你想要 JSON,你可以试试https://medium.com/@ev/latest?format=json,但你会发现你得到的实际上不是有效的 JSON;相反,它的开头是这样的:

])while(1);</x>"success":true,"payload":"user":"userId":"268314bb7e7e","name"…

显然这是故意的,per a comment from a Medium developer in their issue tracker:

JSON 页面不打算用作读取 API。额外的代码是为了支持我们自己的使用,并且是避免 JSON 劫持的标准技术。

不过,这很容易解决:只需首先在客户端代码中将响应作为文本处理,然后从它的开头去掉])while(1);&lt;/x&gt;,然后在剩下的部分上运行JSON.parse

但就使用 Axios 获取文本形式的响应而言,我想您会发现即使您通过 CORS 代理发出请求,它也不会按预期工作;试试这个:

axios.get('https://cors-anywhere.herokuapp.com/http://medium.com/@ev/latest', 
    responseType: 'text'
  )
  .then(res => console.log(res.data))
  .catch(error => console.log("ERROR"))
&lt;script src="https://unpkg.com/axios/dist/axios.min.js"&gt;&lt;/script&gt;

代码命中catch,因为显然即使您指定responseType: 'text',Axios apparently still tries the parse the response as JSON:

这是因为JSON.parse 总是在响应中被尝试,即使responseType 是文本。我们确实应该解决这个问题。

而https://medium.com/@ev/latest 是 HTML,而不是 JSON,因此在其上运行 JSON.parse 会失败。

这就是为什么这个答案中的第一个 sn-p 使用 Fetch API 代替(你可以用它取回文本)。

【讨论】:

【参考方案3】:

Medium 目前不允许这样做(服务器没有响应 Access-Control-Allow-Origin 标头)。可能是出于安全考虑。

正如您链接到的 GitHub 问题中所建议的,一种可能的解决方案是通过您的服务器(作为代理)将请求传送到 Medium。您可以在您的服务器(即http://my-server.com/get-medium/@ev/latest)上创建一个端点,该端点将检索请求的媒体页面(在服务器端)并将其返回给客户端。

此问题的评论描述了一种使用 AWS Lambda 作为代理服务器的方法 - link

【讨论】:

以上是关于尝试从客户端的 Medium API 访问公共故事时出错的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 API 网关配置对 eureka 客户端的 API 请求

如何使用从公共客户端发出的令牌查询 keycloak 资源权限

直接从客户端访问MongoDB

公共 api 请求没有“Access-Control-Allow-Origin”

不同客户端的 iTunes Lookup API 响应不同

舔狗的故事-MySQL客户端与服务端的爱恨情仇-《从0到1-全面深刻理解MySQL系列-第六篇》