python类HTTPBadRequest()的实例源码

http_charfinder2.py 文件源码 项目:notebooks 作者: fluentpython 项目源码 文件源码 阅读 22 收藏 0 点赞 0 评论 0
def get_chars(request):
    peername = request.transport.get_extra_info('peername')
    print('Request from: {}, GET data: {!r}'.format(peername, dict(request.GET)))
    query = request.GET.get('query', '')
    if query:
        try:
            start = int(request.GET.get('start', 0))
            stop = int(request.GET.get('stop', sys.maxsize))
        except ValueError:
            raise web.HTTPBadRequest()
        stop = min(stop, start+RESULTS_PER_REQUEST)
        num_results, chars = index.find_chars(query, start, stop)
    else:
        raise web.HTTPBadRequest()
    text = ''.join(char if n % 64 else char+'\n'
            for n, char in enumerate(chars, 1))
    response_data = {'total': num_results, 'start': start, 'stop': stop}
    print('Response to query: {query!r}, start: {start}, stop: {stop}'.format(
          query=query, **response_data))
    response_data['chars'] = text
    json_obj = json.dumps(response_data)
    print('Sending {} characters'.format(len(text)))
    headers = {'Access-Control-Allow-Origin': '*'}
    return web.Response(content_type=TEXT_TYPE, headers=headers, text=json_obj)
__init__.py 文件源码 项目:py3-kkdcp 作者: kblin 项目源码 文件源码 阅读 19 收藏 0 点赞 0 评论 0
def handle_kkdcp(request):

    length = request.content_length
    if length is None:
        raise web.HTTPLengthRequired(text="Length is required.")
    if length > MAX_LENGTH:
        raise web.HTTPRequestEntityTooLarge(text="Request is too large.")

    try:
        data = await request.read()
        proxy_request = codec.decode(data)
    except codec.ParserError as e:
        raise web.HTTPBadRequest(text=str(e))

    loop = asyncio.get_event_loop()

    # TODO: Change this to look up the KDC to talk to
    try:
        krb5_response = await asyncio.wait_for(forward_kerberos(proxy_request.message, loop=loop), timeout=15, loop=loop)
    except asyncio.TimeoutError:
        raise web.HTTPServiceUnavailable(text="Timeout waiting for Kerberos server")

    return web.Response(body=codec.encode(krb5_response), content_type="application/kerberos")
integration_server.py 文件源码 项目:bravado-asyncio 作者: sjaensch 项目源码 文件源码 阅读 19 收藏 0 点赞 0 评论 0
def upload_pet_image(request):
    with open(os.path.join(os.path.dirname(__file__), 'sample.jpg'), 'rb') as f:
        data = await request.post()
        file_data = data.get('file')
        content = file_data.file.read()
        expected_content = f.read()

    if content != expected_content:
        return web.HTTPBadRequest()

    if not (
        request.match_info['petId'] == '42'
        and data.get('userId') == '12'
    ):
        return web.HTTPBadRequest()

    return web.json_response({})
integration_server.py 文件源码 项目:bravado-asyncio 作者: sjaensch 项目源码 文件源码 阅读 20 收藏 0 点赞 0 评论 0
def update_pet(request):
    body = await request.json()
    success = body == {
        'id': 42,
        'category': {
            'name': 'extracute',
        },
        'name': 'Lili',
        'photoUrls': [],
        'status': 'sold',
    }

    if success:
        return web.json_response({})

    return web.HTTPBadRequest()
web.py 文件源码 项目:fireq 作者: superdesk 项目源码 文件源码 阅读 20 收藏 0 点赞 0 评论 0
def hook(request):
    body = await request.read()
    check_signature = hmac.compare_digest(
        get_signature(body),
        request.headers.get('X-Hub-Signature', '')
    )
    if not check_signature:
        return web.HTTPBadRequest()

    body = await request.json()
    headers = dict(request.headers.items())
    del headers['X-Hub-Signature']
    ref = get_hook_ctx(headers, body, clean=True)
    if ref:
        request.app.loop.create_task(ci(ref))
    return web.json_response(ref)
views.py 文件源码 项目:morpheus 作者: tutorcruncher 项目源码 文件源码 阅读 20 收藏 0 点赞 0 评论 0
def call(self, request):
        try:
            event_data = (await request.post())['mandrill_events']
        except KeyError:
            raise HTTPBadRequest(text='"mandrill_events" not found in post data')

        sig_generated = base64.b64encode(
            hmac.new(
                self.app['webhook_auth_key'],
                msg=(self.app['mandrill_webhook_url'] + 'mandrill_events' + event_data).encode(),
                digestmod=hashlib.sha1
            ).digest()
        )
        sig_given = request.headers.get('X-Mandrill-Signature', '<missing>').encode()
        if not hmac.compare_digest(sig_generated, sig_given):
            raise HTTPForbidden(text='invalid signature')
        try:
            events = ujson.loads(event_data)
        except ValueError as e:
            raise HTTPBadRequest(text=f'invalid json data: {e}')

        await self.sender.update_mandrill_webhooks(events)
        return Response(text='message status updated\n')
middlewares.py 文件源码 项目:playlog 作者: rossnomann 项目源码 文件源码 阅读 22 收藏 0 点赞 0 评论 0
def response_middleware(app, next_handler):
    async def handler(request):
        result = await next_handler(request)
        if not isinstance(result, Response):
            accept = request.headers.get('accept', 'application/json')
            if accept in ('application/json', '*/*'):
                if isinstance(result, ErrorResponse):
                    data, status, headers = result.data, result.status, result.headers
                    if headers:
                        # Passing both Content-Type header
                        # and content_type or charset params is forbidden
                        # (json_response already passes content_type)
                        headers.pop('content-type', None)
                else:
                    data, status, headers = result, HTTP_OK, None
                result = json_response(data, status=status, headers=headers)
            else:
                logger.error('Unable to serialize response (accept=%s)', accept)
                raise HTTPBadRequest()
        return result
    return handler
test_web_functional.py 文件源码 项目:aiohttp-tokio 作者: fafhrd91 项目源码 文件源码 阅读 33 收藏 0 点赞 0 评论 0
def test_post_max_client_size(loop, test_client):

    @asyncio.coroutine
    def handler(request):
        try:
            yield from request.post()
        except ValueError:
            return web.HTTPOk()
        return web.HTTPBadRequest()

    app = web.Application(client_max_size=10)
    app.router.add_post('/', handler)
    client = yield from test_client(app)

    data = {"long_string": 1024 * 'x', 'file': io.BytesIO(b'test')}
    resp = yield from client.post('/', data=data)

    assert 200 == resp.status
test_web_functional.py 文件源码 项目:aiohttp-tokio 作者: fafhrd91 项目源码 文件源码 阅读 21 收藏 0 点赞 0 评论 0
def test_post_max_client_size_for_file(loop, test_client):

    @asyncio.coroutine
    def handler(request):
        try:
            yield from request.post()
        except ValueError:
            return web.HTTPOk()
        return web.HTTPBadRequest()

    app = web.Application(client_max_size=2)
    app.router.add_post('/', handler)
    client = yield from test_client(app)

    data = {'file': io.BytesIO(b'test')}
    resp = yield from client.post('/', data=data)

    assert 200 == resp.status
configuration.py 文件源码 项目:FogLAMP 作者: foglamp 项目源码 文件源码 阅读 22 收藏 0 点赞 0 评论 0
def get_category(request):
    """
    Args:
         request: category_name is required

    Returns:
            the configuration items in the given category.

    :Example:
            curl -X GET http://localhost:8081/category/PURGE_READ
    """
    category_name = request.match_info.get('category_name', None)

    if not category_name:
        raise web.HTTPBadRequest(reason="Category Name is required")

    # TODO: make it optimized and elegant
    cf_mgr = ConfigurationManager(connect.get_storage())
    category = await cf_mgr.get_category_all_items(category_name)

    if category is None:
        raise web.HTTPNotFound(reason="No such Category Found for {}".format(category_name))

    return web.json_response(category)
configuration.py 文件源码 项目:FogLAMP 作者: foglamp 项目源码 文件源码 阅读 29 收藏 0 点赞 0 评论 0
def get_category_item(request):
    """
    Args:
         request: category_name & config_item are required

    Returns:
            the configuration item in the given category.

    :Example:
            curl -X GET http://localhost:8081/foglamp/category/PURGE_READ/age
    """
    category_name = request.match_info.get('category_name', None)
    config_item = request.match_info.get('config_item', None)

    if not category_name or not config_item:
        raise web.HTTPBadRequest(reason="Both Category Name and Config items are required")

    # TODO: make it optimized and elegant
    cf_mgr = ConfigurationManager(connect.get_storage())
    category_item = await cf_mgr.get_category_item(category_name, config_item)

    if category_item is None:
        raise web.HTTPNotFound(reason="No Category Item Found")

    return web.json_response(category_item)
backup_restore.py 文件源码 项目:FogLAMP 作者: foglamp 项目源码 文件源码 阅读 18 收藏 0 点赞 0 评论 0
def get_backup_details(request):
    """
    Returns the details of a backup

    :Example: curl -X GET  http://localhost:8082/foglamp/backup/1
    """
    backup_id = request.match_info.get('backup_id', None)
    if not backup_id:
        raise web.HTTPBadRequest(reason='Backup id is required')
    else:
        try:
            backup_id = int(backup_id)
        except ValueError:
            raise web.HTTPBadRequest(reason='Invalid backup id')
    try:
        # TODO : Fix after actual implementation
        Backup.get_backup_details.return_value = \
            {"date": '2017-08-30 04:05:10.382', "status": "running"}
    except Backup.DoesNotExist:
        raise web.HTTPNotFound(reason='Backup with {} does not exist'.format(backup_id))

    _resp = Backup.get_backup_details(id=backup_id)
    _resp["id"] = backup_id
    return web.json_response(_resp)
backup_restore.py 文件源码 项目:FogLAMP 作者: foglamp 项目源码 文件源码 阅读 17 收藏 0 点赞 0 评论 0
def restore_backup(request):
    """
    Restore from a backup

    :Example: curl -X PUT  http://localhost:8082/foglamp/backup/1/restore
    """
    backup_id = request.match_info.get('backup_id', None)
    if not backup_id:
        raise web.HTTPBadRequest(reason='Backup id is required')
    else:
        try:
            backup_id = int(backup_id)
        except ValueError:
            raise web.HTTPBadRequest(reason='Invalid backup id')
        try:
            # TODO : Fix after actual implementation
            Backup.restore_backup.return_value = 1
        except Backup.DoesNotExist:
            raise web.HTTPNotFound(reason='Backup with {} does not exist'.format(backup_id))
        try:
            Backup.restore_backup(id=backup_id)
            return web.json_response({'message': 'Restore backup with id {} started successfully'.format(backup_id)})
        except Backup.RestoreFailed as ex:
            return web.json_response({'error': 'Restore backup with id {} failed, reason {}'.format(backup_id, ex)})
scheduler.py 文件源码 项目:FogLAMP 作者: foglamp 项目源码 文件源码 阅读 25 收藏 0 点赞 0 评论 0
def get_scheduled_process(request):
    """
    Returns a list of all the defined scheduled_processes from scheduled_processes table
    """

    scheduled_process_name = request.match_info.get('scheduled_process_name', None)

    if not scheduled_process_name:
        raise web.HTTPBadRequest(reason='No Scheduled Process Name given')

    payload = PayloadBuilder().SELECT(("name")).WHERE(["name", "=", scheduled_process_name]).payload()
    _storage = connect.get_storage()
    scheduled_process = _storage.query_tbl_with_payload('scheduled_processes', payload)

    if len(scheduled_process['rows']) == 0:
        raise web.HTTPNotFound(reason='No such Scheduled Process: {}.'.format(scheduled_process_name))

    return web.json_response(scheduled_process['rows'][0].get("name"))


#################################
# Schedules
#################################
scheduler.py 文件源码 项目:FogLAMP 作者: foglamp 项目源码 文件源码 阅读 21 收藏 0 点赞 0 评论 0
def delete_schedule(request):
    """
    Delete a schedule from schedules table

    :Example: curl -X DELETE  http://localhost:8082/foglamp/schedule/dc9bfc01-066a-4cc0-b068-9c35486db87f
    """

    try:
        schedule_id = request.match_info.get('schedule_id', None)

        if not schedule_id:
            raise web.HTTPBadRequest(reason='Schedule ID is required.')

        try:
            assert uuid.UUID(schedule_id)
        except ValueError as ex:
            raise web.HTTPNotFound(reason="Invalid Schedule ID {}".format(schedule_id))

        await server.Server.scheduler.delete_schedule(uuid.UUID(schedule_id))

        return web.json_response({'message': 'Schedule deleted successfully', 'id': schedule_id})
    except (ValueError, ScheduleNotFoundError) as ex:
        raise web.HTTPNotFound(reason=str(ex))
scheduler.py 文件源码 项目:FogLAMP 作者: foglamp 项目源码 文件源码 阅读 25 收藏 0 点赞 0 评论 0
def cancel_task(request):
    """Cancel a running task from tasks table

    :Example: curl -X GET  http://localhost:8082/foglamp/task/cancel/{task_id}
    """
    try:
        task_id = request.match_info.get('task_id', None)

        if not task_id:
            raise web.HTTPBadRequest(reason='Task ID is required.')

        try:
            assert uuid.UUID(task_id)
        except ValueError as ex:
            raise web.HTTPNotFound(reason="Invalid Task ID {}".format(task_id))

        task = await server.Server.scheduler.get_task(task_id)

        # Cancel Task
        await server.Server.scheduler.cancel_task(uuid.UUID(task_id))

        return web.json_response({'id': task_id, 'message': 'Task cancelled successfully'})
    except (ValueError, TaskNotFoundError) as ex:
        raise web.HTTPNotFound(reason=str(ex))
service_registry.py 文件源码 项目:FogLAMP 作者: foglamp 项目源码 文件源码 阅读 16 收藏 0 点赞 0 评论 0
def unregister(request):
    """ Deregister a service

    :Example: curl -X DELETE  http://localhost:8082/foglamp/service/dc9bfc01-066a-4cc0-b068-9c35486db87f
    """

    try:
        service_id = request.match_info.get('service_id', None)

        if not service_id:
            raise web.HTTPBadRequest(reason='Service id is required')

        try:
            Service.Instances.get(idx=service_id)
        except Service.DoesNotExist:
            raise web.HTTPBadRequest(reason='Service with {} does not exist'.format(service_id))

        Service.Instances.unregister(service_id)

        _resp = {'id': str(service_id), 'message': 'Service unregistered'}

        return web.json_response(_resp)
    except ValueError as ex:
        raise web.HTTPNotFound(reason=str(ex))
middleware.py 文件源码 项目:FogLAMP 作者: foglamp 项目源码 文件源码 阅读 23 收藏 0 点赞 0 评论 0
def error_middleware(app, handler):
    async def middleware_handler(request):
        if_trace = request.query.get('trace') if 'trace' in request.query and request.query.get('trace') == '1' else None

        try:
            response = await handler(request)
            if response.status == 404:
                return handle_api_exception({"code": response.status, "message": response.message}, ex.__class__.__name__, if_trace)
            return response
        except (web.HTTPNotFound, web.HTTPBadRequest) as ex:
            return handle_api_exception({"code": ex.status_code, "message": ex.reason}, ex.__class__.__name__, if_trace)
        except web.HTTPException as ex:
            raise
        # Below Exception must come last as it is the super class of all exceptions
        except Exception as ex:
            return handle_api_exception(ex, ex.__class__.__name__, if_trace)

    return middleware_handler
ajax.py 文件源码 项目:blog-server 作者: chehThss 项目源码 文件源码 阅读 23 收藏 0 点赞 0 评论 0
def ajax_handler(request: web.Request):
    action = request.match_info.get('action')
    data = await parse(request, global_handlers.keys())
    if action not in global_handlers[request.method]:
        raise web.HTTPBadRequest()
    handler = global_handlers[request.method][action]
    try:
        result = await handler(*(data, request, None)[:len(signature(handler).parameters)])
    except InvalidRequest as err:
        return web.Response(text=json.dumps({
            'status': 1,
            'data': str(err)
        }, ensure_ascii=False), status=err.status_code, content_type='application/json')
    if isinstance(result, web.StreamResponse):
        return result
    return web.Response(text=json.dumps({
        'status': 0,
        **({'data': result} if result is not None else {})
    }, ensure_ascii=False), content_type='application/json')
factories.py 文件源码 项目:mblog 作者: moling3650 项目源码 文件源码 阅读 25 收藏 0 点赞 0 评论 0
def data_factory(app, handler):
    async def parse_data(request):
        logging.info('data_factory...')
        if request.method in ('POST', 'PUT'):
            if not request.content_type:
                return web.HTTPBadRequest(text='Missing Content-Type.')
            content_type = request.content_type.lower()
            if content_type.startswith('application/json'):
                request.__data__ = await request.json()
                if not isinstance(request.__data__, dict):
                    return web.HTTPBadRequest(text='JSON body must be object.')
                logging.info('request json: %s' % request.__data__)
            elif content_type.startswith(('application/x-www-form-urlencoded', 'multipart/form-data')):
                params = await request.post()
                request.__data__ = dict(**params)
                logging.info('request form: %s' % request.__data__)
            else:
                return web.HTTPBadRequest(text='Unsupported Content-Type: %s' % content_type)
        elif request.method == 'GET':
            qs = request.query_string
            request.__data__ = {k: v[0] for k, v in parse.parse_qs(qs, True).items()}
            logging.info('request query: %s' % request.__data__)
        else:
            request.__data__ = dict()
        return await handler(request)
    return parse_data

# ??????????????????Response??
test_client.py 文件源码 项目:aiosparql 作者: aio-libs 项目源码 文件源码 阅读 20 收藏 0 点赞 0 评论 0
def sparql_endpoint(request):
    result = {
        "post": dict((await request.post()).items()),
        "path": request.path,
    }
    if "failure" in result['post'].get('query', ""):
        raise web.HTTPBadRequest()
    if "failure" in result['post'].get('update', ""):
        raise web.HTTPBadRequest()
    return web.Response(text=json.dumps(result),
                        content_type="application/json")
factorys.py 文件源码 项目:FBlog-python3-webapp 作者: fuyangzhen 项目源码 文件源码 阅读 20 收藏 0 点赞 0 评论 0
def data_factory(app, handler):
    async def parse_data(request):
        if request.method == 'POST':
            if not request.content_type:
                return web.HTTPBadRequest(text='Missing Content-type.')
            content_type = request.content_type.lower()
            if content_type.startswith('application/json'):
                request.__data__ = await request.json()
                if not isinstance(request.__data__, dict):
                    return web.HTTPBadRequest(text='JSON body must be object.')
                logging.info('request json: %s' % str(request.__data__))
            elif request.content_type.startswith('application/x-www-form-urlencoded'):
                params = await request.post()
                request.__data__ = dict(**params)
                logging.info('request form: %s' % str(request.__data__))
            else:
                return web.HTTPBadRequest(text='Unsupported Content_Type: %s' % content_type)
        elif request.method == 'GET':
            qs = request.query_string
            request.__data__ = {k: v[0] for k, v in parse.parse_qs(qs, True).items()}
            logging.info('request query: %s' % request.__data__)
        else:
            request.__data__ = dict()
        return (await handler(request))

    return parse_data


# ??????????????????Response??
views.py 文件源码 项目:aiohttp_admin 作者: aio-libs 项目源码 文件源码 阅读 16 收藏 0 点赞 0 评论 0
def vote(self, request):
        question_id = int(request.match_info['question_id'])
        data = await request.post()
        try:
            choice_id = int(data['choice'])
        except (KeyError, TypeError, ValueError) as e:
            raise web.HTTPBadRequest(
                text='You have not specified choice value') from e
        try:
            await db.vote(self.postgres, question_id, choice_id)
        except db.RecordNotFound as e:
            raise web.HTTPNotFound(text=str(e))
        router = request.app.router
        url = router['results'].url(parts={'question_id': question_id})
        return web.HTTPFound(location=url)
strong_parameters.py 文件源码 项目:aioweb 作者: kreopt 项目源码 文件源码 阅读 19 收藏 0 点赞 0 评论 0
def require(self, *args):
        data = self.permit(*args)
        for arg in args:
            if type(arg) == str:
                if arg not in data:
                    raise web.HTTPBadRequest()
            elif type(arg) == Or:
                found = False
                for item in arg:
                    if item in data:
                        found = True
                        break
                if not found:
                    raise web.HTTPBadRequest()
        return data
strong_parameters.py 文件源码 项目:aioweb 作者: kreopt 项目源码 文件源码 阅读 17 收藏 0 点赞 0 评论 0
def typesafe(self, args):
        ret = StrongParameters()
        for arg, required_type in args.items():
            converted = convert_type(self.get(arg), required_type)
            if not converted.valid:
                raise web.HTTPBadRequest()
            ret[arg] = converted.value

        return ret
integration_server.py 文件源码 项目:bravado-asyncio 作者: sjaensch 项目源码 文件源码 阅读 19 收藏 0 点赞 0 评论 0
def login(request):
    if not (
        request.query.get('username') == 'asyncio'
        and request.query.get('password') == 'password'
        and request.query.get('invalidate_sessions') == 'True'
    ):
        return web.HTTPBadRequest()

    return web.json_response('success', headers={
        'X-Rate-Limit': '4711',
        'X-Expires-After': 'Expiration date',
    })
zenhttp_aiohttp.py 文件源码 项目:zenchmarks 作者: squeaky-pl 项目源码 文件源码 阅读 19 收藏 0 点赞 0 评论 0
def simple(request):
    try:
        letter = request.url.query['q']
    except KeyError:
        raise web.HTTPBadRequest()

    try:
        zenline = zenlines[letter]
    except KeyError:
        raise web.HTTPNotFound()

    return web.Response(text=zenline)
views.py 文件源码 项目:morpheus 作者: tutorcruncher 项目源码 文件源码 阅读 22 收藏 0 点赞 0 评论 0
def _strftime(self, ts):
        dt_tz = self.request.query.get('dttz') or 'utc'
        try:
            dt_tz = pytz.timezone(dt_tz)
        except pytz.UnknownTimeZoneError:
            raise HTTPBadRequest(text=f'unknown timezone: "{dt_tz}"')

        dt_fmt = self.request.query.get('dtfmt') or '%a %Y-%m-%d %H:%M'
        return from_unix_ms(ts, 0).astimezone(dt_tz).strftime(dt_fmt)
configuration.py 文件源码 项目:FogLAMP 作者: foglamp 项目源码 文件源码 阅读 65 收藏 0 点赞 0 评论 0
def set_configuration_item(request):
    """
    Args:
         request: category_name, config_item, {"value" : <some value>} are required

    Returns:
            set the configuration item value in the given category.

    :Example:
        curl -X PUT -H "Content-Type: application/json" -d '{"value": <some value> }' http://localhost:8081/foglamp/category/{category_name}/{config_item}

        For {category_name}=>PURGE update value for {config_item}=>age
        curl -X PUT -H "Content-Type: application/json" -d '{"value": 24}' http://localhost:8081/foglamp/category/PURGE/age

    """
    category_name = request.match_info.get('category_name', None)
    config_item = request.match_info.get('config_item', None)

    data = await request.json()
    # TODO: make it optimized and elegant
    cf_mgr = ConfigurationManager(connect.get_storage())

    try:
        value = data['value']
        await cf_mgr.set_category_item_value_entry(category_name, config_item, value)
        result = await cf_mgr.get_category_item(category_name, config_item)

        if result is None:
            raise web.HTTPNotFound(reason="No detail found for the category_name: {} and config_item: {}".format(category_name, config_item))

    except KeyError:
        raise web.HTTPBadRequest(reason='Missing required value for {}'.format(config_item))

    return web.json_response(result)
configuration.py 文件源码 项目:FogLAMP 作者: foglamp 项目源码 文件源码 阅读 38 收藏 0 点赞 0 评论 0
def delete_configuration_item_value(request):
    """
    Args:
        request: category_name, config_item are required

    Returns:
        set the configuration item value to empty string in the given category

    :Example:
        curl -X DELETE http://localhost:8081/foglamp/category/{category_name}/{config_item}/value

        For {category_name}=>PURGE delete value for {config_item}=>age
        curl -X DELETE http://localhost:8081/foglamp/category/PURGE/age/value

    """
    category_name = request.match_info.get('category_name', None)
    config_item = request.match_info.get('config_item', None)

    if not category_name or not config_item:
        raise web.HTTPBadRequest(reason="Both Category Name and Config items are required")

    # TODO: make it optimized and elegant
    cf_mgr = ConfigurationManager(connect.get_storage())
    await cf_mgr.set_category_item_value_entry(category_name, config_item, '')
    result = await cf_mgr.get_category_item(category_name, config_item)

    if result is None:
        raise web.HTTPNotFound(reason="No detail found for the category_name: {} and config_item: {}".format(category_name, config_item))

    return web.json_response(result)


问题


面经


文章

微信
公众号

扫码关注公众号