尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

深入解析 libcurl 的 CURLINFO_EFFECTIVE_URL:获取最后一次实际请求的 URL

深入解析 libcurl 的 CURLINFO_EFFECTIVE_URL:获取最后一次实际请求的 URL 深入解析 libcurl 的 CURLINFO_EFFECTIVE_URL获取最后一次实际请求的 URL【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl导读CURLINFO_EFFECTIVE_URL是 libcurl 提供的一个curl_easy_getinfo()信息选项用于在请求完成后获取最后一次实际使用的有效 URL。在开启重定向跟随CURLOPT_FOLLOWLOCATION、遇到 HTTP 3xx 跳转、HSTS 升级或 URL 规范化等场景下最终请求的 URL 往往与你最初通过CURLOPT_URL设置的地址不同本选项正是为获取这一真相而设计。读完本文你将掌握该选项的完整用法、内存生命周期、返回值语义以及它在单连接与多连接multi interface编程中的典型实战模式并了解其底层在 curl 源码中的实现原理。一、选项概览属性值选项名称CURLINFO_EFFECTIVE_URL所属函数curl_easy_getinfo(3)适用协议HTTP及基于 HTTP 的重定向机制加入版本curl 7.4Addded-in: 7.4数据类型char *指向只读字符串的指针相关选项CURLOPT_FOLLOWLOCATION、CURLOPT_URL该选项的完整权威定义位于仓库 docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md它是 libcurl 选项文档体系docs/libcurl/curl_easy_getinfo.md 中列出的众多 getinfo 选项之一。一句话理解当你用CURLOPT_URL设置的地址与实际发出的请求地址不一致时重定向、HSTS 升级、自动补齐等CURLINFO_EFFECTIVE_URL返回的是后者——也就是 libcurl 内部当前正在使用的那个 URL。二、函数原型SYNOPSIS#include curl/curl.h CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_EFFECTIVE_URL, char **urlp);要点handle已初始化的CURL *句柄CURLINFO_EFFECTIVE_URL信息类型常量CURLINFO枚举值urlp指向char *的指针函数执行后*urlp指向返回的 URL 字符串。调用时机通常在curl_easy_perform()返回CURLE_OK之后调用此时句柄内已保存了本次传输最终使用的 URL。三、核心语义与使用要点DESCRIPTION文档明确给出了三条关键语义1. 最后一次使用的有效 URLcurl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, urlp)返回的是 libcurl 在本次传输过程中最后一次实际使用的有效 URL。2. 跟随重定向时与 CURLOPT_URL 可能不同In cases when you have asked libcurl to follow redirects, it may not be the same value you set with CURLOPT_URL(3).当通过CURLOPT_FOLLOWLOCATION开启自动跟随重定向后若服务器返回 3xx 且Location指向新的地址libcurl 会一路跟随最终请求的 URL 往往已不是最初设置的值。此时CURLINFO_EFFECTIVE_URL返回的正是重定向链末端的最终 URL。3. 返回指针的生命周期只读、勿释放、自动回收Theurlppointer is NULL or points to private memory. Youmust notfree it. It memory gets freed automatically when you call curl_easy_cleanup(3) on the corresponding curl handle.返回的指针可能为 NULL也可能指向私有内存绝对不要调用free()释放它该内存会在对对应句柄调用curl_easy_cleanup()时自动释放因此使用模式是先拷贝使用或在本次句柄生命周期内消费完切勿长期持有指针。四、完整可运行示例EXAMPLE文档给出了完整示例在开启重定向跟随的场景下打印最终落点 URLint main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, https://example.com); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); result curl_easy_perform(curl); if(result CURLE_OK) { char *url NULL; curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, url); if(url) printf(Redirect to: %s\n, url); } curl_easy_cleanup(curl); } }代码解读CURLOPT_FOLLOWLOCATION, 1L开启自动跟随 3xx 重定向传输成功后通过CURLINFO_EFFECTIVE_URL取最终 URL先判空if(url)再使用因为返回的指针可能为 NULL示例并未free(url)这正符合私有内存、自动回收的语义。若example.com响应 301/302 并指向新地址程序输出形如Redirect to: https://www.example.com/。五、返回值RETURN VALUEcurl_easy_getinfo()始终返回CURLcodeCURLE_OK (0)一切正常非零值发生错误具体错误码参见 libcurl-errors(3)即CURLE_*错误码系列文档。因此严谨的写法是检查返回值后再使用输出参数CURLcode rc curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, url); if(rc ! CURLE_OK) { fprintf(stderr, getinfo failed: %d\n, rc); }六、底层实现原理源码级佐证1. 数据来源data-state.url在 lib/getinfo.c 中CURLINFO_EFFECTIVE_URL分支的实现非常直观case CURLINFO_EFFECTIVE_URL: { const char *s Curl_bufref_ptr(data-state.url); *param_charp s ? s : ; } break;也就是说返回的字符串就是句柄内部状态data-state.url的当前值通过bufref缓冲区引用访问。state.url在整个传输过程中会被持续更新初始由CURLOPT_URL设置见 lib/setopt.c 附近对STRING_SET_URL的处理重定向跟随、HSTS 升级等流程会将其替换为新的 URL见下文。2. 谁在更新它重定向与 HSTS在 lib/http.c 附近libcurl 在决定跟随Location时会将新的跳转地址写回state.urlCurl_bufref_set(data-state.url, follow_url, 0, curl_free);同样在 lib/url.c 的 HSTS 升级逻辑中当访问 HTTP 地址但 HSTS 策略要求强制 HTTPS 时libcurl 会把 URL 的 scheme 升级为https并重新写回state.urluc curl_url_set(uh, CURLUPART_SCHEME, https, 0); ... Curl_bufref_set(data-state.url, url, 0, curl_free);这两处更新恰恰印证了文档所述跟随重定向时它可能不再是你用CURLOPT_URL设置的值——state.url是 libcurl 当前生效中的 URLCURLINFO_EFFECTIVE_URL只是把它原样暴露给调用方。3. 内存管理bufref 与自动回收state.url使用Curl_bufref缓冲引用管理Curl_bufref_ptr()返回其持有的指针。该内存在句柄清理时统一释放lib/easy.c 附近初始化、句柄销毁时释放这与文档中由 curl_easy_cleanup 自动释放、用户不得 free的约定完全一致。七、实战进阶在多连接multi interface中获取每个传输的最终 URLCURLINFO_EFFECTIVE_URL最常见的进阶用法是在 multi interface 中配合curl_multi_info_read()对每个完成的 easy 句柄分别取回其最终 URL。仓库中的 docs/examples/crawler.c 是一个典型范例while((m curl_multi_info_read(multi, msgs_left))) { if(m-msg CURLMSG_DONE) { CURL *curl m-easy_handle; char *url; struct memory *mem; curl_easy_getinfo(curl, CURLINFO_PRIVATE, mem); curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, url); if(m-data.result CURLE_OK) { long res_status; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, res_status); if(res_status 200) { char *ctype; curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, ctype); printf([%d] HTTP 200 (%s): %s\n, complete, ctype, url); if(is_html(ctype) mem-size 100) { /* 基于最终 URL 继续爬取链接 */ pending follow_links(multi, mem, url); } } } } }该模式的价值在于并发爬虫中每个 easy 句柄的初始 URL 相同如https://example.com/但经重定向后各自的最终 URL 不同。此时CURLINFO_EFFECTIVE_URL能精确告诉你这个句柄最终真正访问了哪个地址从而打印/记录真实的请求落点用于调试与审计以最终 URL 为基准继续解析相对链接、发起下一轮抓取crawler.c 中follow_links()正是把url作为基准传入配合CURLINFO_PRIVATE、CURLINFO_RESPONSE_CODE、CURLINFO_CONTENT_TYPE等选项组成完整的请求结果画像。仓库中 docs/examples/multi-event.c、docs/examples/hiperfifo.c、docs/examples/ephiperfifo.c 等事件驱动示例也展示了同样的用法可作为参考。八、常见问题与使用建议问题解答返回的 URL 指针能为 NULL 吗能。文档明确说明指针可能为 NULL使用前务必判空if(url)。需要自己 free 吗不需要也严禁free。内存由句柄私有管理curl_easy_cleanup()时自动释放。什么时机调用最合适curl_easy_perform()返回后multi 场景下在CURLMSG_DONE消息处理中调用。未跟随重定向时会怎样若不存在重定向/HSTS 升级等改写返回的通常就是你设置的原 URL规范化后的形式。与 CURLOPT_URL 的区别CURLOPT_URL是输入——你要求的地址CURLINFO_EFFECTIVE_URL是输出——libcurl 最终实际使用的地址。工程实践建议立即消费或拷贝由于指针指向句柄私有内存、生命周期与句柄绑定如需长期保存请strdup()一份配合 FOLLOWLOCATION 使用只要开启了重定向跟随就应通过本选项获取真实落点而不是想当然地认为最终 URL 等于初始 URL判空 检查返回值先判断CURLcode是否为CURLE_OK再判断url是否非 NULL用于日志与审计把 effective URL 与响应码、内容类型一起记录可精确还原每次请求的真实路径。九、总结CURLINFO_EFFECTIVE_URL是 libcurl 中轻量却极为实用的信息选项它以char **输出句柄内部data-state.url的当前值真实反映最后一次实际使用的有效 URL。其核心价值在于重定向跟随、HSTS 升级等场景下揭示请求的真实落点。使用上只需记住三条铁律只读、勿 free、随curl_easy_cleanup()自动释放并在 multi interface 中通过CURLMSG_DONE逐个句柄取回结果。结合本文给出的源码路径lib/getinfo.c、lib/http.c、lib/url.c与仓库示例docs/examples/crawler.c你可以在自己的项目中准确、安全地使用这一 API。【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表