使用http-client的call-with-input-request如何获取状态≥300的响应对象
调用
call-with-input-request遇到非2xx状态码时获取响应对象的方法 call-with-input-request抛出的HTTP相关异常条件本身就绑定了完整的响应对象,不需要等待函数正常返回,通过Scheme原生的条件捕获机制即可取出,具体实现如下:
核心实现逻辑
- 用CHICKEN内置的
handle-exceptions语法包裹请求调用,捕获(exn http client-error)、(exn http server-error)、(exn http unexpected-server-response)三类HTTP异常。 - 捕获到对应异常后,通过
exn:http-response访问器直接从异常实例中提取响应对象,后续读取状态码、原因短语、响应头、响应体的操作和正常响应的处理逻辑完全一致。 - 非HTTP类的异常不要捕获,直接重新抛出避免影响其他错误处理逻辑。
可直接运行的示例代码
(import http-client (chicken condition) (chicken port)) (handle-exceptions exn (cond ;; 匹配所有HTTP请求相关异常 ((or (exn:http:client-error? exn) (exn:http:server-error? exn) (exn:http:unexpected-server-response? exn)) (let* ((resp (exn:http-response exn)) ; 从异常中提取响应对象 (status (http-response-status resp)) (reason (http-response-reason resp)) (body (read-string #f (http-response-port resp)))) ;; 这里可以按需做日志打印、内容解析等操作 (printf "请求返回非2xx状态,状态码:~a,原因:~a~n响应内容:~a~n" status reason body))) ;; 非HTTP异常直接向上抛出 (else (abort exn))) ;; 正常请求逻辑 (call-with-input-request "https://example.com/not-exist-path" #f (lambda (reader) (print "请求成功,响应内容:" (read-string #f reader)))))
补充说明
- 不需要替换成其他底层请求函数,也不需要修改
call-with-input-request的参数,异常携带响应是http-client库的默认实现,所有3xx-5xx区间的响应都可以通过这个方式拿到。 - 从异常中取出的响应端口读取完成后会被GC自动回收,也可以手动调用
close-input-port释放资源,避免端口占用。 - 如果需要自行处理3xx跳转逻辑,可以在发起请求前将参数
*follow-redirects?*设置为#f关闭自动跳转,此时3xx响应同样会以异常形式抛出,按上述方法提取响应即可。 - 注意不要混淆不可继续异常的特性:不可继续仅代表异常触发后原函数不会恢复执行返回正常值,不代表异常对象本身携带的上下文数据会丢失,在异常捕获分支内可以正常访问所有绑定的字段。
内容的提问来源于stack exchange,提问作者shadowtalker
相关产品推荐
相关产品推荐

