面试整理:Web框架
前端基础
1、基础中的基础
HTML
CSS
JS
2、框架和类库
Jquery
BootStrap
Vue.js
3、响应式布局的本质
也即自适应各种平台,例如电脑端显示应有的样式、移动端显示应有的样式;
浏览器窗口大小变化时,显示该大小应有的样式。
BootStrap的本质(源码),都是通过各种 CSS 样式实现的。
4、简单实现响应式布局
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>响应式布局本质</title> <!--简单实现响应式布局--> <style> body{ margin: 0; } .pg-header{ background-color: red; height: 50px; } /*浏览器窗口宽度大于768,背景色变为 green*/ @media (min-width: 768px) { .pg-header{ background-color: green; } } /*浏览器窗口宽度大于992,背景色变为 pink*/ @media (min-width: 992px) { .pg-header{ background-color: pink; } } </style> </head> <body> <div class="pg-header"></div> </body> </html>
5、JqueryAjax和原生Ajax
Jquery Ajax: $.ajax(......)
原生Ajax: XMLHttpRequest
6、跨域
JSONP
CORS
- 简单请求
- 复杂请求
PS:
Flask框架
7_0、Flask请求生命周期?
7_1、Flask的优势?
7_2、Flask内置功能的依赖关系?
7_3、写一个Flask服务
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run()
8、Flask内置功能
# 配置 config app = Flask(__name__) app.config['DEBUG'] = True # 路由 route # 视图 # 模板 template # Session 内置session 需要配置secret_key, 存放于cookie # 消息闪现 flash # 蓝图 blueprint
# 装饰器
# 中间件 middleware
9、Flask中使用装饰器
from functools import wraps #检查是否登录 def checkLogin(f): @wraps(f) def decorated_function(*args, **kwargs): if not flask.session.has_key('userid') or flask.session['userid'] == 0: return redirect('/login', code=302) return f(*args, **kwargs) return decorated_function @app.route('/', methods=['GET']) @checkLogin def index(): return "user is login" @app.route('/my', methods=['GET']) @checkLogin def index(): return "user center"
10、Flask中两个特殊装饰器
@app.before_request
@app.after_request
11、Flask中常用的第三方组件
# Flask组件 flask-session session放在redis flask-SQLAlchemy flask-migrate flask-script blinker # 第三方组件 wtforms dbutile gevnet-websocket # 自定义Flask组件 auth 参考flask-login组件
12_1、threading.local 以及作用?
12_2、Flask上下文管理流程以及和django比较?
12_3、Flask中上下文管理主要涉及到了那些相关的类?并描述类主要作用?
12_3、为什么要把Local的值维护成一个列表?
12_4、Flask中多app应用是怎么完成?
12_5、Flask中g的作用?
# 可以简单啊理解为针对与一次请求的全局变量集合
13、Flask主要用到了哪些技术
# 反射 # 面向对象:下划线方法 # 线程相关 threading.local.
14、实现一个栈&栈有哪些特性?
class Stack(object): # 初始化栈 def __init__(self): self.items = [] # 判断栈是否为空 def is_empty(self): return self.items == [] # 返回栈顶 def peek(self): return self.items[len(self.items) - 1] # 返回栈大小 def size(self): return len(self.items) # 压栈 def push(self, item): self.items.append(item) # 出栈 def pop(self): return self.items.pop()
15、什么是蓝图,作用呢?
# blueprint把实现不同功能的module分开. # 把一个大的application分割成各自实现不同功能的module. # 在一个blueprint中可以调用另一个blueprint的view function, 但要加相应的blueprint名.
16、Flask中的session什么时候创建、什么时候销毁?
# 前提: 不熟的话:记不太清了,应该是…… 熟悉的话:前两天恰好刚看过……. # 创建: 当请求刚进来的时候,会将request和session封装成一个RequestContext()对象, 接下来把这个对象通过LocalStack()放入内部的一个Local()(实现对数据隔离,类似threading.local) 对象中; 因为刚开始 Local 的ctx 中的session是空的; 所以,接着执行open_session,将cookie 里面的值拿过来,重新赋值到ctx中 (Local用来存数据) # 销毁: 最后返回时,候执行 save_session() 将ctx 中的session读出来进行序列化,写到cookie 然后给用户,接着把 ctx 移除掉(pop)
17、Local的作用?
-用于保存 # 请求(RequestContext())上下文对象 # App (AppContext())上下文对象 -并且可以做到”线程”间的数据隔离 # 线程指: threading.local
18、LocalStack的作用?
# 将Local中保存的数据维护成一个栈(后进先出—弹夹) 例如: { 1234:{ stack:[ctx, ctx, ctx] } }
Django框架
19、Django请求生命周期
图示:http://www.cnblogs.com/bigtreei/p/8379635.html
20、对Django/flask框架的认识(Django和Flask区别)
# 口述 # Django:对于django来说,是一个大而全的框架,内部组件特别多,
# 例如:ORM、admin、Form、ModelForm、中间件、信号、缓存、csrf等;
# Flask:而flask是一个微型框架,但可扩展性很强;如果开发简单程序,使用flask比较快捷;如果实现复杂功能,则需要引入一些组件;
# 例如:flask-session\flask-SQLAlchemy\wtforms\flask-migrate\flask-script\blinker
# 他们两个都基于wsgi协议实现的,但默认使用的wsgi模块是不一样的;(Django:wsigref Flask:werkzurg)
# 还有一个显著的特点,他们处理请求方式不同:
# Django:通过将请求封装成Request对象,再通过参数进行传递。
# Flask:通过上下文管理机制实现。
# 对了,感觉Flask的上下文管理还是挺有意思的。
延伸(可能会顺着问下去):
- Django组件:
- Flask组件、用途:
- wsgi
- 上下文管理:
21、你了解哪些框架?他们之间的区别?
21_1、Django和Flask,请求方式不同
#Django: 请求方式为传参 #Flask: 请求方式为上下文管理机制
21_2、Django的请求生命周期?
# 请求进来 # 走到wsgi # 走到中间件 # 路由匹配 # 执行相应的视图函数,ORM数据库操作 # 模板渲染成字符串 # 再经过中间件走回wsgi
21_3、什么是wsgi?
# 是web服务网关接口,是一套协议 #目前接触的: # wsigref(Django,性能较低) # werkzurg(Flask,性能较低) # uwsig(性能较高、线上发布) # 以上模块的本质: #实现wsgi协议的模块本质上是写了一个socket服务端,用来监听用户请求;
#如果有请求进来,则将请求进行一次封装,然后将封装后的请求交给web框架来进行后续处理。
from wsgiref.simple_server import make_server def run_server(environ, start_response): """ environ: 封装了请求相关的数据 start_response:用于设置响应头相关数据 """ start_response('200 OK', [('Content-Type', 'text/html')]) return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ] if __name__ == '__main__': httpd = make_server('', 8000, run_server) httpd.serve_forever()
class WSGIHandler(base.BaseHandler): request_class = WSGIRequest def __init__(self, *args, **kwargs): super(WSGIHandler, self).__init__(*args, **kwargs) self.load_middleware() def __call__(self, environ, start_response): # 请求刚进来之后 # set_script_prefix(get_script_name(environ)) signals.request_started.send(sender=self.__class__, environ=environ) request = self.request_class(environ) response = self.get_response(request) response._handler_class = self.__class__ status = '%d %s' % (response.status_code, response.reason_phrase) response_headers = [(str(k), str(v)) for k, v in response.items()] for c in response.cookies.values(): response_headers.append((str('Set-Cookie'), str(c.output(header='')))) start_response(force_str(status), response_headers) if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'): response = environ['wsgi.file_wrapper'](response.file_to_stream) return response
21_4、Django中间件的作用?用它做过什么?以及涉及的方法?
#a.中间件的作用? - 对所有的请求进行批量处理,在视图函数执行前后进行自定义操作。 #b.中间件的应用? - 登录验证 - 权限处理 - CORS跨域 - 还有一些内置的: - csrf? - session? - 全站缓存(中间件2/4)(见下图)? - 另外还有一个就是处理跨域(前后端分离时,本地测试开发时使用的) #c.中间件的方法( 5个方法)? 1、process_request(self, request) 2、process_view(self, request, callback, callback_args, callback_kwargs) 3、process_template_response(self, request, response)(当视图函数返回值对象中有render方法时,该方法才会被调用。) 4、process_exception(self, request, exception) 5、process_response(self, request, response)
21_4_1、为什么要用缓存?
#将常用且不太频繁修改的数据放入缓存。 #以后用户再来访问,先去缓存查看是否存在,如果有就返回 #否则,去数据库中获取并返回给用户(再加入到缓存,以便下次访问)
21_4_2、Django内部支持哪些缓存?
#Django中提供了6种缓存方式: 开发调试(不加缓存) 内存 文件 数据库 Memcache缓存(python-memcached模块) Memcache缓存(pylibmc模块) #安装第三方组件支持redis: django-redis组件
21_4_3、设置缓存有哪些?
#- 全站缓存 #- 视图函数缓存 #- 局部模板缓存
21_5、路由系统
#在url和视图函数对应关系中,根据当前请求url找到相应的函数。
21_6、模板
索引: {{v.0}} 方法执行: {% for item in dic.items %} {%endfor%} 模板继承 自定义方法: - simple_tag - inclusion_tags - filter
21_7、视图函数
- 遇到的难题: - CBV是添加csrf装饰器 - 多数据库配置 allow_relation方法 - FBV def index(request): pass - CBV(源码中走的 as_view) class IndexView(View): 路由:IndexView.as_view() - CBV 和 FBV的区别是什么? - 我认为没什么区别,他们的本质都是函数。因为CBV中.as_view()返回的是view函数,view函数中调用类的dispatch方法,在dispatch方法中通过反射执行get/post/delete/put等方法。 - 如果非要说区别的话,CBV比较简洁,它的GET/POST等业务功能分别放在不同get/post函数中。而FBV则自己做判断进行区分。 -使用CBV时的注意事项? -装饰器
-csrf的装饰器要加到dispatch
from django.views import View from django.utils.decorators import method_decorator def auth(func): def inner(*args,**kwargs): return func(*args,**kwargs) return inner class UserView(View): @method_decorator(auth) def get(self,request,*args,**kwargs): return HttpResponse('...')
from django.views import View from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt,csrf_protect class UserView(View): @method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): return HttpResponse('...') 或 from django.views import View from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt,csrf_protect @method_decorator(csrf_exempt,name='dispatch') class UserView(View): def dispatch(self, request, *args, **kwargs): return HttpResponse('...')
22、CSRF的原理是什么?
# #为了防止用户直接向服务端发起POST请求。 # 用户先发送一个GET请求,获取csrf_token:Form表单中一个 隐藏的标签+cookie # 发起POST请求时,需要携带之前发送给用户的CSRF_TOKEN: # 在 process_view 方法中进行校验
23、向后台发送POST请求的方式有哪些?
- Ajax
- Postman
- form表单
- 爬虫:request.post()
<form method="POST"> {% csrf_token %} <input type='text' name='user' /> <input type='submit' /> </form>
$.ajax({ url:'/index', type:'POST', data:{csrfmiddlewaretoken:'{{ csrf_token }}',name:'alex'} }) 前提:引入jquery + 引入jquery.cookie $.ajax({ url: 'xx', type:'POST', data:{name:'oldboyedu'}, headers:{ X-CSRFToken: $.cookie('csrftoken') }, dataType:'json', // arg = JSON.parse('{"k1":123}') success:function(arg){ } })
<body> <input type="button" onclick="Do1();" value="Do it"/> <input type="button" onclick="Do2();" value="Do it"/> <input type="button" onclick="Do3();" value="Do it"/> <script src="/static/jquery-3.3.1.min.js"></script> <script src="/static/jquery.cookie.js"></script> <script> $.ajaxSetup({ beforeSend: function(xhr, settings) { xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken')); } }); function Do1(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } function Do2(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } function Do3(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } </script> </body>
24、Form和ModelForm的作用?区别?应用场景?
# 作用: - 对用户请求数据格式进行校验 - 自动生成HTML标签 # 区别: # Form,字段需要自己手写。 class Form(Form): xx = fields.CharField(.) xx = fields.CharField(.) xx = fields.CharField(.) xx = fields.CharField(.) # ModelForm,可以通过Meta进行定义 class MForm(ModelForm): class Meta: fields = "__all__" model = UserInfo # 应用:只要是客户端向服务端发送表单数据时,都可以进行使用,如:用户登录注册
# 问题:choice的数据如果从数据库获取可能会造成数据无法实时更新 # 答案:重写构造方法,在构造方法中重新去数据库获取值。
25、Django中都有哪些内置组件?
#例如:ORM、admin、Form、ModelForm、中间件、信号、缓存、csrf等,
#这些都是django内置的组件
26、这些组件中哪个组件最好?对哪个组件最熟悉?
#1、我感觉不能说哪个组件最好,因为他们各有所长,单独拿出来进行比较不合适; #2、ORM用的最多,因为只要涉及到数据操作,基本都会用到ORM
27、ORM中你都记得哪些方法?(★★★★★)
#a、首先是增删改查这些,例如:.creat(),bukle_creat() #b、然后是查询取值这块,values/values_list #c、还有有F/Q这类复杂查询用法 #d、以及性能相关,例如:.prefetch_related()/select_related() #都可以用于连表,减少SQL查询次数 #e、再者是一些靠近原生SQL的用法,例如:extra、raw、execute等
28、django信号的作用?
#django的信号其实就是django内部为开发者预留的一些自定制功能的钩子。 #只要在某个信号中注册了函数,那么django内部执行的过程中就会自动触发注册在信号中的函数。 如: pre_init # django的modal执行其构造方法前,自动触发 post_init # django的modal执行其构造方法后,自动触发 pre_save # django的modal对象保存前,自动触发 post_save # django的modal对象保存后,自动触发 #用信号做过什么? 在数据库某些表中添加数据时,可以进行日志记录。
29、Django中的序列化?
#内置: from django.core import serializers #queryset = [obj,obj,obj] ret = models.BookType.objects.all() data = serializers.serialize("json", ret) #json: import json #ret = models.BookType.objects.all().values('caption') ret = models.BookType.objects.all().values_list('caption') ret=list(ret) result = json.dumps(ret) #补充: - json.dumps(ensure_ascii=True) - json.dumps( cls=JSONEncoder)
30、admin & stark组件关系?
#- 为公司定制更适用于自己的组件: stark组件
31、ContentType的作用?以及应用场景?
#contenttype是django的一个组件(app),为我们找到django程序中所有app中的所有表并添加到记录中。 #可以使用他再加上表中的两个字段实现:一张表和N张表创建FK关系。 - 字段:表名称 - 字段:数据行ID #应用:路飞表结构优惠券和专题课和学位课关联。
32、什么是幂等性?
# 一个接口通过1次相同的访问,再对该接口进行N次相同的访问时候,对资源不造影响,那么就认为接口具有幂等性。 比如: GET, #第一次获取结果、第二次也是获取结果对资源都不会造成影响,幂等。 POST, #第一次新增数据,第二次也会再次新增,非幂等。 PUT, #第一次更新数据,第二次不会再次更新,幂等。 PATCH,#第一次更新数据,第二次不会再次更新,非幂等。 DELTE,#第一次删除数据,第二次不在再删除,幂等。
33、实现远程数据交互的有哪些?
#- webservice, webservice是在rest api广泛引用之前大家使用的一个跨平台交互的接口。 #- restfull api #- RPC
扩展:WCF他是创建了一个双工通道。
Django rest framework 框架
34、谈谈你对restfull 规范的认识?
# restful其实就是一套编写接口的协议,协议规定如何编写以及如何设置返回值、状态码等信息。 # 最显著的特点: restful: 给用户一个url,根据method不同在后端做不同的处理,比如:post 创建数据、get获取数据、put和patch修改数据、delete删除数据。 no rest: 给调用者很多url,每个url代表一个功能,比如:add_user/delte_user/edit_user/ # 当然,还有协议其他的,比如: # 版本,来控制让程序有多个版本共存的情况,版本可以放在 url、请求头(accept/自定义)、GET参数 # 状态码,200/300/400/500 # url中尽量使用名词,restful也可以称为“面向资源编程” # api标示: api.luffycity.com www.luffycity.com/api/
34_1、状态码有哪些?
- 200 #请求成功 - 300 - 301 #永久重定向 - 302 #临时重定向 - 400 - 403 #CSRF(跨域) - 404 #找不到页面 - 500 #内部服务器错误
34_2、method都有哪些?
# GET/POST/PUT/DELETE/PATCH/OPTIONS/HEADERS/TRACE(请求方式)
34_3、常见的请求头有哪些?
# GET # POST # PUT # DELETE # TRACE # HEAD # OPTIONS # CONNECT
34_4、 你的restfull是怎么学的?
# 因为之前公司要写这样项目 - 接口 - 公司要做前后端分离的项目 - 公司要做微信小程序的开发 # 所以就开始学习restful规范,看的技术文章 阮一峰的博客学到的规范。
35、用django写接口时,有没有用什么框架?
#- 使用 Django rest framework 框架 #- 以及原生CBV
36、为什么用rest framework框架?
#1、在编写接口时可以不使用django rest framework框架, #2、如果不使用:也可以做,那么就可以django的CBV来实现,开发者编写的代码会更多一些。 #3、如果 使用:内部帮助我们提供了很多方便的组件,我们通过配置就可以完成相应操作,如: #a、序列化,可以做用户请求数据校验+queryset对象的序列化称为json #b、解析器,获取用户请求数据request.data,会自动根据content-type请求头的不能对数据进行解析 #c、分页,将从数据库获取到的数据在页面进行分页显示。 # 还有其他组件: #d、认证 #e、权限 #f、访问频率控制
37、rest framework都有哪些组件?
#- 路由,自动帮助开发者快速为一个视图创建4个url www.oldboyedu.com/api/v1/student/$ www.oldboyedu.com/api/v1/student(?P<format>\w+)$ www.oldboyedu.com/api/v1/student/(?P<pk>\d+)/$ www.oldboyedu.com/api/v1/student/(?P<pk>\d+)(?P<format>\w+)$ #- 版本处理 - 问题:版本都可以放在那里? - url - GET - 请求头 #- 认证 - 问题:认证流程? #- 权限 - 权限是否可以放在中间件中?以及为什么? #- 访问频率的控制 - 匿名用户可以真正的防止?无法做到真正的访问频率控制,只能把小白拒之门外。 如果要封IP,使用防火墙来做。 - 登录用户可以通过用户名作为唯一标示进行控制,如果有人注册很多账号,也无法防止。 #- 视图 #- 解析器 ,根据Content-Type请求头对请求体中的数据格式进行处理。request.data #- 分页 #- 序列化 - 序列化 - source - 定义方法 - 请求数据格式校验 #- 渲染器
38、rest framework 视图你都用过哪些基类?
#a. 继承 APIView # 这个类属于rest framework中顶层类,内部帮助我们实现了一些基本功能: # 认证、权限、频率控制,但凡是数据库、分页等操作都需要手动去完成,比较原始。 class GenericAPIView(APIView) def post(...): pass #b. 继承 GenericViewSet(ViewSetMixin, generics.GenericAPIView) # 如果继承它之后,路由中的as_view需要填写对应关系 ---> .as_view({'get':'list','post':'create'}) # 在内部也帮助我们提供了一些方便的方法: - get_queryset - get_object - get_serializer 注意:要设置queryset字段,否则会抛出断言的异常。 # 只提供增加功能 class TestView(GenericViewSet): serializer_class = XXXXXXX def create(self,*args,**kwargs): pass # 获取数据并对数据进行操作 #c. 继承 - ModelViewSet - mixins.CreateModelMixin,GenericViewSet - mixins.CreateModelMixin,DestroyModelMixin,GenericViewSet # 对数据库和分页等操作不用我们在编写,只需要继承相关类即可。 示例:只提供增加功能 class TestView(mixins.CreateModelMixin,GenericViewSet): serializer_class = XXXXXXX 类的继承关系
39、rest framework中的认证流程?
- 如何编写?写类并实现authticate - 方法中可以定义三种返回值: - (user,auth),认证成功 - None , 匿名用户 - 异常 ,认证失败 - 流程: - dispatch - 再去request中进行认证处理
40、rest framework中的访问频率控制?
# 匿名用户,根据用户IP或代理IP作为标识进行记录,为每一个用户在redis中创建一个列表 { throttle_1.1.1.1:[1526868876.497521,152686885.497521...] throttle_1.1.1.2:[1526868876.497521,152686885.497521...] throttle_1.1.1.3:[1526868876.497521,152686885.497521...] throttle_1.1.1.4:[1526868876.497521,152686885.497521...] throttle_1.1.1.5:[1526868876.497521,152686885.497521...] } 每个用户再来访问时,需要先去记录中剔除以及过期时间,再根据列表的长度判断是否可以继续访问。 如何封IP:在防火墙中进行设置 # 注册用户,根据用户名或邮箱进行判断。 { throttle_xxxx1:[1526868876.497521,152686885.497521...] throttle_xxxx2:[1526868876.497521,152686885.497521...] throttle_xxxx3:[1526868876.497521,152686885.497521...] throttle_xxxx4:[1526868876.497521,152686885.497521...] } 每个用户再来访问时,需要先去记录中剔除以及过期时间,再根据列表的长度判断是否可以继续访问。 1分钟:40次
41、渲染器中的坑?
#- 指定渲染器只用JSON #- 视图: class UserView(...): queryset = [] ...
42、assert (断言)是的作用?
#条件成立则继续往下,否则抛出异常; #一般用于:满足某个条件之后,才能执行,否则应该抛出异常。
应用场景:rest framework
class GenericAPIView(views.APIView): queryset = None serializer_class = None lookup_field = 'pk' lookup_url_kwarg = None # The filter backend classes to use for queryset filtering filter_backends = api_settings.DEFAULT_FILTER_BACKENDS # The style to use for queryset pagination. pagination_class = api_settings.DEFAULT_PAGINATION_CLASS def get_queryset(self): assert self.queryset is not None, ( "'%s' should either include a `queryset` attribute, " "or override the `get_queryset()` method." % self.__class__.__name__ ) queryset = self.queryset if isinstance(queryset, QuerySet): # Ensure queryset is re-evaluated on each request. queryset = queryset.all() return queryset
43、Django中用到的跨域?
#JsonP #CORS
Websocket协议相关
44、websocket和http的区别?
websocket是一套类似于http的协议。 区别: # http协议:\r\n分割、请求头和请求体\r\n分割、无状态、短连接。 #websocket协议:\r\n分割、创建连接后不断开、 验证+数据加密;
45、什么是websocket?
websocket是给浏览器新建一套协议。协议规定:浏览器和服务端连接之后不断开,以此可以完成:服务端向客户端主动推送消息。
websocket协议额外做的一些前提操作: - 握手,连接前进行校验 - 发送数据加密
46、websocket的本质是?
就是一个创建连接后不断开的socket
握手,魔法字符串+加密 加密,payload_len=127/126/<=125 -> mask key
websocket是什么? websocket是一套类似于http的协议。 扩展: http协议:\r\n分割、请求头和请求体\r\n分割、无状态、短连接。 websocket协议:\r\n分割、创建连接后不断开、 验证+数据加密; websocket本质: - 就是一个创建连接后不断开的socket - 当连接成功之后: - 客户端(浏览器)会自动向服务端发送消息,包含: Sec-WebSocket-Key: iyRe1KMHi4S4QXzcoboMmw== - 服务端接收之后,会对于该数据进行加密: base64(sha1(swk + magic_string)) - 构造响应头: HTTP/1.1 101 Switching Protocols\r\n Upgrade:websocket\r\n Connection: Upgrade\r\n Sec-WebSocket-Accept: 加密后的值\r\n WebSocket-Location: ws://127.0.0.1:8002\r\n\r\n - 发给客户端(浏览器) - 建立:双工通道,接下来就可以进行收发数据 - 发送的数据是加密,解密,根据payload_len的值进行处理: - payload_len <=125 - payload_len ==126 - payload_len ==127 - 获取内容: - mask_key - 数据 根据mask_key和数据进行位运算,就可以把值解析出来。
47、不同框架在项目中通过什么实现websocket?
#django: channel #flask: gevent-websocket #tornado: 内置
a. 安装 pip3 install gevent-websocket 作用: - 处理Http、Websocket协议的请求 -> socket - 封装Http、Websocket相关数据 -> request b. 基本结构 from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer @app.route('/test') def test(): ws = request.environ.get('wsgi.websocket') ws.receive() ws.send(message) ws.close() return render_template('index.html') if __name__ == '__main__': http_server = WSGIServer(('0.0.0.0', 5000,), app, handler_class=WebSocketHandler) http_server.serve_forever()
#后端: from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer from flask import Flask,render_template,request import pickle app = Flask(__name__) app.secret_key = 'xfsdfqw' @app.route('/index') def index(): return render_template('index.html') WS_LIST = [] @app.route('/test') def test(): ws = request.environ.get('wsgi.websocket') if not ws: return '请使用WebSocket协议' # websocket连接已经成功 WS_LIST.append(ws) while True: # 等待用户发送消息,并接受 message = ws.receive() # 关闭:message=None if not message: WS_LIST.remove(ws) break for item in WS_LIST: item.send(message) return "asdfasdf" if __name__ == '__main__': http_server = WSGIServer(('0.0.0.0', 5000,), app, handler_class=WebSocketHandler) http_server.serve_forever() #前端: <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <style> .msg-item{ padding: 5px; border: 1px; margin: 0 5px; } </style> </head> <body> <h1>首页</h1> <div> <h2>发送消息</h2> <input id="msg" type="text" /> <input type="button" value="发送" onclick="sendMsg()"> <h2>接收消息</h2> <div id="container"> </div> </div> <script src="/static/jquery-3.3.1.min.js"></script> <script> ws = new WebSocket('ws://192.168.12.42:5000/test'); ws.onmessage = function (event) { var tag = document.createElement('div'); tag.className = 'msg-item'; tag.innerText = event.data; $('#container').append(tag); } function sendMsg() { ws.send($('#msg').val()); } </script> </body> </html>
48、实时消息推送用什么实现?优缺点?
#轮询 优点:简单 缺点:请求次数多,服务器压力大,消息延迟 #长轮询 优点:实时接收数据,兼容性好 缺点:请求次数比原来少,但是相对原来也不少 #websocket 优点:代码简单,不再重复创建连接 缺点:兼容性没有长轮询好
Tornado框架
49、什么是Tornado?
#Tornado是一个轻量级的Web框架,异步非阻塞+内置WebSocket功能。
#安装:pip3 install tornado
目标:通过一个线程处理N个并发请求。
- 处理请求IO :牛逼起来
- 处理非请求IO:傻逼起来
import tornado from tornado.web import Application from tornado.web import RequestHandler from tornado.websocket import WebSocketHandler class IndexHandler(RequestHandler): def get(self, *args, **kwargs): # self.write('Hello World') self.render('index.html') def post(self, *args, **kwargs): user = self.get_argument('user') self.write('成功') WS_LIST = [] class MessageHandler(WebSocketHandler): def open(self, *args, **kwargs): WS_LIST.append(self) def on_message(self, message): for ws in WS_LIST: ws.write_message(message) def on_close(self): WS_LIST.remove(self) settings = { 'template_path':'templates', 'static_path':'static', } app = Application([ (r"/index", IndexHandler), (r"/message", MessageHandler), ],**settings) if __name__ == '__main__': app.listen(address='0.0.0.0',port=9999) tornado.ioloop.IOLoop.instance().start()
50、tornado有哪些内部组件?
#内部自己实现socket #路由系统 #视图 #模板 #cookie #csrf
51、Tornado异步非阻塞本质?
视图函数yield一个futrue对象,futrue对象默认: self._done = False ,请求未完成 self._result = None ,请求完成后返回值,用于传递给回调函数使用。 tornado就会一直去检测futrue对象的_done是否已经变成True。 如果IO请求执行完毕,自动会调用future的set_result方法: self._result = result self._done = True
参考:http://www.cnblogs.com/wupeiqi/p/6536518.html(自定义异步非阻塞web框架)
MTV和MVC区别
52、MTV和MVC?
#MVC: model view controller #MTV: model tempalte view