花了两个星期,我终于把 WSGI 整明白了
在 三百六十行,行行转 IT 的现状下,很多来自各行各业的同学,都选择 Python 这门胶水语言做为踏入互联网大门的第一块敲门砖,在这些人里,又有相当大比例的同学选择了 Web 开发这个方向(包括我)。而从事 web 开发,绕不过一个知识点,就是 WSGI。
不管你是否是这些如上同学中的一员,都应该好好地学习一下这个知识点。
由于我本人不从事专业的 python web 开发,所以在写这篇文章的时候,借鉴了许多优秀的网络博客,并花了很多的精力阅读了大量的 OpenStack 代码。
为了写这篇文章,零零散散地花了大概两个星期。本来可以拆成多篇文章,写成一个系列的,经过一番思虑,还是准备一篇讲完,这就是本篇文章这么长的原因。
另外,一篇文章是不能吃透一个知识点的,本篇涉及的背景知识也比较多的,若我有讲得不到位的,还请你多多查阅其他人的网络博客进一步学习。
在你往下看之前,我先问你几个问题,你带着这些问题往下看,可能更有目的性,学习可能更有效果。
问1:一个 HTTP 请求到达对应的 application处理函数要经过怎样的过程?
问2:如何不通过流行的 web 框架来写一个简单的web服务?
一个HTTP请求的过程可以分为两个阶段,第一阶段是从客户端到WSGI Server,第二阶段是从WSGI Server 到WSGI Application
今天主要是讲第二阶段,主要内容有以下几点:
- WSGI 是什么,因何而生?
- 为什么需要有 WSGI?(补充)
- HTTP请求是如何到应用程序的?
- 实现一个简单的 WSGI Server
- 实现“高并发”的WSGI Server
- 第一次路由:PasteDeploy
- PasteDeploy 使用说明
- webob.dec.wsgify 装饰器
- 第二次路由:中间件 routes 路由
01. WSGI 是什么,因何而生?
WSGI是 Web Server Gateway Interface 的缩写。
它是 Python应用程序(application)或框架(如 Django)和 Web服务器之间的一种接口,已经被广泛接受。
它是一种协议,一种规范,其是在 PEP 333提出的,并在 PEP 3333 进行补充(主要是为了支持 Python3.x)。这个协议旨在解决众多 web 框架和web server软件的兼容问题。有了WSGI,你不用再因为你使用的web 框架而去选择特定的 web server软件。
常见的web应用框架有:Django,Flask等
常用的web服务器软件有:uWSGI,Gunicorn等
那这个 WSGI 协议内容是什么呢?知乎上有人将 PEP 3333 翻译成中文,写得非常好,我将这段协议的内容搬运过来。
WSGI 接口有服务端和应用端两部分,服务端也可以叫网关端,应用端也叫框架端。服务端调用一个由应用端提供的可调用对象。如何提供这个对象,由服务端决定。例如某些服务器或者网关需要应用的部署者写一段脚本,以创建服务器或者网关的实例,并且为这个实例提供一个应用实例。另一些服务器或者网关则可能使用配置文件或其他方法以指定应用实例应该从哪里导入或获取。
WSGI 对于 application 对象有如下三点要求
- 必须是一个可调用的对象
- 接收两个必选参数environ、start_response。
- 返回值必须是可迭代对象,用来表示http body。
02. 为什么要有WSGI?
这是来自评论区的一个问题,我觉得问得很好,所以来答一下,更新在这里。
请教下用wsgi协议的地方为何不直接用http?为什么要翻译一次?
以下是我的回答,个人理解,仅供交流。
web框架(即app)在生产中一般不用于直接接收http请求。
你可能会说,django不就可以直接接收http请求吗,也不需要uwsgi之类的所谓的服务器。
其实不是,django只是在其内部自己实现了一个简易的web服务器,以供开发调试之用。所以初学者往往会误以为,web app框架本身就可以接收http请求。
web 服务器 和 web 框架,分工不同,职责不同(web 服务器专注于接收并解析请求以调用的方式将请求的内容传web框架),缺一不可,可以说它们是两个组件,共同协作才能实现web网页的访问,既然是两个组件,那总要定义一些约定俗成的通讯协议,而这就是WSGI,所以必须有WSGI。
那接下来,就引出另一个问题了:如果它们不分开,而将二者整合在一起,对外只有一个组件,是不是就没有WSGI什么事了?
答案,是的。
但是你也可以发现目前市场上有相当多的大大小小的web开发框架,如果每个框架都去自己实现web服务器,那岂不是重复造轮子?
最好的情况应该是,由专业的团队去开发专业的web服务器,而开发出来的web服务器需要具备框架通用性,Django可以用,Flask也可以用,开发者也可以自由选择用哪个web 服务器软件,用哪个web 框架,灵活组合。
03. HTTP请求是如何到应用程序的?
当客户端发出一个 HTTP 请求后,是如何转到我们的应用程序处理并返回的呢?
关于这个过程,细节的点这里没法细讲,只能讲个大概。
我根据其架构组成的不同将这个过程的实现分为两种:
1、两级结构 在这种结构里,uWSGI作为服务器,它用到了HTTP协议以及wsgi协议,flask应用作为application,实现了wsgi协议。当有客户端发来请求,uWSGI接受请求,调用flask app得到相应,之后相应给客户端。 这里说一点,通常来说,Flask等web框架会自己附带一个wsgi服务器(这就是flask应用可以直接启动的原因),但是这只是在开发阶段用到的,在生产环境是不够用的,所以用到了uwsgi这个性能高的wsgi服务器。
2、三级结构 这种结构里,uWSGI作为中间件,它用到了uwsgi协议(与nginx通信),wsgi协议(调用Flask app)。当有客户端发来请求,nginx先做处理(静态资源是nginx的强项),无法处理的请求(uWSGI),最后的相应也是nginx回复给客户端的。 多了一层反向代理有什么好处?
提高web server性能(uWSGI处理静态资源不如nginx;nginx会在收到一个完整的http请求后再转发给wWSGI)
nginx可以做负载均衡(前提是有多个服务器),保护了实际的web服务器(客户端是和nginx交互而不是uWSGI)
04. 实现一个简单的 WSGI Server
在上面的架构图里,不知道你发现没有,有个库叫做 wsgiref
,它是 Python 自带的一个 wsgi 服务器模块。
从其名字上就看出,它是用纯Python编写的WSGI服务器的参考实现。所谓“参考实现”是指该实现完全符合WSGI标准,但是不考虑任何运行效率,仅供开发和测试使用。
有了 wsgiref 这个模块,你就可以很快速的启动一个wsgi server。
from wsgiref.simple_server import make_server# 这里的 appclass 暂且不说,后面会讲到
app = appclass()
server = make_server('', 64570, app)
server.serve_forever()
当你运行这段代码后,就会开启一个 wsgi server,监听 0.0.0.0:64570
,并接收请求。
使用 lsof 命令可以查到确实开启了这个端口
以上使用 wsgiref 写了一个demo,让你对wsgi有个初步的了解。其由于只适合在学习测试使用,在生产环境中应该另寻他道。
05. 实现“高并发”的 WSGI Server
上面我们说不能在生产中使用 wsgiref ,那在生产中应该使用什么呢?选择有挺多的,比如优秀的 uWSGI,Gunicorn等。但是今天我并不准备讲这些,一是因为我不怎么熟悉,二是因为我本人从事 OpenStack 的二次开发,对它比较熟悉。
所以下面,是我花了几天时间阅读 OpenStack 中的 Nova 组件代码的实现,刚好可以拿过来学习记录一下,若有理解偏差,还望你批评指出。
在 nova 组件里有不少服务,比如 nova-api,nova-compute,nova-conductor,nova-scheduler 等等。
其中,只有 nova-api 有对外开启 http 接口。
要了解这个http 接口是如何实现的,从服务启动入口开始看代码,肯定能找到一些线索。
从 Service 文件可以得知 nova-api 的入口是 nova.cmd.api:main()
打开nova.cmd.api:main()
,一起看看是 OpenStack Nova 的代码。
在如下的黄框里,可以看到在这里使用了service.WSGIService 启动了一个 server,就是我们所说的的 wsgi server
那这里的 WSGI Server 是依靠什么实现的呢?让我们继续深入源代码。
wsgi.py 可以看到这里使用了 eventlet 这个网络并发框架,它先开启了一个绿色线程池,从配置里可以看到这个服务器可以接收的请求并发量是 1000 。
可是我们还没有看到 WSGI Server 的身影,上面使用eventlet 开启了线程池,那线程池里的每个线程应该都是一个服务器吧?它是如何接收请求的?
再继续往下,可以发现,每个线程都是使用 eventlet.wsgi.server 开启的 WSGI Server,还是使用的 eventlet。
由于源代码比较多,我提取了主要的代码,精简如下
# 创建绿色线程池
self._pool = eventlet.GreenPool(self.pool_size)# 创建 socket:监听的ip,端口
bind_addr = (host, port)
self._socket = eventlet.listen(bind_addr, family, backlog=backlog)
dup_socket = self._socket.dup()# 整理孵化协程所需的各项参数
wsgi_kwargs = {'func': eventlet.wsgi.server,'sock': dup_socket,'site': self.app, # 这个就是 wsgi 的 application 函数'protocol': self._protocol,'custom_pool': self._pool,'log': self._logger,'log_format': CONF.wsgi.wsgi_log_format,'debug': False,'keepalive': CONF.wsgi.keep_alive,'socket_timeout': self.client_socket_timeout
}# 孵化协程
self._server = utils.spawn(**wsgi_kwargs)
就这样,nova 开启了一个可以接受1000个绿色协程并发的 WSGI Server。
06. 第一次路由:PasteDeploy
上面我们提到 WSGI Server 的创建要传入一个 Application,用来处理接收到的请求,对于一个有多个 app 的项目。
比如,你有一个个人网站提供了如下几个模块
/blog # 博客 app
/wiki # wiki app
如何根据 请求的url 地址,将请求转发到对应的application上呢?
答案是,使用 PasteDeploy 这个库(在 OpenStack 中各组件被广泛使用)。
PasteDeploy 到底是做什么的呢?
根据说明,翻译如下
PasteDeploy 是用来寻找和配置WSGI应用和服务的系统。PasteDeploy给开发者提供了一个简单的函数loadapp。通过这个函数,可以从一个配置文件或者Python egg中加载一个WSGI应用。
使用PasteDeploy的其中一个重要意义在于,系统管理员可以安装和管理WSGI应用,而无需掌握与Python和WSGI相关知识。
由于 PasteDeploy 原来是属于 Paste 的,现在独立出来了,但是安装的时候还是会安装到paste目录(site-packages\paste\deploy)下。
我会先讲下在 Nova 中,是如何借助 PasteDeploy 实现对url的路由转发。
还记得在上面创建WSGI Server的时候,传入了一个 self.app 参数,这个app并不是一个固定的app,而是使用 PasteDeploy 中提供的 loadapp 函数从 paste.ini 配置文件中加载application。
具体可以,看下nova的实现。
通过打印的 DEBUG 内容得知 config_url 和 app name 的值
app: osapi_compute
config_url: /etc/nova/api-paste.inia
通过查看 /etc/nova/api-paste.ini
,在 composite 段里找到了 osapi_compute
这个app(这里的app和wsgi app 是两个概念,需要注意区分) ,可以看出 nova 目前有两个版本的api,一个是 v2,一个是v2.1,目前我们在用的是 v2.1,从配置文件中,可以得到手机靓号买号平台指定的 application 的路径是nova.api.openstack.compute
这个模块下的 APIRouterV21 类 的factory方法,这是一个工厂函数,返回 APIRouterV21 实例。
[composite:osapi_compute]
use = call:nova.api.openstack.urlmap:urlmap_factory
/: oscomputeversions
/v2: openstack_compute_api_v21_legacy_v2_compatible
/v2.1: openstack_compute_api_v21[app:osapi_compute_app_v21]
paste.app_factory = nova.api.openstack.compute:APIRouterV21.factory
这是 OpenStack 使用 PasteDeploy 实现的第一层的路由,如果你不感兴趣,可以直接略过本节,进入下一节,下一节是 介绍 PasteDeploy 的使用,教你实现一个简易的web server demo。推荐一定要看。
07. PasteDeploy 使用说明
到上一步,我已经得到了 application 的有用的线索。考虑到很多人是第一次接触 PasteDeploy,所以这里结合网上博客做了下总结。对你入门会有帮助。
掌握 PasteDeploy ,你只要按照以下三个步骤逐个完成即可。
1、配置 PasteDeploy使用的ini文件;
2、定义WSGI应用;
3、通过loadapp函数加载WSGI应用;
第一步:写 paste.ini 文件
在写之前,咱得知道 ini 文件的格式吧。
首先,像下面这样一个段叫做 section
。
[type:name]
key = value
...
其上的type,主要有如下几种
composite
(组合):多个app的路由分发;
ini [composite:main] use = egg:Paste#urlmap / = home /blog = blog /wiki = wiki
- app(应用):指明 WSGI 应用的路径;
ini [app:home] paste.app_factory = example:Home.factory
- pipeline(管道):给一个 app 绑定多个过滤器。将多个filter和最后一个WSGI应用串联起来。
```ini [pipeline:main] pipeline = filter1 filter2 filter3 myapp
[filter:filter1] ...
[filter:filter2] ...
[app:myapp] ... ```
- filter(过滤器):以 app 做为唯一参数的函数,并返回一个“过滤”后的app。通过键值next可以指定需要将请求传递给谁。next指定的可以是一个普通的WSGI应用,也可以是另一个过滤器。虽然名称上是过滤器,但是功能上不局限于过滤功能,可以是其它功能,例如日志功能,即将认为重要的请求数据记录下来。
```ini [app-filter:filter_name] use = egg:... next = next_app
[app:next_app] ... ```
对 ini 文件有了一定的了解后,就可以看懂下面这个 ini 配置文件了
[composite:main]
use = egg:Paste#urlmap
/blog = blog
/wiki = wiki[app:blog]
paste.app_factory = example:Blog.factory[app:wiki]
paste.app_factory = example:Wiki.factory
第二步是定义一个符合 WSGI 规范的 applicaiton 对象。
符合 WSGI 规范的 application 对象,可以有多种形式,函数,方法,类,实例对象。这里仅以实例对象为例(需要实现 __call__
方法),做一个演示。
import os
from paste import deploy
from wsgiref.simple_server import make_serverclass Blog(object):def __init__(self):print("Init Blog.")def __call__(self, environ, start_response):status_code = "200 OK"response_headers = [("Content-Type", "text/plain")]response_body = "This is Blog's response body.".encode('utf-8')start_response(status_code, response_headers)return [response_body]@classmethoddef factory(cls, global_conf, **kwargs):print("Blog factory.")return Blog()
最后,第三步是使用 loadapp 函数加载 WSGI 应用。
loadapp 是 PasteDeploy 提供的一个函数,使用它可以很方便地从第一步的ini配置文件里加载 app
loadapp 函数可以接收两个实参:
- URI:"config:<配置文件的全路径>"
- name:WSGI应用的名称
conf_path = os.path.abspath('paste.ini')# 加载 app
applications = deploy.loadapp("config:{}".format(conf_path) , "main")# 启动 server, 监听 localhost:22800
server = make_server("localhost", "22800", applications)
server.serve_forever()
applications 是URLMap 对象。
完善并整合第二步和第三步的内容,写成一个 Python 文件(wsgi_server.py)。内容如下
import os
from paste import deploy
from wsgiref.simple_server import make_serverclass Blog(object):def __init__(self):print("Init Blog.")def __call__(self, environ, start_response):status_code = "200 OK"response_headers = [("Content-Type", "text/plain")]response_body = "This is Blog's response body.".encode('utf-8')start_response(status_code, response_headers)return [response_body]@classmethoddef factory(cls, global_conf, **kwargs):print("Blog factory.")return Blog()class Wiki(object):def __init__(self):print("Init Wiki.")def __call__(self, environ, start_response):status_code = "200 OK"response_headers = [("Content-Type", "text/plain")]response_body = "This is Wiki's response body.".encode('utf-8')start_response(status_code, response_headers)return [response_body]@classmethoddef factory(cls, global_conf, **kwargs):print("Wiki factory.")return Wiki()if __name__ == "__main__":app = "main"port = 22800conf_path = os.path.abspath('paste.ini')# 加载 appapplications = deploy.loadapp("config:{}".format(conf_path) , app)server = make_server("localhost", port, applications)print('Started web server at port {}'.format(port))server.serve_forever()
一切都准备好后,在终端执行 python wsgi_server.py
来启动 web server
08. webob.dec.wsgify 装饰器
经过了 PasteDeploy 的路由调度,我们找到了 nova.api.openstack.compute:APIRouterV21.factory
这个 application 的入口,看代码知道它其实返回了 APIRouterV21 类的一个实例。
WSGI规定 application 必须是一个 callable 的对象,函数、方法、类、实例,若是一个类实例,就要求这个实例所属的类实现 __call__
的方法。
APIRouterV21 本身没有实现 __call__
,但它的父类 Router实现了 __call__
我们知道,application 必须遵丛 WSGI 的规范
- 必须接收
environ
,start_response
两个参数; - 必须返回 「可迭代的对象」。
但从 Router 的 __call__
代码来看,它并没有遵从这个规范,它不接收这两个参数,也不返回 response,而只是返回另一个 callable 的对象,就这样我们的视线被一次又一次的转移,但没有关系,这些__call__
都是外衣,只要扒掉这些外衣,我们就能看到核心app。
而负责扒掉这层外衣的,就是其头上的装饰器 @webob.dec.wsgify
,wsgify 是一个类,其 __call__
源码实现如下:
可以看出,wsgify 在这里,会将 req 这个原始请求(dict对象)封装成 Request 对象(就是规范1里提到的 environ)。然后会一层一层地往里地执行被wsgify装饰的函数(self._route), 得到最内部的核心application。
上面提到了规范1里的第一个参数,补充下第二个参数start_response,它是在哪定义并传入的呢?
其实这个无需我们操心,它是由 wsgi server 提供的,如果我们使用的是 wsgiref 库做为 server 的话。那这时的 start_response 就由 wsgiref 提供。
再回到 wsgify,它的作用主要是对 WSGI app 进行封装,简化wsgi app的定义与编写,它可以很方便的将一个 callable 的函数或对象,封装成一个 WSGI app。
上面,其实留下了一个问题,self._route(routes 中间件 RoutesMiddleware对象)是如何找到真正的 application呢?
带着这个问题,我们了解下 routes 是如何为我们实现第二次路由。
09. 第二次路由:中间件 routes 路由
在文章最开始处,我们给大家画了一张图。
这张图把一个 HTTP 请求粗略简单地划分为两个过程。但事实上,整个过程远比这个过程要复杂得多。
实际上在 WSGI Server 到 WSGI Application 这个过程中,我们加很多的功能(比如鉴权、URL路由),而这些功能的实现方式,我们称之为中间件。
中间件,对服务器而言,它是一个应用程序,是一个可调用对象, 有两个参数,返回一个可调用对象。而对应用程序而言,它是一个服务器,为应用程序提供了参数,并且调用了应用程序。
今天以URL路由为例,来讲讲中间件在实际生产中是如何起作用的。
当服务器拿到了客户端请求的URL,不同的URL需要交由不同的函数处理,这个功能叫做 URL Routing。
在 Nova 中是用 routes 这个库来实现对URL的的路由调度。接下来,我将从源代码处分析一下这个过程。
在routes模块里有个中间件,叫 routes.middleware.RoutesMiddleware
,它将接受到的 url,自动调用 map.match()
方法,对 url 进行路由匹配,并将匹配的结果存入request请求的环境变量['wsgiorg.routing_args']
,最后会调用self._dispatch
(dispatch返回真正的application)返回response,最后会将这个response返回给 WSGI Server。
这个中间件的原理,看起来是挺简单的。并没有很复杂的逻辑。
但是,我在阅读 routes 代码的时候,却发现了另一个令我困惑的点。
self._dispatch
(也就上图中的self.app)函数里,我们看到了 app,controller 这几个很重要的字眼,其是否是我苦苦追寻的 application 对象呢?
要搞明白这个问题,只要看清 match 到是什么东西?
这个 match 对象 是在 RoutesMiddleware.__call__()
里塞进 req.environ
的,它是什么东西呢,我将其打印出来。
{'action': u'detail', 'controller': <nova.api.openstack.wsgi.ResourceV21 object at 0x667bad0>, 'project_id': u'2ac17c7c792d45eaa764c30bac37fad9'}{'action': u'index', 'controller': <nova.api.openstack.wsgi.ResourceV21 object at 0x6ec8910>, 'project_id': u'2ac17c7c792d45eaa764c30bac37fad9'}{'action': u'show', 'controller': <nova.api.openstack.wsgi.ResourceV21 object at 0x6ed9710>, 'project_id': u'2ac17c7c792d45eaa764c30bac37fad9', 'id': u'68323d9c-ebe5-499a-92e9-32fea900a892'}
结果令人在失所望呀,这个 app 并不是我们要寻找的 Controller 对象。而是 nova.api.openstack.wsgi.ResourceV21 类的实例对象,说白了就是Resource 对象。
看到这里,我有心态有点要崩了,怎么还没到 Controller?OpenStack 框架的代码绕来绕去的,没有点耐心还真的很难读下去。
既然已经开了头,没办法还得硬着头皮继续读了下去。
终于我发现,在APIRouter初始化的时候,它会去注册所有的 Resource,同时将这些 Resource 交由 routes.Mapper 来管理、创建路由映射,所以上面提到的 routes.middleware.RoutesMiddleware 才能根据url通过 mapper.match 获取到相应的Resource。
从 Nova 代码中看出每个Resource 对应一个 Controller 对象,因为 Controller 对象本身就是对一种资源的操作集合。
通过日志的打印,可以发现 nova 管理的 Resource 对象有多么的多而杂
os-server-groups
os-keypairs
os-availability-zone
remote-consoles
os-simple-tenant-usage
os-instance-actions
os-migrations
os-hypervisors
diagnostics
os-agents
images
os-fixed-ips
os-networks
os-security-groups
os-security-groups
os-security-group-rules
flavors
os-floating-ips-bulk
os-console-auth-tokens
os-baremetal-nodes
os-cloudpipe
os-server-external-events
os-instance_usage_audit_log
os-floating-ips
os-security-group-default-rules
os-tenant-networks
os-certificates
os-quota-class-sets
os-floating-ip-pools
os-floating-ip-dns
entries
os-aggregates
os-fping
os-server-password
os-flavor-access
consoles
os-extra_specs
os-interface
os-services
servers
extensions
metadata
metadata
limits
ips
os-cells
versions
tags
migrations
os-hosts
os-virtual-interfaces
os-assisted-volume-snapshots
os-quota-sets
os-volumes
os-volumes_boot
os-volume_attachments
os-snapshots
os-server-groups
os-keypairs
os-availability-zone
remote-consoles
os-simple-tenant-usage
os-instance-actions
os-migrations
os-hypervisors
diagnostics
os-agents
images
os-fixed-ips
os-networks
os-security-groups
os-security-groups
os-security-group-rules
flavors
os-floating-ips-bulk
os-console-auth-tokens
os-baremetal-nodes
os-cloudpipe
os-server-external-events
os-instance_usage_audit_log
os-floating-ips
os-security-group-default-rules
os-tenant-networks
os-certificates
os-quota-class-sets
os-floating-ip-pools
os-floating-ip-dns
entries
os-aggregates
os-fping
os-server-password
os-flavor-access
consoles
os-extra_specs
os-interface
os-services
servers
extensions
metadata
metadata
limits
ips
os-cells
versions
tags
migrations
os-hosts
os-virtual-interfaces
os-assisted-volume-snapshots
os-quota-sets
os-volumes
os-volumes_boot
os-volume_attachments
os-snapshots
你一定很好奇,这路由是如何创建的吧,关键代码就是如下一行。
routes.mapper.connect("server","/{project_id}/servers/list_vm_state",controller=self.resources['servers'],action='list_vm_state',conditions={'list_vm_state': 'GET'})
历尽了千辛万苦,我终于找到了 Controller 对象,知道了请求发出后,wsgi server是如何根据url找到对应的Controller(根据routes.Mapper路由映射)。
但是很快,你又会问。对于一个资源的操作(action),有很多,比如新增,删除,更新等
不同的操作要执行Controller 里不同的函数。
如果是新增资源,就调用 create()
如果是删除资源,就调用 delete()
如果是更新资源,就调用 update()
那代码如何怎样知道要执行哪个函数呢?
以/servers/xxx/action请求为例,请求调用的函数实际包含在请求的body中。
经过routes.middleware.RoutesMiddleware的__call__
函数解析后,此时即将调用的Resource已经确定为哪个模块中的Controller所构建的Resource,而 action 参数为"action",接下来在Resource的__call__
函数里面会因为action=="action"从而开始解析body的内容,找出Controller中所对应的方法。
Controller在构建的过程中会由于MetaClass的影响将其所有action类型的方法填入一个字典中,key由每个_action_xxx
方法前的 @wsgi.action('xxx')
装饰函数给出,value为每个_action_xxx方法的名字(从中可以看出规律,在body里面请求的方法名前加上_aciton_即为Controller中对应调用的方法)。
之后在使用Controller构建Resource对象的过程中会向Resource注册该Controller的这个字典中的内容。这样,只需在请求的body中给出调用方法的key,然后就可以找到这个key所映射的方法,最后在Resource的call函数中会调用Controller类的这个函数!
其实我在上面我们打印 match 对象时,就已经将对应的函数打印出来了。
这边以 nova show(展示资源为例),来理解一下。
当你调用 nova show [uuid] 命令,novaclient 就会给 nova-api 发送一个http的请求
nova show 1c250b15-a346-43c5-9b41-20767ec7c94b
通过打印得到的 match 对象如下
{'action': u'show', 'controller': <nova.api.openstack.wsgi.ResourceV21 object at 0x667bad0>, 'project_id': u'2ac17c7c792d45eaa764c30bac37fad9'}
其中 action 就是对应的处理函数,而controller 就对应的 Resource 对象,project_id 是租户id(你可以不理会)。
继续看 ResourceV21 类里的 __call__
函数的代码。
图示地方,会从 environ 里获取中看到获取 action 的具体代码
我将这边的 action_args打印出来
{'action': 'show', 'project_id': '2ac17c7c792d45eaa764c30bac37fad9', 'id': '1c250b15-a346-43c5-9b41-20767ec7c94b'}
其中 action 还是是函数名,id 是要操作的资源的唯一id标识。
在 __call__
的最后,会 调用 _process_stack
方法
在图标处,get_method 会根据 action(函数名) 取得处理函数对象。
meth :<bound method ServersController.show of <nova.api.openstack.compute.servers.ServersController object at 0x7be3750>>
最后,再执行这个函数,取得 action_result,在 _process_stack
会对 response 进行初步封装。
然后将 response 再返回到 wsgify ,由这个专业的工具函数,进行 response 的最后封装和返回给客户端。
至此,一个请求从发出到响应就结束了。
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- Python3网络爬虫
3.Python3网络爬虫3.1爬虫分析爬取目的:爬取虎牙TV下,英雄联盟主播的人气排行。爬取网页:https://www.huya.com/g/lol分析网页:(1)如何实现爬取目的:抓取主播名称和直播间观看人数;(2)查找数据的html:在360浏览器下,按f12查看网页的html信息,点击html中左上角的箭头,…...
2024/4/28 11:58:03 - 解决sendmail启动慢的问题
在大部分linux发行版本中,sendmail这个古老的邮件系统包是默认安装的,装完系统后,重启时,不少兄弟遇到在启动过程中,到了启动sendmail服务的时候就停止了,没有耐性和经验的朋友这时候可能会以为系统出故障或…...
2024/4/27 11:53:29 - 软件定义汽车—箭在弦上的变革
1、软件定义汽车背景 在过去的几年中,智能手机和计算机,其标准化硬件在现有技术水平下正逐渐接近物理极限,这推动了其行业逐步从由硬件升级发展主导产品创新,转向由软件开发和迭代去推动硬件设计的更新和升级。 诚然,不…...
2024/4/28 5:21:39 - C语言单链表实现插入删除查找遍历
数据结构严蔚敏版复习1.1——单链表基础操作 基础复盘,还有很多不足 插入一个数 x->nextp->next;(这里p指向的是7) p->nextx; 删除 p一直往前走,不断和q比较 #include<stdio.h> #inclu…...
2024/4/29 0:47:10 - ASP家教信息管理系统
(1)家教注册模块 家教注册模块提供了两个表单供家教注册。第一个表单用于填写家教登录网站时需要的昵称和密码,若填写正确则进入第二个表单继续填写个人详细情况,所有必需信息填写完毕后重定向到家教的个人信息管理区,家教可以发布自己的求职…...
2024/4/28 6:57:43 - asp家政服务网
aspaccess 家政服务网 后台模块: 1,网站设置 :设置网站的访问地址,名称,邮箱地址等 2,管理应聘家政:对前台注册的从事家政工作的人员进行增,删,改,查. 3,管理招聘家政:对前台注册的,发布家政信息的会员进行增,删,改,查. 4,家政类管理 :对家政的类别进行增删改查,系统预设:搬家搬…...
2024/4/28 8:06:16 - asp家教预约网站(大学生家教网站)
本程序使用简单易学的aspaccess构建. 主要功能模块: 1,请家教信息登记(注册). 2.做家教用户注册包括三类用户(在校学生,教师,毕业学生). 3.学员列表:请家教用户信息列表 4.教员列表:做家教用户的信息列表 5.家教新闻资讯:此模块有后台新闻资讯分类灵活设置发布. 6.网站留言本 7…...
2024/4/28 2:24:00 - asp二学位在线报名管理系统的设计与实现
在二学位报名日渐增多的今天,大量的学生报名信息涌入,使得传统的报名审核模式逐渐不能满足需求。传统的报名管理工作是一个漫长而复杂的过程,已经越来越不适应现代化教学管路的需要。人工处理的工作量大,并且工作十分的繁琐而且容…...
2024/4/28 13:10:33 - #ifndef (#ifdef)... #def ... #endif用法
在C文件中我们常常看到文件中有#ifndef… #def…#endif (或者#ifdef … #def…)这些代码,它们属于预处理中的条件编译,主要有以下两个作用,防止头文件被重复引用和按条件对代码进行编译或者不编译。 1.防止头文件被重…...
2024/4/20 13:30:37 - 记 vant-popup 安卓样式折叠/样式错误问题(大坑)
最近用vant写一个项目的弹框,老碰到如下图这种错误 而且只有安卓有这种问题,找了一天,才知道安卓内置浏览器的高度会因为输入法唤醒而缩小, 所以不能用官方例子推荐的百分比高度或者vh高度,只能用固定高度!…...
2024/4/28 16:48:08 - 论文阅读(9)---基于Transformer的多模态CNN心电图心律失常分类
Multi-module Recurrent Convolutional Neural Network with Transformer Encoder for ECG Arrhythmia Classification 研究背景 目前已存的关于心电图分类的方法主要包括: 将原始心电图作为输入,并且将ECG分段以后利用1DCNN进行分类侧重于心电图信号…...
2024/4/21 18:20:57 - 基于springboot的文件上传功能实现
Service public class UploadService {Value("${file.uploadFolder}")private String uploadFolder; //这里为了扩展性,把这些路径写在yml文件中,如果项目上线,可以通过修改yml文件实现动态的修改Value("${file.staticPath…...
2024/4/21 18:20:57 - #ifndef ... #def ... #endif用法
#ifndef(#ifdef)… #def … #endif用法 在C文件中我们常常看到文件中有#ifndef… #def…#endif (或者#ifdef … #def…)这些代码,它们属于预处理中的条件编译,主要有以下两个作用,防止头文件被…...
2024/4/21 18:20:55 - Hibernate之关联关系
今日目标: 1,一对多的关联配置(数据库:主表从表,通过外键关联) 2,懒加载 3,一对多的自关联 4,多对多的关联,数据库中不能直接映射多对多(创建…...
2024/4/21 18:20:54 - PaddleLabel格式的数据批量处理
PaddleLabel格式的数据批量处理 import os import jsondef json_2_icdar(js_path, ic_path):with open(js_path, r, encodingutf-8) as f:with open(ic_path, w, encodingutf-8) as f1:for line in f.readlines():content line.split(\t)list_dict json.loads(content[1])ns…...
2024/4/21 18:20:53 - kakfa生产者
生产者分区:1.方便再集群中扩展2.可以提高并发原则:我们需要将producer发送的数据封装成一个ProduceRecord对象(行记录对象) 1.指明partition的情况下,直接将指明的值直接作为partition值 2.数据可靠性:为了保证producer发送的数据,可靠的发送…...
2024/4/21 18:20:53 - 2021-10-28 python试错笔记和学习笔记
调试:...
2024/4/21 18:20:51 - PMP学习整理
PMP学习Level 1Level 2Level 3Level 4Level 5Level 6Level 7Level 8过程组启动制定项目章程输出项目章程制定项目章程是编写一份正式批准项目并授权项目经理在项目活动中使用组织资源的文 件的过程。 本过程的主要作用是, 明确定义项目开始和项目边界, 确立项目的正式地位…...
2024/4/21 18:20:50 - Java的基本程序设计结构
一个简单的Java应用程序 下面看一个最简单也是比较经典的Java应用程序 public class FirstSample {public static void main(String[]args){System.out.println("We will not use Hello,world!");} } 这个程序虽然简单,但是所有的Java应用程序都具有这…...
2024/4/21 18:20:49 - RabbitMQ防止消息丢失
消息丢失场景 MQ消息丢失场景主要有三个: 1.消息生产者,发送消息后,rabbitmq服务器没有收到;导致消息丢失 2.rabbitmq收到消息后,没有持久化保存,导致消息丢失 3.消费者收到消息后,没来得及处理…...
2024/4/21 18:20:49
最新文章
- pytorch运行物体检测模型 SSD
物体检测是指根据一张图片包含的多个物体,通过模型分析物体的信息,最终给出图片中物体的位置以及物体的分类名称。物体检测输入的是一张图片,图片上包含多个物体,输出包括 图片中物体的位置和大小的相关信息物体的分类标签名称检…...
2024/4/29 1:08:13 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - JVM总结
类加载器与类的加载过程 ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定。 加载阶段 通过一个类的全限定名获取定义此类的二进制字节流 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构 在内存中生成…...
2024/4/26 4:35:04 - 利用Spark将Kafka数据流写入HDFS
利用Spark将Kafka数据流写入HDFS 在当今的大数据时代,实时数据处理和分析变得越来越重要。Apache Kafka作为一个分布式流处理平台,已经成为处理实时数据的事实标准。而Apache Spark则是一个强大的大数据处理框架,它提供了对数据进行复杂处理…...
2024/4/28 10:02:59 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/4/28 13:52:11 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/4/28 3:28:32 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/26 23:05:52 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/4/28 13:51:37 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/27 17:58:04 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/27 14:22:49 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/28 1:28:33 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/28 15:57:13 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/27 17:59:30 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/4/25 18:39:16 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/28 1:34:08 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/28 1:22:35 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/25 18:39:14 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/4/26 23:04:58 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/4/27 23:24:42 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/28 5:48:52 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/26 19:46:12 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/4/27 11:43:08 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/27 8:32:30 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57