Django让web开发更简单(九):设计项目管理模块

设计一个项目管理模块

项目管理模块,用于管理创建的项目,每个项目都有自己独特性,因此,项目管理模块,相当于一个存储仓库,用于存储接口等信息。

定义日志

定义一个日志,用于所有模块的debug,在settings里设置:

# 可以在全局配置settings.py中的LOGGING,来配置日志信息
LOGGING = {
    # 版本号
    'version': 1,
    # 指定是否禁用已经存在的日志器
    'disable_existing_loggers': False,
    # 日志的显示格式
    'formatters': {
        # simple为简化版格式的日志
        'simple': {
            'format': '%(asctime)s - [%(levelname)s] - [msg]%(message)s'
        },
        # verbose为详细格式的日志
        'verbose': {
            'format': '%(asctime)s - [%(levelname)s] - %(name)s - [msg]%(message)s - [%(filename)s:%(lineno)d ]'
        },
    },
    # filters指定日志过滤器
    'filters': {
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    # handlers指定日志输出渠道
    'handlers': {
        # console指定输出到控制台
        'console': {
            'level': 'DEBUG',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        # 日志保存到日志文件
        'file': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            # 指定存放日志文件的所处路径
            'filename': os.path.join(BASE_DIR, "logs/test.log"),  # 日志文件的位置
            'maxBytes': 100 * 1024 * 1024,
            'backupCount': 10,
            'formatter': 'verbose',
            'encoding': 'utf-8'
        },
    },
    # 定义日志器
    'loggers': {
        'mytest': {  # 定义了一个名为mytest的日志器
            'handlers': ['console', 'file'],
            'propagate': True,
            'level': 'DEBUG',  # 日志器接收的最低日志级别
        },
    }
}

根据配置路径logs/test.log,在工程目录下创建存放日志的文件夹logs。

创建应用并注册

django-admin startapp projects

拖动到apps后,在INSTALLED_APPS注册。

设计模型

首先在utils文件夹里创建base_models.py,定义一个基础模型:

from django.db import models


class BaseModel(models.Model):
    create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间', help_text='创建时间')
    update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间', help_text='更新时间')

    class Meta:
        # 指定在迁移时不创建表
        abstract = True

然后在projects应用里的models.py,继承基础模型并定义一个模型:

from django.db import models
from utils.base_models import BaseModel
# Create your models here.


class Projects(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('项目名称', max_length=200, unique=True, help_text='项目名称')
    leader = models.CharField('负责人', max_length=50, help_text='项目负责人')
    tester = models.CharField('测试人员', max_length=50, help_text='项目测试人员')
    programmer = models.CharField('开发人员', max_length=50, help_text='开发人员')
    publish_app = models.CharField('发布应用', max_length=100, help_text='发布应用')
    desc = models.CharField('简要描述', max_length=200, null=True, blank=True, default='', help_text='简要描述')

    class Meta:
        db_table = 'tb_projects'
        verbose_name = '项目信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

因为涉及到一些其他逻辑,现在我们补充一下其他应用:

1、创建interfaces应用,并定义models、serializers:

# models
from django.db import models

from utils.base_models import BaseModel


class Interfaces(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('接口名称', max_length=200, unique=True, help_text='接口名称')
    project = models.ForeignKey('projects.Projects', on_delete=models.CASCADE,
                                related_name='interfaces', help_text='所属项目')
    tester = models.CharField('测试人员', max_length=50, help_text='测试人员')
    desc = models.CharField('简要描述', max_length=200, null=True, blank=True, help_text='简要描述')

    class Meta:
        db_table = 'tb_interfaces'
        verbose_name = '接口信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

# seriializers
from rest_framework import serializers

from .models import Interfaces
from projects.models import Projects
from testcases.models import Testcases
from configures.models import Configures
from utils import common
from utils import validates


class InterfacesModelSerializer(serializers.ModelSerializer):
    project = serializers.StringRelatedField(label='所属项目名称', help_text='所属项目名称')
    # project_id = serializers.PrimaryKeyRelatedField(queryset=Projects.objects.all(),
    #                                                 label='项目id', help_text='项目id',
    #                                                 write_only=True)
    project_id = serializers.PrimaryKeyRelatedField(queryset=Projects.objects.all(),
                                                    label='项目id', help_text='项目id',
                                                    )

    class Meta:
        model = Interfaces
        fields = ('id', 'name', 'tester', 'create_time', 'desc', 'project', 'project_id')

        extra_kwargs = {
            'create_time': {
                'read_only': True,
                'format': common.datetime_fmt()
            }
        }

    def create(self, validated_data):
        project = validated_data.pop('project_id')
        validated_data['project'] = project
        return super().create(validated_data)

    def update(self, instance, validated_data):
        if 'project_id' in validated_data:
            project = validated_data.pop('project_id')
            validated_data['project'] = project

        return super().update(instance, validated_data)


class TestcasesNamesModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = Testcases
        fields = ('id', 'name')


class TestcasesByInterfaceIdModelSerializer(serializers.ModelSerializer):
    testcases = TestcasesNamesModelSerializer(many=True, read_only=True)

    class Meta:
        model = Interfaces
        fields = ('testcases', )


class ConfiguresNamesModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = Configures
        fields = ('id', 'name')


class ConfiguresByInterfaceIdModelSerializer(serializers.ModelSerializer):
    configures = ConfiguresNamesModelSerializer(many=True, read_only=True)

    class Meta:
        model = Interfaces
        fields = ('configures', )


class InterfaceRunSerializer(serializers.ModelSerializer):
    """
    通过接口来运行测试用例序列化器
    """
    env_id = serializers.IntegerField(write_only=True,
                                      help_text='环境变量ID',
                                      validators=[validates.is_exised_env_id])

    class Meta:
        model = Interfaces
        fields = ('id', 'env_id')

2、创建应用testcases并设计models

from django.db import models
from utils.base_models import BaseModel


class Testcases(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('用例名称', max_length=50, unique=True, help_text='用例名称')
    interface = models.ForeignKey('interfaces.Interfaces', on_delete=models.CASCADE, related_name='testcases',
                                  help_text='所属接口')
    # include = models.ForeignKey('', on_delete=models.SET_NULL, null=True, related_name='testcases')
    include = models.TextField('前置', null=True, help_text='用例执行前置顺序')
    author = models.CharField('编写人员', max_length=50, help_text='编写人员')
    request = models.TextField('请求信息', help_text='请求信息')

    class Meta:
        db_table = 'tb_testcases'
        verbose_name = '用例信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

3、创建应用configures并设计models

from django.db import models

from utils.base_models import BaseModel


class Configures(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('配置名称', max_length=50, help_text='配置名称')
    interface = models.ForeignKey('interfaces.Interfaces',
                                  on_delete=models.CASCADE,
                                  related_name='configures',
                                  help_text='所属接口')
    author = models.CharField('编写人员', max_length=50, help_text='编写人员')
    request = models.TextField('请求信息', help_text='请求信息')

    class Meta:
        db_table = 'tb_configures'
        verbose_name = '配置信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

4、在utils添加common、validates模块

# common
from datetime import datetime

from rest_framework.response import Response
import yaml
from httprunner.task import HttpRunner
from httprunner.report import render_html_report

from debugtalks.models import DebugTalks
from configures.models import Configures
from testcases.models import Testcases
from reports.models import Reports


def datetime_fmt():
    locale.setlocale(locale.LC_CTYPE, 'chinese')
    return '%Y年%m月%d日 %H:%M:%S'


def create_report(runner, report_name=None):
    """
    创建测试报告
    :param runner:
    :param report_name:
    :return:
    """
    time_stamp = int(runner.summary["time"]["start_at"])
    start_datetime = datetime.fromtimestamp(time_stamp).strftime('%Y-%m-%d %H:%M:%S')
    runner.summary['time']['start_datetime'] = start_datetime

    # duration保留3位小数
    runner.summary['time']['duration'] = round(runner.summary['time']['duration'], 3)
    report_name = report_name if report_name else start_datetime
    runner.summary['html_report_name'] = report_name

    for item in runner.summary['details']:
        # 对时间戳进行处理
        try:
            time_stamp = int(item['time']['start_at'])
            detail['time']['start_at'] = datetime.fromtimestamp(time_stamp).strftime('%Y-%m-%d %H:%M:%S')
        except Exception:
            pass

        try:
            for record in item['records']:
                # 对时间戳进行处理
                try:
                    time_stamp = int(record['meta_data']['request']['start_timestamp'])
                    record['meta_data']['request']['start_timestamp'] = \
                        datetime.fromtimestamp(time_stamp).strftime('%Y-%m-%d %H:%M:%S')
                except Exception:
                    pass

                record['meta_data']['response']['content'] = record['meta_data']['response']['content']. \
                    decode('utf-8')
                record['meta_data']['response']['cookies'] = dict(record['meta_data']['response']['cookies'])

                request_body = record['meta_data']['request']['body']
                if isinstance(request_body, bytes):
                    record['meta_data']['request']['body'] = request_body.decode('utf-8')
        except Exception as e:
            continue

    summary = json.dumps(runner.summary, ensure_ascii=False)

    report_name = report_name + '_' + datetime.strftime(datetime.now(), '%Y%m%d%H%M%S')
    report_path = runner.gen_html_report(html_report_name=report_name)

    with open(report_path, encoding='utf-8') as stream:
        reports = stream.read()

    test_report = {
        'name': report_name,
        'result': runner.summary.get('success'),
        'success': runner.summary.get('stat').get('successes'),
        'count': runner.summary.get('stat').get('testsRun'),
        'html': reports,
        'summary': summary
    }
    report_obj = Reports.objects.create(**test_report)
    return report_obj.id


def generate_testcase_file(instance, env, testcase_dir_path):
    testcase_list = []
    config = {
        'config': {
            'name': instance.name,
            'request': {
                'base_url': env.base_url if env else ''
            }
        }
    }
    testcase_list.append(config)

    # 获取include信息
    include = json.loads(instance.include, encoding='utf-8')
    # 获取request字段
    request = json.loads(instance.request, encoding='utf-8')
    # 获取用例所属接口名称
    interface_name = instance.interface.name
    # 获取用例所属项目名称
    project_name = instance.interface.project.name

    testcase_dir_path = os.path.join(testcase_dir_path, project_name)

    if not os.path.exists(testcase_dir_path):
        os.makedirs(testcase_dir_path)
        # 生成debugtalk.py文件,放到项目根目录下
        debugtalk_obj = DebugTalks.objects.filter(project__name=project_name).first()
        debugtalk = debugtalk_obj.debugtalk if debugtalk_obj else ''
        with open(os.path.join(testcase_dir_path, 'debugtalk.py'), 'w', encoding='utf-8') as f:
            f.write(debugtalk)

    testcase_dir_path = os.path.join(testcase_dir_path, interface_name)
    if not os.path.exists(testcase_dir_path):
        os.makedirs(testcase_dir_path)

    # {"config":1,"testcases":[1,2,3]}
    if 'config' in include:
        config_id = include.get('config')
        config_obj = Configures.objects.filter(id=config_id).first()
        if config_obj:
            config_request = json.loads(config_obj.request, encoding='utf-8')
            config_request['config']['request']['base_url'] = env.base_url if env else ''
            testcase_list[0] = config_request

    # 处理前置用例
    if 'testcases' in include:
        for testcase_id in include.get('testcases'):
            testcase_obj = Testcases.objects.filter(id=testcase_id).first()
            try:
                testcase_request = json.loads(testcase_obj.request, encoding='utf-8')
            except Exception as e:
                continue

            testcase_list.append(testcase_request)

    # 把当前需要执行的用例追加到testcase_list最后
    testcase_list.append(request)
    # with open(os.path.join(testcase_dir_path, instance.name + '.yaml'), 'w', encoding='utf-8') as f:
    #     yaml.dump(testcase_list, f, all_unicode=True)

    with open(os.path.join(testcase_dir_path, instance.name + '.yaml'), 'w', encoding='utf-8') as f:
        yaml.dump(testcase_list, f, allow_unicode=True)


def run_testcase(instance, testcase_dir_path):
    # 1、运行用例
    runner = HttpRunner()
    try:
        runner.run(testcase_dir_path)
    except Exception as e:
        res = {'ret': False, 'msg': '用例执行失败'}
        return Response(res, status=400)

    # 2、创建报告
    report_id = create_report(runner, instance.name)

    # 3、用例运行成功之后,需要把生成的报告id返回
    data = {
        'id': report_id
    }
    return Response(data, status=201)

为common安装一些依赖组件:

pip install djangorestframework-yaml==2.0.0
pip install httprunner==1.5.8
# validates

from rest_framework import serializers

from projects.models import Projects
from interfaces.models import Interfaces
from envs.models import Envs


def is_exised_project_id(value):
    """
    校验项目id是否存在
    :param value:
    :return:
    """
    if not Projects.objects.filter(id=value).exists():
        raise serializers.ValidationError('项目id不存在')


def is_exised_interface_id(value):
    """
    校验接口id是否存在
    :param value:
    :return:
    """
    if not Interfaces.objects.filter(id=value).exists():
        raise serializers.ValidationError('接口id不存在')


def is_exised_env_id(value):
    """
    校验环境变量id是否存在
    :param value:
    :return:
    """
    if not Envs.objects.filter(id=value).exists():
        raise serializers.ValidationError('环境变量ID不存在')

5、创建应用debugtalks并设计models

from django.db import models

from utils.base_models import BaseModel


class DebugTalks(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('debugtalk文件名称', max_length=200, default='debugtalk.py', help_text='debugtalk文件名称')
    debugtalk = models.TextField(null=True, default='#debugtalk.py', help_text='debugtalk.py文件')
    project = models.OneToOneField('projects.Projects', on_delete=models.CASCADE,
                                   related_name='debugtalks', help_text='所属项目')

    class Meta:
        db_table = 'tb_debugtalks'
        verbose_name = 'debugtalk.py文件'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

6、创建应用reports并设计models

from django.db import models

from utils.base_models import BaseModel


class Reports(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('报告名称', max_length=200, unique=True, help_text='报告名称')
    result = models.BooleanField('执行结果', default=1, help_text='执行结果')   # 1为成功, 0为失败
    count = models.IntegerField('用例总数', help_text='总用例数')
    success = models.IntegerField('成功总数', help_text='成功总数')
    html = models.TextField('报告HTML源码', help_text='报告HTML源码', null=True, blank=True, default='')
    summary = models.TextField('报告详情', help_text='报告详情', null=True, blank=True, default='')

    class Meta:
        db_table = 'tb_reports'
        verbose_name = '测试报告'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

7、创建应用envs并设计models

from django.db import models

from utils.base_models import BaseModel


class Envs(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField(verbose_name='环境名称', max_length=200, unique=True, help_text='环境名称')
    base_url = models.URLField(verbose_name='请求base url', max_length=200, help_text='请求base url')
    desc = models.CharField(verbose_name='简要描述', max_length=200, help_text='简要描述')

    class Meta:
        db_table = 'tb_envs'
        verbose_name = '环境信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

8、创建应用testsuits并设计models

from django.db import models

from utils.base_models import BaseModel


class Testsuits(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('套件名称', max_length=200, unique=True, help_text='套件名称')
    project = models.ForeignKey('projects.Projects', on_delete=models.CASCADE,
                                related_name='testsuits', help_text='所属项目')
    # include = models.TextField(null=False)
    include = models.TextField('包含的接口', help_text='包含的接口')

    class Meta:
        db_table = 'tb_testsuits'
        verbose_name = '套件信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

执行迁移并运行

没有问题后继续。

设计接口

import json
import logging
import os
from datetime import datetime

from django_filters.rest_framework import DjangoFilterBackend
from django.db.models import Count
from django.conf import settings

# from rest_framework.filters import OrderingFilter
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework import permissions
from rest_framework.response import Response

from .models import Projects
from interfaces.models import Interfaces
from configures.models import Configures
from testsuits.models import Testsuits
from testcases.models import Testcases
from envs.models import Envs
from .serializers import ProjectsModelSerializer, ProjectsNamesModelSerializer, \
    InterfacesByProjectIdModelSerializer, ProjectsRunSerializer
from utils import common

# from utils.pagination import MyPagination
# 定义日志器用于记录日志,logging.getLogger('全局配置settings.py中定义的日志器名')
logger = logging.getLogger('mytest')


class ProjectsViewSet(viewsets.ModelViewSet):
    """
    list:
    获取项目的列表信息

    retrive:
    获取项目详情数据

    create:
    创建项目

    names:
    获取项目名称

    interfaces:
    获取某个项目下的接口名称
    """
    queryset = Projects.objects.all()
    serializer_class = ProjectsModelSerializer
    permission_classes = [permissions.IsAuthenticated]

    # 如果父类中有提供相关的逻辑
    # 1、绝大部分不需要修改,只有少量要修改的,直接对父类中的action进行拓展
    # 2、绝大部分都需要修改的话,那么直接自定义即可
    def list(self, request, *args, **kwargs):
        # print(1/0)
        response = super().list(request, *args, **kwargs)
        results = response.data['results']
        data_list = []
        for item in results:
            # item为一条项目数据所在的字典
            # 需要获取当前项目所属的接口总数、用例总数、配置总数、套件总数
            project_id = item.get('id')
            # interface_count = Interfaces.objects.filter(project_id=project_id).count()
            # interface_qs = Interfaces.objects.filter(project_id=project_id)
            # for obj in interface_qs:
            #     interface_id = obj.id
            #     TestCase.ojbects.filter(interface_id=interface_id).count()

            # a.使用.annotate()方法,那么会自动使用当前模型类的主键作为分组条件
            # b.使用.annotate()方法里可以添加聚合函数,计算的名称为一般从表模型类名小写(可以在外键字段上设置related_name)
            # c.values可以指定需要查询的字段(默认为所用字段)
            # d.可以给聚合函数指定别名,默认为testcases__count
            # e.如果values放在annotate前面,那么聚合运算的字段不需要在values中添加,放在后面需要
            # interfaces_obj = Interfaces.objects.annotate(testcases1=Count('testcases')).values('id', 'testcases1').\
            #     filter(project_id=project_id)

            interface_testcase_qs = Interfaces.objects.values('id').annotate(testcases=Count('testcases')). \
                filter(project_id=project_id)

            # 获取项目下的接口总数
            interfaces_count = interface_testcase_qs.count()

            # 定义初始用例总数为0
            testcases_count = 0
            for one_dict in interface_testcase_qs:
                testcases_count += one_dict.get('testcases')

            # 获取项目下的配置总数
            interface_configure_qs = Interfaces.objects.values('id').annotate(configures=Count('configures')). \
                filter(project_id=project_id)
            configures_count = 0
            for one_dict in interface_configure_qs:
                configures_count += one_dict.get('configures')

            # 获取项目下套件总数
            testsuites_count = Testsuits.objects.filter(project_id=project_id).count()

            item['interfaces'] = interfaces_count
            item['testcases'] = testcases_count
            item['testsuits'] = testsuites_count
            item['configures'] = configures_count
            data_list.append(item)

        response.data['results'] = data_list

        return response

    @action(methods=['get'], detail=False)
    def names(self, request, *args, **kwargs):
        # return self.list(request, *args, **kwargs)
        qs = self.get_queryset()
        serializer = self.get_serializer(qs, many=True)
        return Response(serializer.data)

    @action(detail=True)
    def interfaces(self, request, *args, **kwargs):
        # instance = self.get_object()
        # # qs = Interfaces.objects.filter(projects=instance)
        # serializer_obj = self.get_serializer(instance=instance)
        # # 进行过滤和分页操作
        # return Response(serializer_obj.data)
        # return self.retrieve(request, *args, **kwargs)
        response = self.retrieve(request, *args, **kwargs)
        response.data = response.data['interfaces']
        return response

    @action(methods=['post'], detail=True)
    def run(self, request, *args, **kwargs):
        # 取出并构造参数
        instance = self.get_object()
        response = super().create(request, *args, **kwargs)
        env_id = response.data.serializer.validated_data.get('env_id')
        testcase_dir_path = os.path.join(settings.SUITES_DIR, datetime.strftime(datetime.now(), '%Y%m%d%H%M%S%f'))
        # 创建一个以时间戳命名的路径
        os.mkdir(testcase_dir_path)
        env = Envs.objects.filter(id=env_id).first()

        interface_qs = Interfaces.objects.filter(project=instance)
        if not interface_qs.exists():
            data = {
                'ret': False,
                'msg': '此项目下无接口,无法运行'
            }
            return Response(data, status=400)

        runnable_testcase_obj = []
        for interface_obj in interface_qs:
            # 当前接口项目的用例所在查询集对象
            testcase_qs = Testcases.objects.filter(interface=interface_obj)
            if testcase_qs.exists():
                # 将两个列表合并
                runnable_testcase_obj.extend(list(testcase_qs))

        if len(runnable_testcase_obj) == 0:
            data = {
                'ret': False,
                'msg': '此项目下无用例,无法运行'
            }
            return Response(data, status=400)

        for testcase_obj in runnable_testcase_obj:
            # 生成yaml用例文件
            common.generate_testcase_file(testcase_obj, env, testcase_dir_path)

        # 运行用例(生成报告)
        # common.run_testcase(instance, testcase_dir_path)
        return common.run_testcase(instance, testcase_dir_path)

    def get_serializer_class(self):
        if self.action == 'names':
            return ProjectsNamesModelSerializer
        elif self.action == 'interfaces':
            return InterfacesByProjectIdModelSerializer
        elif self.action == 'run':
            return ProjectsRunSerializer
            # return InterfacesByProjectIdModelSerializer1
        else:
            return self.serializer_class

    def perform_create(self, serializer):
        if self.action == 'run':
            pass
        else:
            serializer.save()

需要安装django-filter==2.3.0,然后在settings.py中注册应用django_filters。

设计子路由

from django.urls import path, re_path

from rest_framework.routers import DefaultRouter, SimpleRouter

# from projects.views import
from projects import views


# 定义路由对象
# router = SimpleRouter()
# DefaultRouter相比SimpleRouter,自动添加了一条根路径的路由 /  -> 可浏览器的api页面
router = DefaultRouter()
# 使用路由对象.register()方法,来进行注册
# a.第一个参数指定路由前缀,r'子应用名小写'
# b.第二个参数指定视图集类即可,不要调用.as_view()
router.register(r'projects', views.ProjectsViewSet)

urlpatterns = []

# 使用路由对象.urls属性来获取自动生成的路由条目,往往为列表
# 需要将这个列表添加至urlpatterns
urlpatterns += router.urls

设计好之后,将子路由添加到主路由里。

运行测试

在这里插入图片描述在这里插入图片描述如上,已经提示要进行认证才能请求了。

我们进入接口文档里测试一下:http://127.0.0.1:8000/docs/

在这里插入图片描述登陆之后拿到token。

在这里插入图片描述添加token

在这里插入图片描述请求一个需要验证的接口:

在这里插入图片描述如图,通过添加token后,请求成功。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Lion King

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值