You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ansible技术问题:如何访问rescue区的refresh_token并消除代码重复?

解决Ansible中Token刷新后代码重复及Block访问Rescue变量的问题

首先修正你当前代码里的一个小错误:set_fact中引用的token_response应该是central_token_response,否则会触发未定义变量的错误。

下面是几种解决代码重复、实现token刷新后重试API请求的方案:

方案1:封装可复用的API请求任务(最推荐)

把API请求、401错误处理、token刷新的逻辑抽成单独的任务文件,所有API调用都复用这个文件,彻底消除重复代码。

步骤1:创建复用任务文件 tasks/api_request.yml

---
- block:
    - name: "{{ task_name }}"
      ansible.builtin.uri:
        url: "{{ api_url }}"
        method: "{{ api_method | default('GET') }}"
        headers:
          Authorization: Bearer {{ central_access_token }}
          Accept: application/json
        status_code: [200, 401]
      register: api_response

  rescue:
    # 只处理401(token过期)的情况,其他错误直接抛出
    - name: 非401错误直接失败
      ansible.builtin.fail:
        msg: "API请求出错,状态码: {{ api_response.status }}"
      when: api_response.status != 401

    - name: 刷新Access Token
      ansible.builtin.uri:
        method: POST
        status_code: 200
        headers:
          Accept: application/json
          Content-Type: application/x-www-form-urlencoded
        payload:
          grant_type: client_credentials
          client_id: "{{ client_id }}"
          client_secret: "{{ client_secret }}"
      register: central_token_response
    
    - name: 更新token变量
      ansible.builtin.set_fact:
        central_access_token: "{{ central_token_response.json.access_token }}"

    # 用新token重新执行API请求
    - name: 重试 "{{ task_name }}"
      ansible.builtin.uri:
        url: "{{ api_url }}"
        method: "{{ api_method | default('GET') }}"
        headers:
          Authorization: Bearer {{ central_access_token }}
          Accept: application/json
        status_code: 200
      register: api_response

步骤2:主任务中调用复用文件

---
# 先获取初始token(如果还没有的话)
- name: 获取初始Access Token
  ansible.builtin.uri:
    method: POST
    status_code: 200
    headers:
      Accept: application/json
      Content-Type: application/x-www-form-urlencoded
    payload:
      grant_type: client_credentials
      client_id: "{{ client_id }}"
      client_secret: "{{ client_secret }}"
  register: central_token_response

- name: 保存初始token
  ansible.builtin.set_fact:
    central_access_token: "{{ central_token_response.json.access_token }}"

# 调用第一个API
- name: 获取站点列表
  ansible.builtin.include_tasks: tasks/api_request.yml
  vars:
    task_name: "获取站点列表"
    api_url: "{{ central_base_url }}/network-monitoring/v1/sites-health"
  register: central_sites_response

# 调用第二个API
- name: 获取站点下设备
  ansible.builtin.include_tasks: tasks/api_request.yml
  vars:
    task_name: "获取站点下设备"
    api_url: "{{ central_base_url }}/network-monitoring/v1/aps?filter=siteId eq {{ siteId | urlencode}}"
  register: central_devices_response

- name: 调试设备信息
  ansible.builtin.debug:
    var: central_devices_response.results[0].api_response

方案2:用循环重试机制处理token过期

利用Ansible的until循环,在API请求返回401时自动刷新token并重试,适合单个API的场景:

---
# 初始获取token
- name: 获取初始Access Token
  ansible.builtin.uri:
    method: POST
    status_code: 200
    headers:
      Accept: application/json
      Content-Type: application/x-www-form-urlencoded
    payload:
      grant_type: client_credentials
      client_id: "{{ client_id }}"
      client_secret: "{{ client_secret }}"
  register: central_token_response

- name: 保存初始token
  ansible.builtin.set_fact:
    central_access_token: "{{ central_token_response.json.access_token }}"
    token_已刷新: false

- name: 获取站点列表
  ansible.builtin.uri:
    url: "{{ central_base_url }}/network-monitoring/v1/sites-health"
    headers:
      Authorization: Bearer {{ central_access_token }}
      Accept: application/json
    method: GET
    status_code: 200
  register: central_sites_response
  until: central_sites_response.status == 200
  retries: 2
  delay: 1
  rescue:
    - name: 401时刷新token
      ansible.builtin.uri:
        method: POST
        status_code: 200
        headers:
          Accept: application/json
          Content-Type: application/x-www-form-urlencoded
        payload:
          grant_type: client_credentials
          client_id: "{{ client_id }}"
          client_secret: "{{ client_secret }}"
      register: central_token_response
      when: central_sites_response.status == 401 and not token_已刷新

    - name: 更新token变量
      ansible.builtin.set_fact:
        central_access_token: "{{ central_token_response.json.access_token }}"
        token_已刷新: true
      when: central_sites_response.status == 401 and not token_已刷新

    - name: 非401错误直接失败
      ansible.builtin.fail:
        msg: "API请求出错,状态码: {{ central_sites_response.status }}"
      when: central_sites_response.status != 401

# 同理处理第二个API请求
- name: 获取站点下设备
  ansible.builtin.uri:
    url: "{{ central_base_url }}/network-monitoring/v1/aps?filter=siteId eq {{ siteId | urlencode}}"
    headers:
      Authorization: Bearer {{ central_access_token }}
      Accept: application/json
    method: GET
    status_code: 200
  register: central_devices_response
  until: central_devices_response.status == 200
  retries: 2
  delay: 1
  rescue:
    - name: 401时刷新token
      ansible.builtin.uri:
        method: POST
        status_code: 200
        headers:
          Accept: application/json
          Content-Type: application/x-www-form-urlencoded
        payload:
          grant_type: client_credentials
          client_id: "{{ client_id }}"
          client_secret: "{{ client_secret }}"
      register: central_token_response
      when: central_devices_response.status == 401 and not token_已刷新

    - name: 更新token变量
      ansible.builtin.set_fact:
        central_access_token: "{{ central_token_response.json.access_token }}"
        token_已刷新: true
      when: central_devices_response.status == 401 and not token_已刷新

    - name: 非401错误直接失败
      ansible.builtin.fail:
        msg: "API请求出错,状态码: {{ central_devices_response.status }}"
      when: central_devices_response.status != 401

- name: 调试设备信息
  ansible.builtin.debug:
    var: central_devices_response

方案3:Block-Rescue结合任务重入

把需要执行的API任务单独抽成文件,在rescue中刷新token后重新导入执行,适合批量API任务的场景:

步骤1:创建API任务文件 tasks/api_tasks.yml

---
- block:
    - name: 获取站点列表
      ansible.builtin.uri:
        url: "{{ central_base_url }}/network-monitoring/v1/sites-health"
        headers:
          Authorization: Bearer {{ central_access_token }}
          Accept: application/json
        method: GET
        status_code: [200, 401]
      register: central_sites_response

    - name: 获取站点下设备
      ansible.builtin.uri:
        url: "{{ central_base_url }}/network-monitoring/v1/aps?filter=siteId eq {{ siteId | urlencode}}"
        method: GET
        headers: 
          Authorization: Bearer {{ central_access_token }}
          Accept: application/json
        status_code: [200, 401]
      register: central_devices_response

    - name: 调试设备信息
      ansible.builtin.debug:
        var: central_devices_response

  rescue:
    - name: 已重试过则直接失败
      ansible.builtin.fail:
        msg: "API任务在token刷新后仍失败"
      when: retry_on_token_expiry

    - name: 刷新Access Token
      ansible.builtin.uri:
        method: POST
        status_code: 200
        headers:
          Accept: application/json
          Content-Type: application/x-www-form-urlencoded
        payload:
          grant_type: client_credentials
          client_id: "{{ client_id }}"
          client_secret: "{{ client_secret }}"
      register: central_token_response
    
    - name: 更新token变量
      ansible.builtin.set_fact:
        central_access_token: "{{ central_token_response.json.access_token }}"

    # 重新执行API任务,标记已重试
    - name: 用新token重试API任务
      ansible.builtin.include_tasks: tasks/api_tasks.yml
      vars:
        retry_on_token_expiry: true

步骤2:主任务中调用

---
# 初始获取token
- name: 获取初始Access Token
  ansible.builtin.uri:
    method: POST
    status_code: 200
    headers:
      Accept: application/json
      Content-Type: application/x-www-form-urlencoded
    payload:
      grant_type: client_credentials
      client_id: "{{ client_id }}"
      client_secret: "{{ client_secret }}"
  register: central_token_response

- name: 保存初始token
  ansible.builtin.set_fact:
    central_access_token: "{{ central_token_response.json.access_token }}"

# 执行API任务
- name: 执行站点及设备查询任务
  ansible.builtin.include_tasks: tasks/api_tasks.yml
  vars:
    retry_on_token_expiry: false

内容的提问来源于stack exchange,提问作者Женя Медяник

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 12:32:28