QGIS Server 插件开发指南

QGIS Server 插件开发指南

一、插件机制

1.1 插件发现

QGIS Server 启动时,扫描 QGIS_PLUGINPATH 环境变量指定的目录,对每个包含 metadata.txtserver=True 的子目录,执行其 __init__.py 中的 serverClassFactory(serverIface) 函数。

复制代码
QGIS_PLUGINPATH=/io/plugins
    │
    ├── rest_map_service/       ← 含 metadata.txt (server=True),加载
    ├── qgis-helloserver/       ← 含 metadata.txt (server=True),加载
    ├── template_service/       ← 含 metadata.txt (server=True),加载
    └── some_dir/               ← 无 metadata.txt,跳过

插件最小文件集合:

复制代码
my_plugin/
├── metadata.txt       # 元信息(server=True 是必须的)
└── __init__.py        # 包含 serverClassFactory(serverIface) 函数

1.2 入口函数约定

python 复制代码
# __init__.py --- QGIS Server 唯一识别入口
def serverClassFactory(serverIface):
    """serverIface 是 QgsServerInterface 实例,提供注册 API"""
    from .impl import MyPlugin
    return MyPlugin(serverIface)

serverIface 提供三种注册方法,对应三种插件类型:

注册方法 插件类型 基类
serverIface.serviceRegistry().registerService(obj) Service(服务) QgsService
serverIface.registerFilter(obj, priority) Filter(过滤器) QgsServerFilter
serverIface.registerAccessControl(obj, priority) Access Control(访问控制) QgsAccessControlFilter

一个 serverClassFactory 内可以同时注册多种类型。

1.3 架构全景

复制代码
                          HTTP Request
                               │
                               ▼
                    ┌──────────────────────┐
                    │       Nginx          │
                    │  URL 重写 / 反向代理  │
                    └──────────┬───────────┘
                               │ /ows/?SERVICE=...&MAP=...
                               ▼
                    ┌──────────────────────┐
                    │    QGIS Server        │
                    │                       │
                    │  ┌─────────────────┐ │
                    │  │ requestReady()  │ │ ← Filter 钩子 1
                    │  └────────┬────────┘ │
                    │           │          │
                    │  ┌────────▼────────┐ │
                    │  │ Access Control  │ │ ← 权限检查(在渲染前)
                    │  └────────┬────────┘ │
                    │           │          │
                    │  ┌────────▼────────┐ │
                    │  │ Service / WMS   │ │ ← 核心处理或 Service 接管
                    │  │ / WFS / WCS ... │ │
                    │  └────────┬────────┘ │
                    │           │          │
                    │  ┌────────▼────────┐ │
                    │  │ sendResponse()  │ │ ← Filter 钩子 2
                    │  └────────┬────────┘ │
                    │           │          │
                    │  ┌────────▼────────┐ │
                    │  │responseComplete │ │ ← Filter 钩子 3
                    │  │   ()            │ │
                    │  └────────┬────────┘ │
                    │                       │
                    └───────────┬───────────┘
                               ▼
                          HTTP Response

二、三种插件类型

2.1 Service(服务) --- 完全接管

基类QgsService
激活SERVICE=XXX 参数匹配 name() 返回值
适用场景:自定义 REST API、替代 WMS/WFS 的自定义协议

复制代码
请求: /ows/?SERVICE=MYAPI&OPERATION=xxx
        │
        ▼
  QGIS Server 查找注册了 name()=="MYAPI" 的 Service
        │
        ▼
  调用 executeRequest(request, response, project)
        │
        ▼
  插件完全控制响应内容

必须实现的方法

方法 说明
name() 返回服务名,对应 SERVICE= 参数
version() 返回版本号字符串
executeRequest(request, response, project) 核心:处理请求、写入响应

关键 API

python 复制代码
# 请求
request.parameter("KEY")        # 获取参数(仅标准 OWS 参数)
request.method()                 # QgsServerRequest.GetMethod / PostMethod
request.url()                    # PyQt6 返回 QUrl,需 .toString()

# 响应
response.setStatusCode(200)
response.setHeader("Content-Type", "application/json")
response.write(b"...body...")

注意request.parameter() 仅返回 QGIS Server 识别的标准参数(SERVICE、MAP、REQUEST 等)。自定义参数需通过解析 URL 获取,见 [4.1 常见问题](#4.1 常见问题)。


2.2 Filter(过滤器) --- 旁路拦截

基类QgsServerFilter
激活 :所有请求自动经过(不需要特定 SERVICE)
适用场景:日志、鉴权、水印、响应注入、参数预处理

复制代码
请求到达
    │
    ▼
  requestReady()        ← 可修改请求参数、做鉴权
    │
    ▼
  [QGIS Server 核心处理]
    │
    ▼
  sendResponse()        ← 可修改响应头
    │
    ▼
  responseComplete()    ← 可修改响应体(加水印、替换内容)
    │
    ▼
响应发出

三个钩子按固定顺序触发 ,每个钩子的 handler 对象提供不同能力:

python 复制代码
handler = self.serverInterface().requestHandler()
params  = handler.parameterMap()      # 读所有参数
handler.setParameter('K', 'V')        # 注入参数 (requestReady 中)
handler.setResponseHeader('K', 'V')   # 设置响应头 (sendResponse 中)
handler.setServiceException(ex)       # 抛出受控异常
handler.body()                        # 读响应体 (responseComplete 中)
handler.clearBody()                   # 清空
handler.appendBody(b'...')            # 追加
handler.clear()                       # 清空全部

优先级registerFilter(filter, priority) 的值越小越先执行。


2.3 Access Control(访问控制) --- 权限管控

基类QgsAccessControlFilter
激活 :在渲染/查询之前 自动执行
适用场景:图层级权限、字段过滤、行级数据过滤

特点:在 Service 或 WMS/WFS 处理之前运行,被限制的数据根本不会进入渲染管线,比 Filter 更安全。

可覆写的方法

python 复制代码
# 图层级权限------控制增删改查
def layerPermissions(self, layer) -> LayerPermissions:
    # canRead / canInsert / canUpdate / canDelete

# 字段级权限------控制哪些字段可见
def authorizedLayerAttributes(self, layer, attributes) -> list:
    # 返回允许的字段列表

# 行级权限------SQL 过滤表达式(可选)
def layerFilterExpression(self, layer) -> str:
    # 返回 SQL WHERE 子句

三、三个模板插件

3.1 template_service --- Service 模板

路径qgis-server/plugins/template_service/

python 复制代码
# service_impl.py(核心代码)
from qgis.server import QgsService

class TemplateService(QgsService):
    def name(self):
        return "TEMPLATE"         # 请求中 SERVICE=TEMPLATE

    def version(self):
        return "1.0.0"

    def executeRequest(self, request, response, project):
        operation = request.parameter("OPERATION") or ""
        if not operation:
            self._send_json(response, {           # 默认:返回服务描述
                "service": "TEMPLATE",
                "operations": ["ping", "echo", "info"],
            })
        elif operation == "ping":
            self._send_json(response, {"pong": True})
        elif operation == "echo":
            msg = request.parameter("msg") or ""
            self._send_json(response, {"echo": msg})
        elif operation == "info":
            # 返回项目元信息
            layers = [{"id": lid, "name": l.name()} for lid, l in project.mapLayers().items()]
            self._send_json(response, {"project": ..., "layers": layers})
        else:
            self._send_json(response, {"error": "Unknown"}, 404)

测试

bash 复制代码
curl "localhost:8050/ows/?SERVICE=TEMPLATE&MAP=/io/data/china.qgs"
# → {"service":"TEMPLATE","version":"1.0.0","operations":["ping","echo","info"],...}

curl "localhost:8050/ows/?SERVICE=TEMPLATE&OPERATION=ping&MAP=/io/data/china.qgs"
# → {"pong":true}

curl "localhost:8050/ows/?SERVICE=TEMPLATE&OPERATION=info&MAP=/io/data/china.qgs"
# → {"project":"/io/data/china.qgs","crs":"EPSG:4490","layerCount":1,...}

扩展指南 :在 executeRequest 中添加新的 elif operation == "xxx": 分支,或改为 RESTful 路由(参考 rest_map_service)。


3.2 template_filter --- Filter 模板

路径qgis-server/plugins/template_filter/

python 复制代码
# filter_impl.py(核心代码)
from qgis.server import QgsServerFilter

class TemplateFilter(QgsServerFilter):
    def requestReady(self):
        # 钩子 1:请求到达,可注入参数
        params = handler.parameterMap()
        log(f"--> {params.get('SERVICE')} / {params.get('REQUEST')}")

    def sendResponse(self):
        # 钩子 2:响应头发送前
        handler.setResponseHeader("X-Template-Filter", "v1.0")

    def responseComplete(self):
        # 钩子 3:响应生成完毕,可修改响应体
        elapsed = (time.time() - self._start) * 1000
        log(f"<-- done in {elapsed:.1f}ms")

测试

bash 复制代码
curl "localhost:8050/ows/?SERVICE=WMS&REQUEST=GetCapabilities&MAP=/io/data/china.qgs"
# 查看 QGIS Server 日志:
# docker logs qgis-server | grep TemplateFilter
# → --> WMS / GetCapabilities from /io/data/china.qgs
# → <-- WMS / GetCapabilities done in 1.9ms

扩展指南

  • 鉴权 :在 requestReady 中检查 token,不合法则 handler.setServiceException()
  • 水印 :在 responseComplete 中读 handler.body() → QPainter 画水印 → 写回
  • 参数注入 :在 requestReadyhandler.setParameter('KEY', 'VALUE')

3.3 template_access_control --- Access Control 模板

路径qgis-server/plugins/template_access_control/

python 复制代码
# access_impl.py(核心代码)
from qgis.server import QgsAccessControlFilter

class TemplateAccessControl(QgsAccessControlFilter):
    def layerPermissions(self, layer):
        perms = QgsAccessControlFilter.LayerPermissions()
        perms.canRead = True     # 允许读取
        perms.canInsert = True
        perms.canUpdate = True   # 改为 False 可禁止编辑
        perms.canDelete = True
        return perms

    def authorizedLayerAttributes(self, layer, attributes):
        # 返回允许可见的字段列表
        return attributes

    # def layerFilterExpression(self, layer):
    #     return ""   # 行级过滤 SQL

特性 :无直接 HTTP 入口------它对所有 WMS/WFS 请求静默生效。权限检查发生在渲染之前,被限制的数据不会进入渲染管线。

测试方法

bash 复制代码
# 1. 将 china_province 层的 canRead 改为 False
# 2. 请求 WMS GetMap → 该图层不会渲染
curl "localhost:8050/ows/?SERVICE=WMS&REQUEST=GetMap&MAP=/io/data/china.qgs&LAYERS=china_province&..."
# → 空白图片(图层被 Access Control 屏蔽)

扩展指南

  • 按图层控制 :在 layerPermissionsif layer.name() == "机密数据": perms.canRead = False
  • 字段脱敏 :在 authorizedLayerAttributes 中过滤敏感字段
  • 多租户隔离 :在 layerFilterExpression 中追加 WHERE tenant_id = :current_tenant

四、从模板创建新插件

4.1 快速开始

bash 复制代码
# 1. 拷贝模板
cp -r plugins/template_service plugins/my_api

# 2. 修改 metadata.txt
#    name=My API Service

# 3. 重命名实现文件(可选)
mv plugins/my_api/service_impl.py plugins/my_api/my_api.py

# 4. 修改 __init__.py 的 import 路径
#    from .my_api import MyApiService

# 5. 修改 my_api.py
#    类名、name()、executeRequest 逻辑

# 6. 重启
docker compose restart qgis-server

# 7. 测试
curl "localhost:8050/ows/?SERVICE=???&MAP=/io/data/china.qgs"

4.2 常见问题

request.parameter() 获取不到自定义参数

QGIS Server 的 request.parameter() 只返回已知的 OWS 参数(SERVICE、MAP、REQUEST 等)。自定义参数需从 URL 解析:

python 复制代码
from urllib.parse import urlparse, parse_qs

def get_all_params(request):
    url_str = request.url().toString()  # PyQt6 中 url() 返回 QUrl
    query = urlparse(url_str).query
    params = {}
    for k, vals in parse_qs(query).items():
        params[k] = vals[0]
    return params
实现文件名和包名冲突
python 复制代码
# ❌ 错误:template_service/__init__.py 中
from .template_service import Xxx   # 包名=模块名,导入歧义

# ✅ 正确:用不同文件名
from .service_impl import Xxx
PyQt6 枚举位置变化
python 复制代码
# PyQt5:
from qgis.PyQt.QtCore import QIODevice
QIODevice.WriteOnly

# PyQt6 (QGIS 4.x):
from qgis.PyQt.QtCore import QIODeviceBase
QIODeviceBase.OpenModeFlag.WriteOnly

五、三种模式对比总结

Service Filter Access Control
基类 QgsService QgsServerFilter QgsAccessControlFilter
激活时机 SERVICE= 匹配 所有请求 渲染/查询前
对请求的影响 完全接管 旁路拦截 静默过滤
能做什么 自定义 API 日志/鉴权/水印 图层/字段/行级权限
不能做什么 影响 WMS/WFS 完全取代 Service 自定义响应格式
运行时开销 仅匹配 SERVICE 时 每个请求 每次渲染/查询
模板路径 template_service/ template_filter/ template_access_control/
可混合使用

三种机制在同一请求中的执行顺序:Filter (requestReady) → Access Control → Service/WMS → Filter (sendResponse) → Filter (responseComplete)

QGIS Server 插件开发指南

一、插件机制

1.1 插件发现

QGIS Server 启动时,扫描 QGIS_PLUGINPATH 环境变量指定的目录,对每个包含 metadata.txtserver=True 的子目录,执行其 __init__.py 中的 serverClassFactory(serverIface) 函数。

复制代码
QGIS_PLUGINPATH=/io/plugins
    │
    ├── rest_map_service/       ← 含 metadata.txt (server=True),加载
    ├── qgis-helloserver/       ← 含 metadata.txt (server=True),加载
    ├── template_service/       ← 含 metadata.txt (server=True),加载
    └── some_dir/               ← 无 metadata.txt,跳过

插件最小文件集合:

复制代码
my_plugin/
├── metadata.txt       # 元信息(server=True 是必须的)
└── __init__.py        # 包含 serverClassFactory(serverIface) 函数

1.2 入口函数约定

python 复制代码
# __init__.py --- QGIS Server 唯一识别入口
def serverClassFactory(serverIface):
    """serverIface 是 QgsServerInterface 实例,提供注册 API"""
    from .impl import MyPlugin
    return MyPlugin(serverIface)

serverIface 提供三种注册方法,对应三种插件类型:

注册方法 插件类型 基类
serverIface.serviceRegistry().registerService(obj) Service(服务) QgsService
serverIface.registerFilter(obj, priority) Filter(过滤器) QgsServerFilter
serverIface.registerAccessControl(obj, priority) Access Control(访问控制) QgsAccessControlFilter

一个 serverClassFactory 内可以同时注册多种类型。

1.3 架构全景

复制代码
                          HTTP Request
                               │
                               ▼
                    ┌──────────────────────┐
                    │       Nginx          │
                    │  URL 重写 / 反向代理  │
                    └──────────┬───────────┘
                               │ /ows/?SERVICE=...&MAP=...
                               ▼
                    ┌──────────────────────┐
                    │    QGIS Server        │
                    │                       │
                    │  ┌─────────────────┐ │
                    │  │ requestReady()  │ │ ← Filter 钩子 1
                    │  └────────┬────────┘ │
                    │           │          │
                    │  ┌────────▼────────┐ │
                    │  │ Access Control  │ │ ← 权限检查(在渲染前)
                    │  └────────┬────────┘ │
                    │           │          │
                    │  ┌────────▼────────┐ │
                    │  │ Service / WMS   │ │ ← 核心处理或 Service 接管
                    │  │ / WFS / WCS ... │ │
                    │  └────────┬────────┘ │
                    │           │          │
                    │  ┌────────▼────────┐ │
                    │  │ sendResponse()  │ │ ← Filter 钩子 2
                    │  └────────┬────────┘ │
                    │           │          │
                    │  ┌────────▼────────┐ │
                    │  │responseComplete │ │ ← Filter 钩子 3
                    │  │   ()            │ │
                    │  └────────┬────────┘ │
                    │                       │
                    └───────────┬───────────┘
                               ▼
                          HTTP Response

二、三种插件类型

2.1 Service(服务) --- 完全接管

基类QgsService
激活SERVICE=XXX 参数匹配 name() 返回值
适用场景:自定义 REST API、替代 WMS/WFS 的自定义协议

复制代码
请求: /ows/?SERVICE=MYAPI&OPERATION=xxx
        │
        ▼
  QGIS Server 查找注册了 name()=="MYAPI" 的 Service
        │
        ▼
  调用 executeRequest(request, response, project)
        │
        ▼
  插件完全控制响应内容

必须实现的方法

方法 说明
name() 返回服务名,对应 SERVICE= 参数
version() 返回版本号字符串
executeRequest(request, response, project) 核心:处理请求、写入响应

关键 API

python 复制代码
# 请求
request.parameter("KEY")        # 获取参数(仅标准 OWS 参数)
request.method()                 # QgsServerRequest.GetMethod / PostMethod
request.url()                    # PyQt6 返回 QUrl,需 .toString()

# 响应
response.setStatusCode(200)
response.setHeader("Content-Type", "application/json")
response.write(b"...body...")

注意request.parameter() 仅返回 QGIS Server 识别的标准参数(SERVICE、MAP、REQUEST 等)。自定义参数需通过解析 URL 获取,见 [4.1 常见问题](#4.1 常见问题)。


2.2 Filter(过滤器) --- 旁路拦截

基类QgsServerFilter
激活 :所有请求自动经过(不需要特定 SERVICE)
适用场景:日志、鉴权、水印、响应注入、参数预处理

复制代码
请求到达
    │
    ▼
  requestReady()        ← 可修改请求参数、做鉴权
    │
    ▼
  [QGIS Server 核心处理]
    │
    ▼
  sendResponse()        ← 可修改响应头
    │
    ▼
  responseComplete()    ← 可修改响应体(加水印、替换内容)
    │
    ▼
响应发出

三个钩子按固定顺序触发 ,每个钩子的 handler 对象提供不同能力:

python 复制代码
handler = self.serverInterface().requestHandler()
params  = handler.parameterMap()      # 读所有参数
handler.setParameter('K', 'V')        # 注入参数 (requestReady 中)
handler.setResponseHeader('K', 'V')   # 设置响应头 (sendResponse 中)
handler.setServiceException(ex)       # 抛出受控异常
handler.body()                        # 读响应体 (responseComplete 中)
handler.clearBody()                   # 清空
handler.appendBody(b'...')            # 追加
handler.clear()                       # 清空全部

优先级registerFilter(filter, priority) 的值越小越先执行。


2.3 Access Control(访问控制) --- 权限管控

基类QgsAccessControlFilter
激活 :在渲染/查询之前 自动执行
适用场景:图层级权限、字段过滤、行级数据过滤

特点:在 Service 或 WMS/WFS 处理之前运行,被限制的数据根本不会进入渲染管线,比 Filter 更安全。

可覆写的方法

python 复制代码
# 图层级权限------控制增删改查
def layerPermissions(self, layer) -> LayerPermissions:
    # canRead / canInsert / canUpdate / canDelete

# 字段级权限------控制哪些字段可见
def authorizedLayerAttributes(self, layer, attributes) -> list:
    # 返回允许的字段列表

# 行级权限------SQL 过滤表达式(可选)
def layerFilterExpression(self, layer) -> str:
    # 返回 SQL WHERE 子句

三、三个模板插件

3.1 template_service --- Service 模板

路径qgis-server/plugins/template_service/

python 复制代码
# service_impl.py(核心代码)
from qgis.server import QgsService

class TemplateService(QgsService):
    def name(self):
        return "TEMPLATE"         # 请求中 SERVICE=TEMPLATE

    def version(self):
        return "1.0.0"

    def executeRequest(self, request, response, project):
        operation = request.parameter("OPERATION") or ""
        if not operation:
            self._send_json(response, {           # 默认:返回服务描述
                "service": "TEMPLATE",
                "operations": ["ping", "echo", "info"],
            })
        elif operation == "ping":
            self._send_json(response, {"pong": True})
        elif operation == "echo":
            msg = request.parameter("msg") or ""
            self._send_json(response, {"echo": msg})
        elif operation == "info":
            # 返回项目元信息
            layers = [{"id": lid, "name": l.name()} for lid, l in project.mapLayers().items()]
            self._send_json(response, {"project": ..., "layers": layers})
        else:
            self._send_json(response, {"error": "Unknown"}, 404)

测试

bash 复制代码
curl "localhost:8050/ows/?SERVICE=TEMPLATE&MAP=/io/data/china.qgs"
# → {"service":"TEMPLATE","version":"1.0.0","operations":["ping","echo","info"],...}

curl "localhost:8050/ows/?SERVICE=TEMPLATE&OPERATION=ping&MAP=/io/data/china.qgs"
# → {"pong":true}

curl "localhost:8050/ows/?SERVICE=TEMPLATE&OPERATION=info&MAP=/io/data/china.qgs"
# → {"project":"/io/data/china.qgs","crs":"EPSG:4490","layerCount":1,...}

扩展指南 :在 executeRequest 中添加新的 elif operation == "xxx": 分支,或改为 RESTful 路由(参考 rest_map_service)。


3.2 template_filter --- Filter 模板

路径qgis-server/plugins/template_filter/

python 复制代码
# filter_impl.py(核心代码)
from qgis.server import QgsServerFilter

class TemplateFilter(QgsServerFilter):
    def requestReady(self):
        # 钩子 1:请求到达,可注入参数
        params = handler.parameterMap()
        log(f"--> {params.get('SERVICE')} / {params.get('REQUEST')}")

    def sendResponse(self):
        # 钩子 2:响应头发送前
        handler.setResponseHeader("X-Template-Filter", "v1.0")

    def responseComplete(self):
        # 钩子 3:响应生成完毕,可修改响应体
        elapsed = (time.time() - self._start) * 1000
        log(f"<-- done in {elapsed:.1f}ms")

测试

bash 复制代码
curl "localhost:8050/ows/?SERVICE=WMS&REQUEST=GetCapabilities&MAP=/io/data/china.qgs"
# 查看 QGIS Server 日志:
# docker logs qgis-server | grep TemplateFilter
# → --> WMS / GetCapabilities from /io/data/china.qgs
# → <-- WMS / GetCapabilities done in 1.9ms

扩展指南

  • 鉴权 :在 requestReady 中检查 token,不合法则 handler.setServiceException()
  • 水印 :在 responseComplete 中读 handler.body() → QPainter 画水印 → 写回
  • 参数注入 :在 requestReadyhandler.setParameter('KEY', 'VALUE')

3.3 template_access_control --- Access Control 模板

路径qgis-server/plugins/template_access_control/

python 复制代码
# access_impl.py(核心代码)
from qgis.server import QgsAccessControlFilter

class TemplateAccessControl(QgsAccessControlFilter):
    def layerPermissions(self, layer):
        perms = QgsAccessControlFilter.LayerPermissions()
        perms.canRead = True     # 允许读取
        perms.canInsert = True
        perms.canUpdate = True   # 改为 False 可禁止编辑
        perms.canDelete = True
        return perms

    def authorizedLayerAttributes(self, layer, attributes):
        # 返回允许可见的字段列表
        return attributes

    # def layerFilterExpression(self, layer):
    #     return ""   # 行级过滤 SQL

特性 :无直接 HTTP 入口------它对所有 WMS/WFS 请求静默生效。权限检查发生在渲染之前,被限制的数据不会进入渲染管线。

测试方法

bash 复制代码
# 1. 将 china_province 层的 canRead 改为 False
# 2. 请求 WMS GetMap → 该图层不会渲染
curl "localhost:8050/ows/?SERVICE=WMS&REQUEST=GetMap&MAP=/io/data/china.qgs&LAYERS=china_province&..."
# → 空白图片(图层被 Access Control 屏蔽)

扩展指南

  • 按图层控制 :在 layerPermissionsif layer.name() == "机密数据": perms.canRead = False
  • 字段脱敏 :在 authorizedLayerAttributes 中过滤敏感字段
  • 多租户隔离 :在 layerFilterExpression 中追加 WHERE tenant_id = :current_tenant

四、从模板创建新插件

4.1 快速开始

bash 复制代码
# 1. 拷贝模板
cp -r plugins/template_service plugins/my_api

# 2. 修改 metadata.txt
#    name=My API Service

# 3. 重命名实现文件(可选)
mv plugins/my_api/service_impl.py plugins/my_api/my_api.py

# 4. 修改 __init__.py 的 import 路径
#    from .my_api import MyApiService

# 5. 修改 my_api.py
#    类名、name()、executeRequest 逻辑

# 6. 重启
docker compose restart qgis-server

# 7. 测试
curl "localhost:8050/ows/?SERVICE=???&MAP=/io/data/china.qgs"

4.2 常见问题

request.parameter() 获取不到自定义参数

QGIS Server 的 request.parameter() 只返回已知的 OWS 参数(SERVICE、MAP、REQUEST 等)。自定义参数需从 URL 解析:

python 复制代码
from urllib.parse import urlparse, parse_qs

def get_all_params(request):
    url_str = request.url().toString()  # PyQt6 中 url() 返回 QUrl
    query = urlparse(url_str).query
    params = {}
    for k, vals in parse_qs(query).items():
        params[k] = vals[0]
    return params
实现文件名和包名冲突
python 复制代码
# ❌ 错误:template_service/__init__.py 中
from .template_service import Xxx   # 包名=模块名,导入歧义

# ✅ 正确:用不同文件名
from .service_impl import Xxx
PyQt6 枚举位置变化
python 复制代码
# PyQt5:
from qgis.PyQt.QtCore import QIODevice
QIODevice.WriteOnly

# PyQt6 (QGIS 4.x):
from qgis.PyQt.QtCore import QIODeviceBase
QIODeviceBase.OpenModeFlag.WriteOnly

五、三种模式对比总结

Service Filter Access Control
基类 QgsService QgsServerFilter QgsAccessControlFilter
激活时机 SERVICE= 匹配 所有请求 渲染/查询前
对请求的影响 完全接管 旁路拦截 静默过滤
能做什么 自定义 API 日志/鉴权/水印 图层/字段/行级权限
不能做什么 影响 WMS/WFS 完全取代 Service 自定义响应格式
运行时开销 仅匹配 SERVICE 时 每个请求 每次渲染/查询
模板路径 template_service/ template_filter/ template_access_control/
可混合使用

三种机制在同一请求中的执行顺序:Filter (requestReady) → Access Control → Service/WMS → Filter (sendResponse) → Filter (responseComplete)

插件示例下载

qgis-server插件示例下载

相关推荐
丷丩21 小时前
从“失忆工具“到“智能助手“:GeoAI平台的Agent架构演进
人工智能·架构·gis·空间分析·geoai
杭州泽沃电子科技有限公司4 天前
GIS从“稀少”到“激增”:局放监测再不上就晚了
gis·智能监测·局放
星座5284 天前
【无人机+GIS】智慧农林遥感核心技术:多源数据驱动的作物参数反演与制图
gis·无人机·遥感·智慧农林
zhz52145 天前
一个简单、轻量级且安全的离线GIS 系统架构设计
安全·系统架构·vue·gis·fastapi
Navicat中国5 天前
用 Navicat 来可视化 PostgreSQL GIS 数据,是否支持?
数据库·postgresql·gis·数据可视化·navicat
vjmap8 天前
唯杰地图CAD图层加高性能特效扩展包发布
前端·gis
GISBox11 天前
三大维度焕新!GISBox2.2.0新增三维重建模块与性能优化
gis·三维重建·gisbox·rvt·服务数据缓存·ktx2·win7系统
丷丩12 天前
第 2 篇:入门实操|3dtubetilecreater 环境搭建全教程(零踩坑版)
3d·gis·postgis·管线·自动建模·管网
haokan_Jia14 天前
【6、Gis数据-新疆下属流域划分及其数据】
gis·arcmap·河流