面试6


1. 谈谈你对restful规范的理解?
- 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/
- https
- 请求方式:
- 返回值:
- URL添加条件
- 状态码: 
- 错误信息
- hyperlink

2. 你的restful是怎么学的?
- 因为之前公司要写这样项目
- 接口
- 公司要做前后端分离的项目
- 公司要做微信小程序的开发
- 所以就开始学习restful规范,看的技术文章阮一峰的博客学到的规范。

3. 状态码都有哪些?
200,请求成功
301,永久重定向
302,临时重定向
403,服务器拒绝执行此请求
404,找不到页面
500,服务器错误
4. method都有哪些?
 GET,POST ,HEADER,OPTIONS,PUT,DELETE,TRACE 
5. 常见请求头有哪些?
User-Agent,Referer,Host,Content-Type,Cookie,Accept
6. 你是用什么开发的restful接口?
使用django rest framework框架。

7. 为什么要使用django rest framework框架?
在编写接口时可以不适用django rest framework框架,

如果不使用:也可以做,那么就可以django的CBV来实现,开发者编写的代码会更多一些。
如果 使用:内部帮助我们提供了很多方便的组件,我们通过配置就可以完成相应操作,如:
- 序列化,可以做用户请求数据校验+queryset对象的序列化称为json
- 解析器,获取用户请求数据request.data,会自动根据content-type请求头的不能对数据进行解析
- 分页,将从数据库获取到的数据在页面进行分页显示。
还有其他:
- 认证
- 权限
- 访问频率控制
- 版本
     - 渲染器
- 路由
8. 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



9. 认证流程?
- 写类并实现authticate
- 方法中可以定义三种返回值:
  - (user,auth),认证成功
  - None , 匿名用户
  - 异常 ,认证失败
- 流程:

1,dispatch

2,self.initial(request, *args, **kwargs)

3,self.perform_authentication(request)

4,request.user

5,self._authenticate()

返回三种情况:

  1,(user, token)表示认证通过并设置用户名和Token;
  2,None 匿名用户
  3,AuthenticationFailed异常
- 再去request中进行认证处理

10. 访问频率控制
- 匿名用户,根据用户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...]
}

每个用户再来访问时,需要先去记录中剔除以及过期时间,再根据列表的长度判断是否可以继续访问。


11. 接口的幂等性?(是否会造成2次伤害)
一个接口通过1次相同的访问,再对该接口进行N次相同的访问时候,对资源不造影响,那么就认为接口具有幂等性。
比如:
GET, 第一次获取结果、第二次也是获取结果对资源都不会造成影响,幂等。
POST,第一次新增数据,第二次也会再次新增,非幂等。
PUT, 第一次更新数据,第二次不会再次更新,幂等。
PATCH,第一次更新数据,第二次不会再次更新,非幂等。
DELTE,第一次删除数据,第二次不在再删除,幂等。


12. Https和Http区别?

Http: 80端
https: 443端口

- 自定义证书 
  - 服务端:创建一对证书
  - 客户端:必须携带证书
- 购买证书
  - 服务端: 创建一对证书,。。。。
  - 客户端: 去机构获取证书,数据加密后发给咱们的服务单
  - 证书机构:公钥给改机构


13. Flask框架的优势?
flask: 微型框架、可扩展强,如果开发简单程序使用flask比较快速,如果实现某些功能就需要引入一些组件:flask-session/flask-SQLAlchemy/wtforms/flask-migrate/flask-script/blinker
还有一个显著的特点,他处理请求的方式是通过上下文管理机制实现
14. Flask内置功能依赖?
jinjia2,werkzurg

15. Flask第三方组件?
- flask-session
将默认保存的签名cookie中的值 保存到 redis/memcached/file/Mongodb/SQLAlchemy
    a. 配置
        app.config['SESSION_TYPE'] = 'redis'
        app.config['SESSION_REDIS'] = Redis(host='192.168.0.94',port='6379')
        
    b. 替换 
        from flask_session import Session
        Session(app)
    - flask-migrate
from s8day130_pro import create_app,db
from flask_script import Manager
from flask_migrate import Migrate,MigrateCommand


app = create_app()
manager = Manager(app)

Migrate(app, db)
"""
# 数据库迁移命名
    python manage.py db init
    python manage.py db migrate # makemigrations
    python manage.py db upgrade # migrate
"""
manager.add_command('db', MigrateCommand)


if __name__ == '__main__':
    # app.run()
    manager.run()

- flask-script
from s8day130_pro import create_app,db
from flask_script import Manager
from flask_migrate import Migrate,MigrateCommand


app = create_app()
manager = Manager(app)
if __name__ == '__main__':
    # app.run()
    manager.run()
    - flask-sqlalchemy(SQLAlchemy)  
将SQLAlchemy相关的所有功能都封装到db=flask_sqlalchemy.SQLAlchemy()对象中
- blinker
让开发者可是在flask请求过程中定制一些用户行为。

信号和before_request区别

before_request,可以控制请求是否可以继续往后执行。
信号,在原来的基础增加额外的操作和值。


- wtforms
类似django的form组件
a. wtforms作用?
      --表单验证,渲染标签
b. wtforms涉及到的知识点?哪里用了?
- metaclass
     用于指定使用哪个类来创建当前类--wtforms对字段进行排序
     metaclass--->类--->实例
- 封装:
     wtforms--UnboundField
     restframework--request
- __new__
     wtforms--实例化流程-字段实例化时返回:不是StringField,而是UnboundField
     restframework--many=true
     单例模式--类方法
- __mro__
     类的继承顺序
- setattr
     cbv,django配置文件,wtforms实例化:setattr(self, name, field)
      - type(...)
     type创建类

- dbutils
数据库连接池,为所有线程提供连接池,使用时来进行获取,使用完毕后在放回到连接池,实现并发
- gevent-websocket
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()
    
- flask-login自定义组件

16. threading.local 以及作用?
为每个线程开辟一块空间进行数据存储
17. Flask上下文管理流程以及和django比较?
我认为上下文管理可以分成三个阶段
1,处理请求,并通过localstack将请求相关数据封装到一个栈local中
2,处理视图函数,通过代理localproxy,调用偏函数,通过localstack从local中取到数据
3,保存cookie,对每个对象采用各自的pop方法进行删除
django是通过封装请求到request,然后通过传参的方式传递
18. Flask中的g的作用?

单次请求中处理请求时临时存储的对象
当前请求的整个生命周期内访问和使用,当请求处理完毕的时候,它将会被回收。

19. Flask中上下文管理主要涉及到了那些相关的类?并描述类主要作用?
RequestContext(request,session)封装request和session
AppContext(app,g)封装应用和临时变量g
LocalStack:
将Local中保存的数据维护成一个栈
Local:
- 用于保存
- 请求上下文对象
- app上下文对象
- 并且可以做到“线程”间的数据隔离。
LocalProxy代理 -> 偏函数 -> LocalStack -> Local
20. 为什么要把Local的值维护成一个列表?
Web应用时:
- 服务端单线程:
{
111:{stack: [ctx, ]}
}
- 服务端多线程:
{
111:{stack: [ctx, ]}
112:{stack: [ctx, ]}
}
离线脚本:
with app01.app_context():
print(current_app)
with app02.app_context():
print(current_app)
print(current_app)
21. Flask中多app应用是怎么完成?
from flask import Flask
from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.serving import run_simple

app01 = Flask('app01')
app02 = Flask('app02')

@app01.route('/login')
def login():
    return 'app01.login'

@app02.route('/index')
def index():
    return 'app02.index'


dm = DispatcherMiddleware(app01,{
    '/app02':        app02,
})

if __name__ == '__main__':
    run_simple('localhost', 5000,dm)

22. 原生SQL和ORM的区别?
ORM操作简单,开发效率快
原生SQL操作复杂,数据库执行效率快
23. SQLAlchemy中的 session 的创建有几种方式?
https://www.cnblogs.com/wupeiqi/articles/8259356.html

- 直接创建Session对象
engine = create_engine("mysql+pymysql://root:[email protected]:3306/s6", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)


def task(arg):
session = Session()

obj1 = Users(name="alex1")
session.add(obj1)

session.commit()


for i in range(10):
t = threading.Thread(target=task, args=(i,))
t.start()

- 基于scoped_session(Flask-SQLAlchemy中的连接默认使用该方法)
engine = create_engine("mysql+pymysql://root:[email protected]:3306/s6", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)

session = scoped_session(Session)

def task(arg):

obj1 = Users(name="alex1")
session.add(obj1)

session.commit()


for i in range(10):
t = threading.Thread(target=task, args=(i,))
t.start()












猜你喜欢

转载自www.cnblogs.com/weiwu1578/p/9069348.html