日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Web请求原理

發布時間:2025/3/20 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Web请求原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

1.web請求/響應解析

2.url靜態響應

3.url動態響應

4.連接數據庫

5.使用jinja2優化


1.web請求/響應解析

web的原理,服務端處理監聽狀態,監聽到該ip端口有請求了,根據請求信息返回對應的響應,比如在百度中搜索python教程,百度會無端監聽到之后,進行響應。常用的socket編程就是這樣的過程

web瀏覽器(socket客戶端):

  • 創建socket對象
  • 連接
  • 發送請求
  • 接收請求
  • 斷開連接

百度服務器(socket服務端):

  • 監聽斷開和ip
  • while Trure:

? ? ? ? 等待用戶連接

? ? ? ? 收到用戶請求

? ? ? ?響應

? ? ? ?斷開連接

當然實際的過程要比這個復雜很多,但是基本的過程原理是這樣,因此先模擬以上的過程

#encoding:utf-8import socketsock = socket.socket() sock.bind(('127.0.0.1',8080)) sock.listen(5)while True:conn, addr = sock.accept();# 獲取用戶發送的數據data = conn.recv(8096)print(data)conn.send(b'response')conn.close()

運行之后打開瀏覽器,輸入127.0.0.1:8080展示結果如下:

因為是http請求,知道請求包括三個部分:請求行,請求頭,body三個部分,那按照http請求那樣發送/響應按照http個要求來處理消息的請求和響應。在上面的代碼中打印出來了客戶的請求消息如下:

GET / HTTP/1.1 Host: 127.0.0.1:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate DNT: 1 Connection: keep-alive Upgrade-Insecure-Requests: 1 Cache-Control: max-age=0

抓包看一下實際的請求和響應的格式如下:

響應這里:響應行,響應頭,響應體。響應體這里是一個html的字符串,因為瀏覽器認識這個html字符串并把它變成對普通人更友好的界面進行了展示

注意:請求頭和請求體,響應頭和響應體之間均有一個空白行作為分隔

因為在上述的腳本中只響應了response字符串,沒有按照人家的這個規則進行回復,所以寫的這個東西不規范。因此模擬上述的格式進行請求和響應

#encoding:utf-8import socketsock = socket.socket() sock.bind(('127.0.0.1',8080)) sock.listen(5)while True:conn, addr = sock.accept();# 獲取用戶發送的數據data = conn.recv(8096)print(data)# 返回一個響應頭conn.send(b'HTTP/1.1 200 OK\r\n\r\n')conn.send(b'response')conn.close()

那現在在響應的格式上已經逐步靠近實際的web請求

2.url靜態響應

url的全稱是統一資源定位符,就是通俗的理解像是在自己的PC上的找文件的路徑,得到路徑之后在搜索欄位輸入就會定位到對應的資源,那web也是一樣,訪問不同的url得到不同的響應

響應的報文格式如下:

?

那這里的請求的路徑就是/,所以可以先獲取到請求的路徑,再根據路徑去響應,因為不同的請求路徑意味著客戶端請求的內容不同,因此如何獲取url是現在的工作重點

注意:請求行使用空格進行分割,請求頭中使用:進行分割,請求頭和請求體使用空白行進行分割

#encoding:utf-8import socketsock = socket.socket() sock.bind(('127.0.0.1',8080)) sock.listen(5)while True:conn, addr = sock.accept();# 獲取用戶發送的數據data = conn.recv(8096)data = str(data)headers, bodys = data.split('\r\n\r\n')temp_list = headers.split("\r\n")method, url, protocal = temp_list[0].split(' ')# 返回一個響應頭conn.send(b'HTTP/1.1 200 OK\r\n\r\n')if url == "/xxx":conn.send(b'response')else:conn.send(b'404 not found')conn.close()

運行之后,在瀏覽器中重寫請求

如果是/xxx會判斷等于url,則返回響應response,如果是其他請求,則返回404。因為url有無數個對應著有無數個響應,因此將url提出來。因此做如下改動:

  • 不同的url給出不同的響應結果,
  • 將上述代碼放在一個函數中,方便管理,因為可能越寫越長
  • #encoding:utf-8 import socketdef f1():return "f1" def f2():return b"f2"routers = [('/xxx',f1),('/ooo',f2) ]def run():# 創建socket對象sock = socket.socket();sock.bind(('127.0.0.1',8080))sock.listen(5)while True:conn,addr = sock.accept();# 獲取用戶發送的數據data= conn.recv(8096)data = str(data)headers,bodys = data.split('\r\n\r\n')temp_list = headers.split("\r\n")method,url,protocal = temp_list[0].split(' ')conn.send(b'HTTP/1.1 200 OK\r\n\r\n')func_Name = Nonefor item in routers:if item[0] == url:func_Name = item[1]breakif func_Name:response = func_Name()else:response = b'404'conn.send(response)conn.close()if __name__ == '__main__':run()

    運行查看結果

    ?

    現在是不是有點像平時訪問的web請求的了,不同的請求給出不同的響應。但是這個界面太丑了,能不能像平時一樣展示的稍微好看點,在之前提到說普通的響應返回的是html字符串,那這里也模仿返回一個html字符串,那最常見的就是登陸界面,對應的還是在f1和f2給不同的html響應

    index.html

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><h1>用戶登錄</h1><form><p><input type="text" placeholder="用戶名" /></p><p><input type="password" placeholder="密碼" /></p></form> </body> </html>

    table.html

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><table border="1"><thead><tr><th>ID</th><th>用戶名</th><th>郵箱</th></tr></thead><tbody><tr><th>admin</th><th>root</th><th>admin@qq.com</th></tr></tbody></table> </body> </html>

    對應的將之前的f1和f2中返回的結果用這個文件替代,因為瀏覽器認識html,看看瀏覽器給最終展示的結果如何

    #encoding:utf-8 import socketdef f1(request):"""處理用戶的請求并返回相應的內容:request:用戶請求的所有信息:return:"""f = open('index.html','rb')data = f.read()f.close()return data# return "f1" def f2(request):"""處理用戶的請求并返回相應的內容:request:return:"""f = open('table.html','rb')data = f.read()f.close()return data# return b"f2"routers = [('/xxx',f1),('/ooo',f2) ]def run():# 創建socket對象sock = socket.socket();sock.bind(('127.0.0.1',8080))sock.listen(5)while True:conn,addr = sock.accept();# 獲取用戶發送的數據data= conn.recv(8096)data = str(data)headers,bodys = data.split('\r\n\r\n')temp_list = headers.split("\r\n")method,url,protocal = temp_list[0].split(' ')conn.send(b'HTTP/1.1 200 OK\r\n\r\n')func_Name = Nonefor item in routers:if item[0] == url:func_Name = item[1]breakif func_Name:response = func_Name(data)else:response = b'404'conn.send(response)conn.close()if __name__ == '__main__':run()

    重新運行代碼,并在瀏覽器上進行范圍

    這個網站只有兩個地址,/xxx和/ooo,所以這個網站就寫完了,就這樣像普通的其他的網站一樣訪問。那因為從界面還是底層代碼中不難發現,這個界面展示一直是不變的,即所謂的“靜態網站”,但實際上我們常常訪問的是動態的網站,那數據動態數據當然是從數據庫中獲取的。在上面的index和table的讀取過程中,定義的是html類型,因為是讀取自己定義的文件,所以當然也可以是txt格式,或者任意其他格式了。

    3.url動態響應

    比如在上述的table中用戶名root定義為位當前時間,這樣的話時間一直持續變化的,不斷的刷新就會返回不同的響應的結果,這樣就簡單的實現了動態響應

    def f2(request):"""處理用戶的請求并返回相應的內容:request:return:"""f = open('table.html','r')data = f.read()f.close()import timectime = time.time()data = data.replace("root",str(ctime))data = bytes(data)return data# return b"f2"

    輸出結果如下:

    這是不是就是使用table這個模板展示了不同的“用戶”信息。所以這個html的角色:模板

    那如果這里的用戶名不使用這個時間戳,而是使用數據庫中的數據這樣就是真正的實際使用,那假設現在數據庫有10個數據,需要從數據庫中讀取出來這10個數據進行展示。關于本地mysql的安裝可以在官方網站下載。

    4.連接數據庫

    本地安裝pymsyql,并創建數據庫/表,本地如下所示

    現在接著第3節中的顯示的信息,這里使用mysql數據庫中的數據進行展示

    同樣創建一個userlist.html

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><table border="1"><thead><tr><th>ID</th><th>username</th><th>mail</th></tr></thead><tbody>@@content@@</tbody></table> </body> </html>

    要做的就是把tbody中的@@content@@替換為數據庫中的數據

    def f3(request):import pymysql# 創建連接conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='pgtuser')# 創建游標# 游標設置為字典類型cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)# 執行SQL,并返回收影響行數effect_row = cursor.execute("select id,username,password from userinfo")userlist = cursor.fetchall()# 關閉游標cursor.close()# 關閉連接conn.close()# print(userlist)contentlist = []for row in userlist:tp ="<tr><th>%s</th><th>%s</th><th>%s</th></tr>" %(row['id'],row['username'],row['password'])contentlist.append(tp)content = "".join(contentlist)f = open('userlist.html','r',encoding='utf-8')template = f.read()f.close()data = template.replace('@@content@@',content)return bytes(data,encoding='utf-8')routers = [('/xxx',f1),('/ooo',f2),('/userlist.htm',f3), ]

    展示的結果如下

    那這里的語句,將數據庫中的數據在userlist.html中替換的過程就是渲染,即數據+模板,所謂的模板就是這里的html

    data = template.replace('@@content@@',content)

    5.使用jinja2優化

    在第4章中使用字符串替換非常麻煩,字符串寫一堆處理,其實這個還有一個別人寫好的東西可以直接操作就是jina2

    在jinja2中,存在三種語法:

  • 控制結構 {% %}
  • 變量取值 {{ }}
  • 注釋 {# #}
  • {%?for?user in users %}

    <li>{{ user.username|title }}</li>

    {% endfor %}

  • 這里新增一個host.html,如下

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><table border="1"><thead><tr><th>ID</th><th>username</th><th>mail</th></tr></thead><tbody>{% for row in user_list %}<tr><td>{row.id}</td><td>{row.username}</td><td>{row.password}</td></tr>{% endfo %}</tbody></table> </body> </html>

    新增一個f4的函數

    def f4(request):import pymysql# 創建連接conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='pgtuser')# 創建游標# 游標設置為字典類型cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)# 執行SQL,并返回收影響行數effect_row = cursor.execute("select id,username,password from userinfo")userlist = cursor.fetchall()# 關閉游標cursor.close()# 關閉連接conn.close()f = open('hostlist.html','r',encoding='utf-8')data = f.read()f.close()from jinja2 import Templatetemplate = Template(data)data = template.render(user_list=userlist)print(data)return data.encode('utf-8')routers = [('/xxx',f1),('/ooo',f2),('/userlist.htm',f3),('/host.html',f4) ]

    那這里jinjia2所做的事情就是使用第三方工具做的渲染

    結合剛在我們開發的這個“網站”總結歸納下:

  • socket服務端
  • 根據Url不同返回不同的響應 (即所謂的路由系統,utl -> 函數)
  • 字符串返回給用戶(模板引擎渲染,HTML充當模板)
  • 針對以上的流程,常見的web框架種類有:

  • 1,2,3? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?------->Tornado? ? ? ? ? ? ? ? ? ?
  • [使用第三方的a],b,c? ? ? ? ? ? ? ? ? ? ? ? -------> [wsgiref] ->Django
  • [使用第三方的a],b,[使用第三方的c] -------> flask
  • ?

    總結

    以上是生活随笔為你收集整理的Web请求原理的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。