异步http接口调用库:httpx

2024-01-24 19:52
文章标签 接口 http 调用 异步 httpx

本文主要是介绍异步http接口调用库:httpx,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

谈到http接口调用,Requests大家并不陌生,例如,robotframework-requests、HttpRunner等HTTP接口测试库/框架都是基于它开发。这里将介绍另一款http接口测试框架:httpx。

它的API和Requests高度一致。

github: GitHub - encode/httpx: A next generation HTTP client for Python. 🦋

安装:

> pip install httpx

httpx 简单使用

当然,它是不支持python2.x的。

  • 简单的get调用
import httpxr = httpx.get("http://httpbin.org/get")
print(r.status_code)
print(r.json())

执行结果:

200
{'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-httpx/0.12.1', 'X-Amzn-Trace-Id': 'Root=1-5ea5b58c-e446c44392ea090809e8a4bc'}, 'origin': '113.97.33.224', 'url': 'http://httpbin.org/get'}
  • 带参数的post调用
import httpxpayload = {'key1': 'value1', 'key2': 'value2'}
r = httpx.post("http://httpbin.org/post", data=payload)
print(r.json())

执行结果:

{'args': {}, 'data': '', 'files': {}, 'form': {'key1': 'value1', 'key2': 'value2'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Content-Length': '23', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'httpbin.org', 'User-Agent': 'python-httpx/0.12.1', 'X-Amzn-Trace-Id': 'Root=1-5ea5b61d-1871d10e80b8324e48ea475e'}, 'json': None, 'origin': '113.97.33.224', 'url': 'http://httpbin.org/post'}

你会发现这几乎和requests一模一样,只不过把requests 换成了httpx。

httpx 异步调用

接下来认识httpx的异步调用:

import httpx
import asyncioasync def main():async with httpx.AsyncClient() as client:resp = await client.get('http://httpbin.org/get')result = resp.json()print(result)asyncio.run(main())

这里用到了async 、await, asyncio等,等参考我关于python异步I/O的基础介绍:https://www.cnblogs.com/fnng/p/12757395.html

异步的调用的优势

我们发现,采用异步会让接口的调用更加复杂,那为什么还要使用异步呢?当你要调用1000次接口时,那么异步调用可以让你的调用更快。接下来我们通过简单让例子进行对比。

以我flask开发的简单接口为例子:

GitHub - defnngj/learning-API-test: learning API test

为了测试的更加准确性,我将flask服务部署在了另一台电脑,测试机与被测服务分离。

  • httpx 同步调用
# 同步调用
import time
import httpxdef make_request(client):resp = client.get('http://192.168.0.7:5000')result = resp.json()# print(result)assert result["code"] == 10200def main():session = httpx.Client()# 1000 次调用for _ in range(1000):make_request(session)if __name__ == '__main__':# 开始start = time.time()main()# 结束end = time.time()print(f'同步:发送1000次请求,耗时:{end - start}')

结果:

...
同步:发送1000次请求,耗时:52.948561906814575
  • httpx 异步调用
# 异步调用
import httpx
import asyncio
import timeasync def request(client):resp = await client.get('http://192.168.0.7:5000')result = resp.json()# print(result)assert result["code"] == 10200async def main():async with httpx.AsyncClient() as client:# # 开始# start = time.time()# 1000 次调用task_list = []for _ in range(1000):req = request(client)task = asyncio.create_task(req)task_list.append(task)await asyncio.gather(*task_list)if __name__ == "__main__":#开始start = time.time()asyncio.run(main())# 结束end = time.time()print(f'异步:发送1000次请求,耗时:{end - start}')

结果:

...
异步:发送1000次请求,耗时:3.903275728225708

将httpx用于请求端,同步与异步请求差距非常明显。

以上的例子已经放到 learning-API-test github项目

总结

* 这里只是拿 flask 非异步框架做为接口服务端进行对比,如果如果将接口服务同样换作前面介绍的 snaic 异步框架,上面的两组测试对比并不明显(snaic的异步接口服务处理同步请求更快),在安装 snaic的时候会发现,他同样也集成了 httpx 库。

* 为什么要学习异步,因为我们公司有很多接口是异步调用的,所以,我想真正搞懂这个概念,就这么简单!保持在工作中对技术的好奇心。

  • 异步与多线程的区别?这是我在学习 异步时候的一个疑问,我找到了一个比较形象的例子。

以火车站购票场景为例:一个火车站为一个进程,一个窗口和售票员的组合为一个线程:

  • 多线程:火车站开了N个窗口售票员,我们去买票,会有工作人员(CPU)指定我们去某个窗口买票,你被安排到某个窗口后,告诉售票员你的请求(咨询或买票),售票员执行操作,如果这个过程中发送的阻塞,也是窗口售票员的阻塞(比如查票的过程),但是因为你开了很多个窗口,其他买票的人可以被安排去另外的空闲窗口,如果所有窗口都满了,工作人员就不会给你安排了,直到有空的窗口出来;
  • 多进程(并行):建多个火车站售票,火车站与火车站间互不影响,看买票的自己想去哪里(这里不讨论负载均衡);
  • 异步:火车站只有一个窗口售票员,但是窗口前有一个登记台(事件循环),你把你想买的票告诉给登记台,并留下你的手机(回调函数),然后你就可以走了,由于登记台只是登记了你的请求,并没有做任何其他操作,所以这个耗时基本忽略不计的。之后售票员处理完了上一个任务了,就会自己去登记台取剩下的未完成的任务,直到取到你的任务,操作完后,有票没票都会通过手机通知你,如果有票还会往你的手机发车票的二维码;

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你! 

这篇关于异步http接口调用库:httpx的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/640827

相关文章

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码

【Linux】应用层http协议

一、HTTP协议 1.1 简要介绍一下HTTP        我们在网络的应用层中可以自己定义协议,但是,已经有大佬定义了一些现成的,非常好用的应用层协议,供我们直接使用,HTTP(超文本传输协议)就是其中之一。        在互联网世界中,HTTP(超文本传输协议)是一个至关重要的协议,他定义了客户端(如浏览器)与服务器之间如何进行通信,以交换或者传输超文本(比如HTML文档)。

Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果: 解密后的数据就是正常数据: 后端:使用的是spring-cloud框架,在gateway模块进行操作 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency> 编写一个AES加密

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而

js异步提交form表单的解决方案

1.定义异步提交表单的方法 (通用方法) /*** 异步提交form表单* @param options {form:form表单元素,success:执行成功后处理函数}* <span style="color:#ff0000;"><strong>@注意 后台接收参数要解码否则中文会导致乱码 如:URLDecoder.decode(param,"UTF-8")</strong></span>

【LabVIEW学习篇 - 21】:DLL与API的调用

文章目录 DLL与API调用DLLAPIDLL的调用 DLL与API调用 LabVIEW虽然已经足够强大,但不同的语言在不同领域都有着自己的优势,为了强强联合,LabVIEW提供了强大的外部程序接口能力,包括DLL、CIN(C语言接口)、ActiveX、.NET、MATLAB等等。通过DLL可以使用户很方便地调用C、C++、C#、VB等编程语言写的程序以及windows自带的大

Anaconda 中遇到CondaHTTPError: HTTP 404 NOT FOUND for url的问题及解决办法

最近在跑一个开源项目遇到了以下问题,查了很多资料都大(抄)同(来)小(抄)异(去)的,解决不了根本问题,费了很大的劲终于得以解决,记录如下: 1、问题及过程: (myenv) D:\Workspace\python\XXXXX>conda install python=3.6.13 Solving environment: done.....Proceed ([y]/n)? yDownloa

java线程深度解析(一)——java new 接口?匿名内部类给你答案

http://blog.csdn.net/daybreak1209/article/details/51305477 一、内部类 1、内部类初识 一般,一个类里主要包含类的方法和属性,但在Java中还提出在类中继续定义类(内部类)的概念。 内部类的定义:类的内部定义类 先来看一个实例 [html]  view plain copy pu

模拟实现vector中的常见接口

insert void insert(iterator pos, const T& x){if (_finish == _endofstorage){int n = pos - _start;size_t newcapacity = capacity() == 0 ? 2 : capacity() * 2;reserve(newcapacity);pos = _start + n;//防止迭代