Python技巧-Falcon构建轻量级的REST API服务

Falcon构建轻量级的REST API服务


Falcon 是一个轻量级的Python Web框架,专注于构建RESTful API,它被设计为简单而快速,致力于提供高性能的API服务。

Falcon Tutorial文档

https://falcon.readthedocs.io/en/stable/user/tutorial.html

安装falcon

在开始之前,先得保证falcon已经安装。

$ pip install falcon

构建falcon项目

项目文件结构目录构造,如下:

image-classify
├── .venv
└── image-classify
    ├── __init__.py
    └── app.py

现在创建并打开app.py文件,作为应用的入口,编辑修改如下代码:

import falcon

app = application = falcon.App()

这就创建了一个 WSGI 应用,以app作为别名。 可以使用任何变量名,Gunicorn希望默认使用application。

WSGI应用只是一个可调用的明确定义的签名,可以在任何支持WSGI协议的web server上托管应用。

Falcon框架包含大量的内联文档,可以通过使用python模块查看技巧来查询。经过Falcon团队对文档可读性的大量优化,可以很快浏览和查找我们需要的。

应用托管(Hosting Your App)

前面已经创建了一个简单的Falcon应用,我们可以让它运行在WSGI server上。Python包含一个自托管的参考server,但是我们还是使用实际部署时使用的server。

$ pip install gunicorn
$ gunicorn app

应用服务部署后,可以检验服务效果,现在我们使用curl尝试查询它:

$ curl localhost:8000 -v

如果不出不意外,你应当将会获取到404。网络访问不到,怎么回事?
一方面,说明应用服务已经运行,已经有返回值404。Falcon包含默认的404响应处理(response handler),用来处理没有匹配到任何路由的请求地址。另一方面,返回404,这很正常,因为应用还没有设定任何路由(route)。

简单示例

下面是一个简单的Hello World示例,展示了Falcon框架的基本用法:

Hello World 实例下载

import falcon

class HelloWorldResource:
    def on_get(self, req, resp):
        resp.status = falcon.HTTP_200
        resp.text = 'Hello, Falcon!'

# 创建Falcon应用
app = falcon.App()

# 指定资源路由
app.add_route('/', HelloWorldResource())

在上面的示例中,我们定义了一个名为HelloWorldResource的资源类,它包含一个处理HTTP GET请求的方法 on_get。然后,创建了一个Falcon应用,并将资源路由到根路径’/'。

示例有需要的可下载链接:https://download.csdn.net/download/Alex_StarSky/88536687

内容服务(Serving Text)

JSON请求和响应处理

Falcon使用请求(req)和响应(resp)对象来处理HTTP请求和构建HTTP响应。以下是一个处理GET请求并返回JSON响应的示例:

import falcon
import json

class JsonResource:
    def on_get(self, req, resp):
        # 构建JSON响应
        resp.status = falcon.HTTP_200
        resp.content_type = 'application/json'
        resp.body = json.dumps({'message': 'Hello, Falcon!'})

JSON服务示例下载 : https://download.csdn.net/download/Alex_StarSky/88536826

路由和 URI 参数

Falcon使用路由来映射URI到资源。可以通过add_route方法或者使用装饰器 @app.route 来定义路由。以下是一个使用URI参数的示例:

import falcon

class GreetResource:
    def on_get(self, req, resp, name):
        resp.status = falcon.HTTP_200
        resp.text = f'Hello, {name}!'

app = falcon.App()
app.add_route('/greet/{name}', GreetResource())

在上面的示例中,URI参数{name}将会传递给on_get方法。

中间件

Falcon允许使用中间件来执行在请求处理前后的一些逻辑。以下是一个简单的中间件示例,记录请求处理时间:

import falcon
import time

class TimingMiddleware:
    def process_request(self, req, resp):
        req.start_time = time.time()

    def process_resource(self, req, resp, resource, params):
        resource.processing_time = time.time() - req.start_time

    def process_response(self, req, resp, resource, req_succeeded):
        resp.set_header('X-Processing-Time', str(resource.processing_time))

app = falcon.App(middleware=[TimingMiddleware()])
异常处理

Falcon允许通过抛出自定义异常来处理错误。以下是一个示例,当请求的资源不存在时抛出HTTPNotFound异常:

import falcon

class ResourceNotFound(Exception):
    def __init__(self, resource_name):
        self.resource_name = resource_name

class CustomResource:
    def on_get(self, req, resp, name):
        if name != 'custom':
            raise ResourceNotFound(name)
        
        resp.status = falcon.HTTP_200
        resp.text = f'Hello, {name}!'
        
# 在应用中添加错误处理
app.add_error_handler(ResourceNotFound, lambda ex, req, resp, params: self.handle_not_found(req, resp, ex))

def handle_not_found(self, req, resp, ex):
    resp.status = falcon.HTTP_404
    resp.text = f'Resource "{ex.resource_name}" not found.'        

图像服务(Serving Images)

创建图像资源

Falcon从REST架构风格引入一些术语,REST概念。Falcon的设计理念是,尽可能直观地让所有人理解HTTP基本原理。

在Falcon中,可以把传入的请求(incoming requests)称为资源(Resources)。资源只是一个常规Class,包含一些遵循一定命名规则的方法(Method)。每个方法对应一个动作(API客户端为了获取或转换资源,去请求执行的动作)。

现在项目需要在构建一个图片分享API,那可以创建一个image资源。在项目目录中,创建一个image.py的文件,可以在里面添加下面的代码:

import falcon

class ImgResource(object):    
    def on_get(self, req, resp):
        resp.body = '{"message":"Hello woeld!"}'
        resp.status = falcon.HTTP_200

Resource只是一个很常规的class,类名可以任意取。Falcon使用duck-typing,所以不需要继承任何特定的基类。

上面的image资源定义单一方法on_get。对于resource想要支持的任何HTTP方法,只需要简单在resource上加on_x类方法(class method),x可以是标准HTTP方法中的任何一个,例如on_get,on_put,on_head(小写)等等。

方法称作responders(响应器),每个responder至少需要两个参数,一个代表HTTP请求,另一个代表对应请求的HTTP响应。根据习惯,一般缩写作req和resp。如果是route(路由)和hooks(钩子)可以添加一些额外的参数。

例程中,image资源对GET请求作出响应:200 OK 和一个JSON对象。Falcon默认是application/json作为互联网媒体类型,但是可以设置成任何使用的类型。例如,可以使用MessagePack或者其他序列化格式。

关联资源

现在再把应用服务关联上resource,在app.py,增加资源描述,并关联请求URI,将其修改成如下:

import falcon
import images

api = application = falcon.API()

images = images.ImgResource()
api.add_route('/images', images)

现在,如果传入一个“/images”的请求,Falcon请会调用images的资源中的响应器(responder)–对应所需要的HTTP方法。
重启gunicorn,并且尝试向resource(资源)发送一个GET请求:

$ curl localhost:8000/images -v

duck-typing:动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。在duck typing中,关注的不是对象的类型本身,而是它是如何使用的。

请求和响应对象

资源(resource)中的每个响应器(responder)接收一个请求对象(request object),可以被用作读取headers、查询参数和请求的body。

每个响应器(responder)也能接收一个响应对象(response object),可以被用作设置HTTP状态码、headers和响应的body。
可以使用help函数去列举Request,Response类的成员。

让我们探究一下如何运作。当客户端(client)POST到images集合(collection)时,需要创建一个新的image资源。首先,需指定images保存在什么地方。

实现POST响应器(responder):

编辑images.py 文件,添加下列代码到ImgResource:

import os
import time
import uuid
import falcon

def _media_type_to_ext(media_type):
    #剥离'/images/'前缀
    return media_type[6:]

def _generate_id():
    return str(uuid.uuid4())

class ImgResource(object):

    def __init__(self, storage_path):
        self.storage_path = storage_path
    
    def on_post(self, req, resp):
        image_id = _generate_id()
        ext = _media_type_to_ext(req.content_type)
        filename = image_id + '.' + ext
        
        image_path = os.path.join(self.storage_path, filename)
        with open(image_path, 'wb') as image_file:
            while True:
                chunk  = req.stream.read(4096)
                if not chunk:
                    break
                image_file.write(chunk)
        
        resp.status = falcon.HTTP_201
        resp.location = '/images/' + image_id

程序给新图片生成了一个唯一的ID和文件名,然后从req.stream 中读取文件数据,再写入磁盘。调用stream而不是body去强调事实,正在从输入流读取;Falcon不会输出(spool)或解码(decode)请求数据(request data),而是直接访问由WSGI server提供的二进制输入流(incoming binary stream)。

注意,将HTTP response status code设置为“201 Created”。预定义的状态字符清单,可以通过对falcon.status_codes调用help函数来查看。

在on_post响应器的最后一行,给新创建的资源设置Location Header。创建一个路由(route))注意,Request类和Response类包含一些读取和设置通用header的便利属性,但是通过声明req.get_header和resp.set_header方法,总是可以使用任何header。

重启gunicorn,然后尝试给resource发送一个POST请求(可以将test.jpg替换成任何你想操作的JPEG文件的路径)

图像下载

已经完成上传图片到服务器,接下来是要能获取它们,通过带有文件路径的请求,让服务器返回一张图片到Location header,就像这样:

localhost:8000/images/87db45ff42

接下来,可以在images资源中添加on_get响应器。按照这个思路,如果要处理多张图片,除了表示单张图片资源的类以外,还需要新建一个类。我们可以在新的类中添加on_get响应器。

需要注意到on_get响应器中的name参数。任何在路由中指定的URL参数都将被转换成对应的kwargs参数,同时传递到目标响应器(responder)中。
在on_get响应器中,按照文件名扩展去设置内容类型的header,然后通过打开文件操作来直接以数据流形式输出图片。还有需要注意resp.stream_len 的用法。每当使用resp.stream来代替resp.body或resp.data的时候,必须给数据流指定一个预期的长度,以便web客户端知道从响应(response)中读取的数据有多大。

如果resp.status没有明确地设定,其默认值为200 OK,确切的说,这应该是应该在on_get响应器去做的。

现在将事件关联上,然后尝试运行一下。首先按照下面的例子来编辑app.py:

import falcon
import images

api = application = falcon.API()

storage_path = '/usr/local/var/look'

image_collection = images.ImgResource(storage_path)
image = image.Item(storage_path)

api.add_route('/images', image_collection)
api.add_route('/images/(name)', image)

定义了一个新的路由/images/{name}。这会让Falcon将所有的对应的响应器(responder)和获取的name参数关联起来。

Falcon还支持更加复杂的参数化路径段(包含多个值)。例如,类Grasshopper(GH-like,可以通过参数的调整,直接改变模型形态)的API能够使用下面的模板为两个分支添加一个路由。

/repo/{org}/{repo}/compare/{usr0}:{branch0}…{usr1}:{branch1}

可以继续在浏览器中输入URL,图片会被正确的显示出来。

最佳实践

  • 使用装饰器简化路由定义: Falcon提供了@app.route装饰器,可以简化路由的定义。
  • 使用 Request 和 Response 模型: Falcon提供了Request和Response对象的模型,它们对原始HTTP请求和响应进行了封装,提供更便捷的处理方式。
  • 使用中间件处理通用逻辑: 中间件是Falcon的强大功能之一,可用于处理日志、鉴权等通用逻辑。
  • 异常处理的一致性: 使用自定义异常来处理错误,确保API的一致性和可维护性。

End


决策引擎-利用Drools实现简单防火墙策略

GPT专栏文章:

GPT实战系列-ChatGLM3本地部署CUDA11+1080Ti+显卡24G实战方案

GPT实战系列-ChatGLM2模型的微调训练参数解读

GPT实战系列-如何用自己数据微调ChatGLM2模型训练

GPT实战系列-ChatGLM2部署Ubuntu+Cuda11+显存24G实战方案

GPT实战系列-Baichuan2本地化部署实战方案

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Open-Falcon 是一款开源的监控系统,可以监控各种资源的状态,包括服务器负载、网络状态、应用程序指标等。它提供了丰富的监控指标和灵活的告警机制,可以帮助运维人员及时发现和解决问题。下面是 Spring Boot 整合 Open-Falcon 的简单示例。 1. 引入依赖 在 pom.xml 文件中添加 Open-Falcon 的客户端依赖: ```xml <dependency> <groupId>com.github.open-falcon</groupId> <artifactId>falcon-sdk-java</artifactId> <version>0.1.0</version> </dependency> ``` 2. 配置 Open-Falcon 客户端 在 application.properties 文件中配置 Open-Falcon 客户端相关属性: ```properties # Open-Falcon 服务地址 falcon.server=http://localhost:6060/api/push # 应用程序名称 falcon.endpoint=my-application ``` 3. 编写监控指标 在代码中编写需要监控的指标,如 CPU 使用率、内存使用率等。可以使用 Open-Falcon 客户端提供的 API 将指标发送到 Open-Falcon 服务端: ```java import com.github.openfalcon.push.PushClient; import com.github.openfalcon.push.PushEntity; public class MyMonitor { private PushClient pushClient; public MyMonitor(String falconServer, String endpoint) { pushClient = new PushClient(falconServer, endpoint); } public void reportCpuUsage(float usage) { PushEntity entity = new PushEntity("cpu.usage", String.valueOf(usage), "", ""); pushClient.push(entity); } public void reportMemoryUsage(float usage) { PushEntity entity = new PushEntity("memory.usage", String.valueOf(usage), "", ""); pushClient.push(entity); } // 其他监控指标 } ``` 4. 启动应用程序 在应用程序启动时,创建监控对象,并在需要监控的地方调用相应的监控方法。 ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); MyMonitor monitor = new MyMonitor("http://localhost:6060/api/push", "my-application"); while (true) { float cpuUsage = getCpuUsage(); float memoryUsage = getMemoryUsage(); monitor.reportCpuUsage(cpuUsage); monitor.reportMemoryUsage(memoryUsage); Thread.sleep(1000); } } private static float getCpuUsage() { // 获取 CPU 使用率 return 0.5f; } private static float getMemoryUsage() { // 获取内存使用率 return 0.6f; } } ``` 以上是一个简单的 Spring Boot 整合 Open-Falcon 的示例,具体的监控指标和告警机制可以根据实际需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alex_StarSky

你的鼓励是创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值