-
HTTP - 超文本传输协议 - 请求响应式协议
-
HTTP 请求
- 请求行:GET /index.html HTTP/1.1
- 请求头:键值对
- 空行:\r\n
- 消息体:发给服务器的数据 HTTP 响应
- 响应行:HTTP/1.1 403 Forbidden
-
响应头:键值对
-
-
Content-Type —> MIME类型
- image/png
- text/html
- application/json
- application/pdf
- audio/mp3
- video/mp4
- application/vnd.ms-excel
-
-
Content-Disposition —> 内容处置的方式
- inline
- attachment; filename="…"
-
- 空行:
- 消息体:HTML页面、JSON数据、图片、音视频、PDF、Excel、……
-
-
Ajax - Asynchronous JavaScript and XML
-
异步请求:在浏览器后台偷偷给服务器发请求(不中断用户体验)
- XMLHttpRequest
- Fetch API
- Axois
-
局部刷新:不刷新整个页面,只刷新数据发生了变化的局部
- JavaScript —> DOM
HTML code = Tag + CSS + JavaScript
- Tag —> content
- CSS —> display
- JavaScript —> behavior
~ ECMAScript —> 语法规范
~ BOM —> 浏览器对象模型 —> window
~ DOM —> 文档对象模型 —> document{ messages: [ { from: "余婷", to: "骆昊", content: "晚上请你吃饭" }, { from: "余婷", to: "骆昊", content: "发错了,抱歉" } ] } <?xml version="1.0" encoding="utf-8"?> <messages> <message> <from>余婷</from> <to>骆昊</to> <content>晚上请你吃晚饭</content> </message> <message> <from>余婷</from> <to>骆昊</to> <content>发错了,抱歉</content> </message> </messages>
-
异步请求:在浏览器后台偷偷给服务器发请求(不中断用户体验)
-
-
渲染页面(把动态的内容填到页面上)的方式
-
后端渲染(服务器侧渲染)
缺点:- 如果服务器的并发请求量很大,服务器会不堪重负
- 前端代码和后端代码混在了一起,没有完全分开
-
前端渲染(用户侧渲染)—> 前后端分离的开发
要点:- 服务器不负责渲染页面,只负责提供页面需要的数据(JSON)
- 浏览器通过JavaScript代码实现对页面的渲染 —> Vue
优点: - 服务器负担减小,渲染页面的操作在用户端来完成
- 前端和后端代码完全分离,相互不牵扯,更有利于团队开发
缺点: - 对于移动终端来说,耗电量会增加
- 如果用户终端性能不理想,那么用户体验可能会比较糟糕
-
-
跨域问题
浏览器的同源策略会阻止JavaScript代码回访其他网站的数据,
如果希望别的网站能够跨域请求到我们提供的JSON数据接口,就必须进行跨域设置。- 安装三方库:pip install flask-cors
- flask-cors三方库通过修改HTTP响应头,告诉浏览器可以允许跨域访问数据
from flask_cors import CORS
app = flask.Flask(name)
CORS(app)
创建数据库myapp
drop database if exists `myapp`;
create database `myapp` default character set utf8mb4;
use `myapp`;
create table `tb_fruit`
(
`frt_id` bigint unsigned auto_increment comment '编号',
`frt_name` varchar(50) not null comment '名称',
`frt_image` varchar(255) not null comment '图片',
`frt_intro` varchar(1024) default '' not null comment '介绍',
primary key (`frt_id`)
) engine=innodb comment '水果表';
insert into `tb_fruit`
(`frt_name`, `frt_image`, `frt_intro`)
values
('苹果', 'apple.png', '苹果树是蔷薇科苹果亚科苹果属植物,为落叶乔木,在世界上广泛种植。苹果,又称柰或林檎,是苹果树的果实,一般呈红色,但需视品种而定,富含矿物质和维生素,是人们最常食用的水果之一。人们根据需求的不同口感、用途培育不同的品种,已知有超过7,500个苹果品种,拥有一系列人们需要的不同特性。'),
('榴莲', 'durian.png', '榴梿,是原产于马来西亚和印度尼西亚等东南亚国家的一种巨型热带常绿乔木,木棉科下榴梿属的模式种。榴梿一词通常指其果实,也称麝香猫果,中国古称“赌尔焉”。'),
('山竹', 'mangosteen.png', '山竹,又名莽吉柿、芒翕、山竺、山竹子、倒捻子、凤果,热带常绿乔木,为藤黄科藤黄属下的一个种。原产于马来群岛中的巽他群岛和摩鹿加群岛,由于盛产于南洋热带地区,有“热带果后”之称。在马来西亚、新加坡和泰国,榴梿和山竹被视为“夫妻果”,故此相对于称为“果王”的榴梿而言,山竹就是“果后”。'),
('菠萝', 'pineapple.png', '菠萝是原产于南美洲的热带水果,为禾本目菠萝科菠萝属植物,因多汁酸甜受到喜爱,有解暑之效,是菠萝科中最具经济价值的种类。南美洲种植菠萝已有许多世纪,在17世纪传入欧洲,于1820年代开始在温室与热带地区开始商业种植'),
('火龙果', 'pitaya.png', '火龙果又称红龙果、龙珠果、仙人掌果或量天尺果,是仙人掌科三角柱属或蛇鞭柱属的植物果实。水果呈椭圆形,直径10-12cm,外观为红色或黄色,有绿色圆角三角形的叶状体,灰白色、紫红色或黄色果肉,黑色种子。'),
('草莓', 'strawberry.png', '草莓,为草莓属中最常见的杂交栽培种。也常指其果实。草莓是多年生草本植物,一般存活时间为3年左右。在中国大陆和台湾称草莓,香港称为士多啤梨。'),
('西瓜', 'watermelon.png', '西瓜古称寒瓜,是葫芦科西瓜属的一种植物或其果实。原产于非洲,是一种双子叶开花植物,形状像蔓藤,叶子呈羽毛状。它所结出的果实是假果,且属于植物学家称为瓠果的一类。果实外皮光滑,呈绿色或黄色及有深绿色的花纹,果瓤多汁为红色或黄色,内有籽。');
alter table tb_fruit add column frt_favs int not null default 0;
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>首页</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
width: 80%;
margin: 0 auto;
}
h1 {
border-bottom: 1px darkgray solid;
}
a {
text-decoration: none;
}
.del {
margin-left: 100px;
color: darkgreen;
}
.export {
position: absolute;
top: 10px;
right: 150px;
width: 90px;
height: 30px;
text-align: center;
line-height: 30px;
font-size: 12px;
color: white;
background-color: darkgreen;
}
.name {
font: bold 20px Arial;
}
.favs {
position: relative;
top: -8px;
left: 12px;
}
.fruits > li {
border-bottom: 1px lightgray dashed;
margin: 10px 0 20px 0;
list-style: none;
}
.fruits > li > img {
vertical-align: middle;
}
</style>
</head>
<body>
<h1>水果清单</h1>
<a class="export" href="/export">导出数据</a>
<div id="app">
<ul class="fruits">
<li v-for="fruit in fruits">
<img :src="'/static/' + fruit.image" width="32">
<span class="name">{{ fruit.name }}</span>
<a class="del" href="" @click.prevent="removeItem(fruit)">删除</a>
<p>{{ fruit.intro }}</p>
<a class="like" href="" @click.prevent="likeItem(fruit)">
<img src="/static/like.png" width="32">
</a>
<span class="favs">{{ fruit.favs }}</span>
</li>
</ul>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
fruits: []
},
created() {
fetch('/api/fruits').then(resp => resp.json()).then(json => {
this.fruits = json.fruits
})
},
methods: {
removeItem(fruit) {
fetch('/api/delete?id=' + fruit.id).then(resp => resp.json()).then(json => {
if (json.code === 10000) {
let pos = this.fruits.indexOf(fruit)
this.fruits.splice(pos, 1)
}
})
},
likeItem(fruit) {
fetch('/api/like?id=' + fruit.id).then(resp => resp.json()).then(json => {
if (json.code === 10000) {
fruit.favs += 1
}
})
}
}
})
</script>
</body>
</html>
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript</title>
<style>
h3 {
color: red;
font-size: 1cm;
text-align: center;
font-family: Consolas;
}
</style>
</head>
<body>
<h3 class="foo">Hello</h3>
<button onclick="calc()">确定</button>
<button onclick="quit()">删除</button>
<script>
function quit() {
if (window.confirm('关闭浏览器窗口?')) {
window.close()
}
}
function calc() {
let total = 0
for (let i = 1; i <= 100; i += 1) {
total += i
}
let h3 = document.querySelector('.foo')
h3.textContent = total
h3.style.color = 'blue'
}
</script>
</body>
</html>
vuedemo.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<title>VUE入门</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="fruit in fruits">
{{ fruit.name }} {{ fruit.quantity }}
<span v-if="fruit.quantity == 0"> --- 缺货</span>
<button @click="addten(ftuit)">添加</button>
</li>
</ul>
<p>总数量:{{ total }}</p>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
fruits: [{id:1, name: '苹果', quantity:50},
{id:2, name: '火龙果', quantity:50},
{id:3, name: '苹果', quantity:50},
]
},
computed:{
total(){
return this.fruits.ruduce((result, fruit) => result + fruit.quantity, 0)
}
})
</script>
</body>
</html>
约定大于配置
import io
from urllib.parse import quote
import flask
import openpyxl
import pymysql
from flask import make_response, request, redirect
from flask_cors import CORS
app = flask.Flask(__name__)
CORS(app)
@app.route('/')
def show_index():
return redirect('/templates/index.html')
conn = pymysql.Connect(host='localhost', port=3306,
user='root', password='root',
database='myapp', charset='utf8mb4')
@app.route('/api/fruits')
def get_fruits():
try:
with conn.cursor(pymysql.cursors.DictCursor) as cursor:
cursor.execute('select frt_id as id, frt_name as name, frt_image as image, '
'frt_intro as intro, frt_favs as favs from tb_fruit')
fruits = cursor.fetchall()
result = {'code': 10000, 'fruits': fruits}
except pymysql.MySQLError as err:
print(err)
result = {'code': 10001, 'fruits': []}
finally:
conn.close()
return result
@app.route('/export')
def export_excel():
wb = openpyxl.Workbook()
sheet = wb.active
sheet.append(('编号', '水果名称', '水果介绍', '点赞数'))
try:
with conn.cursor() as cursor:
cursor.execute('select frt_id, frt_name, frt_intro, frt_favs from tb_fruit')
row_data = cursor.fetchone()
while row_data:
sheet.append(row_data)
row_data = cursor.fetchone()
except pymysql.MySQLError as err:
print(err)
finally:
conn.close()
buffer = io.BytesIO()
wb.save(buffer)
resp = make_response(buffer.getvalue())
resp.headers['content-type'] = 'application/vnd.ms-excel'
filename = quote('水果清单.xlsx')
resp.headers['content-disposition'] = f'attachment; filename="{filename}"'
return resp
@app.route('/api/delete')
def delete_fruit():
fruit_id = request.args.get('id')
try:
with conn.cursor() as cursor:
cursor.execute('delete from tb_fruit where frt_id=%s', (fruit_id, ))
conn.commit()
hint = {'code': 10000, 'message': '操作成功'}
except pymysql.MySQLError as err:
print(err)
hint = {'code': 10001, 'message': '操作失败'}
conn.rollback()
return hint
@app.route('/api/like')
def like_fruit():
fruit_id = request.args.get('id')
try:
with conn.cursor() as cursor:
cursor.execute(
'update tb_fruit set frt_favs=frt_favs+1 where frt_id=%s',
(fruit_id, )
)
conn.commit()
hint = {'code': 10000, 'message': '操作成功'}
except pymysql.MySQLError as err:
print(err)
hint = {'code': 10001, 'message': '操作失败'}
conn.rollback()
return hint
if __name__ == '__main__':
app.run(host='localhost', port=8000, debug=True)
conn.close()
第三方库Flask的安装
终端执行pip install flask即可
import flask
app = flask.Flask(__name__)
@app.route('/')
def index():
return '<h1>Hello Flask!</h1>'
if __name__ == '__main__':
app.run(host='10.7.178.89'(本机IP), port=8000, debug=True)
运行上述代码即可获取到该页面URL,点击打开可以看到前端页面的‘Hello Flask’