url-retrieve 使用 curl 作为后端实现

发布: 2021-10-10   上次更新: 2024-10-29   标签: tips network

文章目录

Emacs 自带的 url.el 包提供了网络请求的基本 API,但是问题比较多,比如 Elfeed, cURL, and You 这篇文章就介绍了使用 cURL 代替 url-retrieve 的好处,主要有以下几点:

  1. 更快

    • 早期的 url.el 中 DNS 查询是同步的,直到 25 版本才改成异步
    • 更方便定义头信息,减少不必要的请求
  2. bug 更少

    • url-retrieve 的 CALLBACK 可以会调用多次或零次
    • 不用再去折腾 GnuTLS
    • url.el 对 Windows 平台支持差

此外,在 Emacs 设置代理问题比较多,http 的还好,麻烦的是 https/socks,一些问题链接:

如果连网络请求不通畅,那么诸如 eww、elfeed 等怎么会有好的体验? elfeed 还算好,提供了 cURL 的支持,但很多包是不支持的,因此最彻底的解决办法就是本文标题说的,直接用 cURL 来作为 use-retrieve 的后端实现。

cURL 的代理支持很简单, -x socks5h://127.0.0.1:1080 就可以指定 socks 代理,而且更重要的,没有 bug!

mb-url

上面介绍了使用 cURL 的动机,那么如果实现呢?可以使用 advice 机制来拦截 url.el 内部的接口,繁琐的地方在于解析 cURL 的结果,让它符合 url.el 内部接口。

幸运的是,社区内已经有包解决这个问题了,它就是 mb-url ,其前身是 curl-url-retrieve 。在使用过程中,我发现了它的一些问题,目前需要使用我 fork 的版本才能正确请求类似图片之类的二进制数据。下面给出使用 use-package 的配置,供读者参考:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
(setq socks-proxy "socks5h://127.0.0.1:1080")

(use-package mb-url-http
  :load-path "path to your local directory"
  :defer t
  :commands (mb-url-http-around-advice)
  :init
  (setq mb-url-http-backend 'mb-url-http-curl
	    mb-url-http-curl-switches `("--max-time" "20" "-x" ,socks-proxy))
  (advice-add 'url-http :around 'mb-url-http-around-advice))

测试代码:

1
2
3
4
5
6
7
(let* ((buffer (url-retrieve-synchronously "https://emacstalk.codeberg.page/images/logo.png"))
	   (data (with-current-buffer buffer
				 (goto-char (point-min))
				 (search-forward "\n\n")
				 (buffer-substring-no-properties (point) (point-max)))))
  (insert-image (create-image data nil t))
  (kill-buffer buffer))

执行上面的代码,如果展示出 logo 的图片,说明 mb-url 可以正确解析图片数据。

Emacs + libcurl

通过使用 mb-url 问题是可以得到解决,但是不禁会疑问,Emacs 当初为什么不直接集成 libcurl ,而是选择自己来实现呢? git log 可以看到 url.el 的首次提交是 2004-05-04,根据 cURL Release Table ,那时候大概是版本 7.11,不知道是不是当时的版本还不成熟?

搜了下 devel 邮件列表,最新的一次讨论是 Emacs HTTP libraries,看下来是建议先 profile 下现在 url.el 的问题所在,另起炉灶的可能性不大,还是以改进现有代码的方式为主,此外 RMS 也提到 cURL 的集成也可以通过 fork/exec 的方式,这样更简单些。



收听方式

反馈