def make_response(request, headers=None): """构造响应报文""" # 默认状态码为 200 status = 200 # 处理静态资源请求 if request.path.startswith('/static'): route, methods = routes.get('/static') else: route, methods = routes.get(request.path) # 如果请求方法不被允许返回 405 状态码 if request.method not in methods: status = 405 data = 'Method Not Allowed' else: # 请求首页时 route 实际上就是我们在 controllers.py 中定义的 index 视图函数 data = route(request) # 如果返回结果为 Response 对象,直接获取响应报文 if isinstance(data, Response): response_bytes = bytes(data) else: # 返回结果为字符串,需要先构造 Response 对象,然后再获取响应报文 response = Response(data, headers=headers, status=status) response_bytes = bytes(response) logger(f'response_bytes: {response_bytes}') return response_bytes
def register(request): """注册 Args: request: 请求对象 Returns: GET 请求: 返回注册页面 POST 请求: 注册成功将重定向到登录页 注册失败返回失败原因提示短语 """ if request.method == 'POST': # 获取表单中的用户名和密码 form = request.form logger(f'form: {form}') username = form.get('username') raw_password = form.get('password') # 验证用户名和密码是否合法 if not username or not raw_password: return '无效的用户名或密码'.encode('utf-8') user = User.find_by(username=username, ensure_one=True) if user: return '用户名已存在'.encode('utf-8') # 对密码进行散列计算,创建并保存用户信息 password = User.generate_password(raw_password) user = User(username=username, password=password) user.save() # 注册成功后重定向到登录页面 return redirect('/login') return render_template('auth/register.html')
def edit(request): """编辑 todo 视图函数""" # 处理 POST 请求 if request.method == 'POST': form = request.form logger(f'form: {form}') id = int(form.get('id', -1)) content = form.get('content') if id != -1 and content: todo = Todo.get(id=id) if todo: todo.content = content todo.save() return redirect('/index') # 处理 GET 请求 args = request.args logger(f'args: {args}') id = int(args.get('id', -1)) if id == -1: return redirect('/index') todo = Todo.get(id=id) if not todo: return redirect('/index') context = { 'todo': todo, } return render_template('todo/edit.html', **context)
def current_user(request): """获取当前登录用户 Args: request: 请求对象 Returns: 如果已登录,返回当前登录用户对象,否则返回 None """ # 从 Cookie 中获取 session_id cookies = request.cookies logger(f'cookies: {cookies}') session_id = cookies.get('session_id') # 查找 Session 并验证其是否过期 session = Session.get(session_id) if not session: return None if session.is_expired(): session.delete() return None # 查找当前登录用户 user = User.get(session.user_id) if not user: return None return user
def process_connection(client): """处理客户端请求 Args: client: 客户端请求对象 Returns: None """ request_bytes = b'' while True: chunk = client.recv(BUFFER_SIZE) request_bytes += chunk if len(chunk) < BUFFER_SIZE: break # 请求报文 request_message = request_bytes.decode('utf-8') logger(f'request_message: {request_message}') # 解析请求报文 request = Request(request_message) try: # 根据请求报文构造响应报文 response_bytes = make_response(request) except Exception as e: logger(e) # 返回给用户 500 页面 response_bytes = bytes(errors[500]()) # 返回响应 client.sendall(response_bytes) # 关闭连接 client.close()
def new(request): """新建 todo 视图函数""" form = request.form logger(f'form: {form}') content = form.get('content') if content: todo = Todo(content=content) todo.save() return redirect('/index')
def delete(request): """删除 todo 视图函数""" form = request.form logger(f'form: {form}') id = int(form.get('id', -1)) if id != -1: todo = Todo.get(id=id) if todo: todo.delete() return redirect('/index')
def main(): """入口函数""" with socket.socket() as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((HOST, PORT)) s.listen(5) logger(f'running on http://{HOST}:{PORT}') while True: client, address = s.accept() logger(f'client address: {address}') # 创建新的线程来处理客户端连接 t = threading.Thread(target=process_connection, args=(client, )) t.start()
def edit(request): """编辑 todo 视图函数 Args: request: 请求对象 Returns: GET 请求: 返回编辑页面 POST 请求: 更新当前编辑项,重定向到首页 """ if request.method == 'POST': form = request.form logger(f'form: {form}') id = int(form.get('id', -1)) content = form.get('content') if id != -1 and content: user = current_user(request) if user: todo = Todo.find_by(id=id, user_id=user.id, ensure_one=True) if todo: todo.content = content todo.save() return redirect('/index') args = request.args logger(f'args: {args}') id = int(args.get('id', -1)) if id == -1: return redirect('/index') user = current_user(request) if not user: return redirect('/index') todo = Todo.find_by(id=id, user_id=user.id, ensure_one=True) if not todo: return redirect('/index') context = { 'todo': todo, } return render_template('todo/edit.html', **context)
def login(request): """登录 Args: request: 请求对象 Returns: GET 请求: 返回登录页面 POST 请求: 登录成功将重定向到首页 登录失败返回失败原因提示短语 """ # 如果用户已经登录,直接重定向到首页 if current_user(request): return redirect('/index') if request.method == 'POST': message = '用户名或密码不正确'.encode('utf-8') # 获取表单中的用户名和密码 form = request.form logger(f'form: {form}') username = form.get('username') raw_password = form.get('password') # 验证用户名和密码是否正确 if not username or not raw_password: return message user = User.find_by(username=username, ensure_one=True) if not user: return message password = user.password if not User.validate_password(raw_password, password): return message # 创建 Session 并将 session_id 写入 Cookie 实现登录 session = Session(user_id=user.id) session.save() cookies = { 'session_id': session.id, } return redirect('/index', cookies=cookies) return render_template('auth/login.html')
def new(request): """新建 todo 视图函数 Args: request: 请求对象 Returns: 重定向到首页 """ form = request.form logger(f'form: {form}') content = form.get('content') if content: user = current_user(request) if user: todo = Todo(content=content, user_id=user.id) todo.save() return redirect('/index')
def delete(request): """删除 todo 视图函数 Args: request: 请求对象 Returns: 删除当前项,重定向到首页 """ form = request.form logger(f'form: {form}') id = int(form.get('id', -1)) if id != -1: user = current_user(request) if user: todo = Todo.find_by(id=id, user_id=user.id, ensure_one=True) if todo: todo.delete() return redirect('/index')
def process_connection(client): """处理客户端请求""" # 接收请求报文数据 request_bytes = b'' while True: chunk = client.recv(BUFFER_SIZE) request_bytes += chunk if len(chunk) < BUFFER_SIZE: break # 请求报文 request_message = request_bytes.decode('utf-8') logger(f'request_message: {request_message}') # 解析请求报文,构造请求对象 request = Request(request_message) # 根据请求对象构造响应报文 response_bytes = make_response(request) # 返回响应 client.sendall(response_bytes) # 关闭连接 client.close()