1. 程式人生 > >部落格開發簡記(3):從頁面到後端結構的部署

部落格開發簡記(3):從頁面到後端結構的部署

既然已經可以訪問django,那我們就可以搞點事情了哦,至少來個helloworld吧。

(一)helloworld

有兩個基本的知識點:

  1. 在瀏覽器發起一個請求(get),去到django,django呼叫urls.py來解析地址或引數,所以你可以改成urls.py,來決定對不同的引數作出不同的函式處理。
  2. 如果返回一個HttpResponse給瀏覽器,那瀏覽器就可以看到展示,所以HttpResponse可以是一個頁面。

基於這兩個知識點,我們就改一下urls.py,在請求主頁面時,呼叫一個函式,並且讓這個函式返回helloworld的內容。

urls.py的主要內容如下:

from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from django.http import HttpResponse

def dosomething(request):
    return HttpResponse('<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>你好</title><body>hello world 喂世界 nihao</body><head></html>')

urlpatterns = [
    #path('admin/', admin.site.urls),
    url(r'^$', dosomething)
]

這裡定義一個dosomething的函式,注意這個函式是帶一個引數的,因為django會傳遞request給它。然後dosomething返回了一個HttpResponse物件,裡面就是一些簡單的文字了。

./manage.py runserver啟動django後,在瀏覽器請求一下,可以看到這樣的效果:

這就是一個簡單的helloworld程式,太好改了吧。但這裡有個問題,上面那段python程式碼,裡面出現一段html,有什麼問題嗎?html標識的是一個介面,比如用什麼標題、用什麼字型、用幾號大小,等等,這是介面設計的東西,而把介面設計跟程式碼邏輯或業務邏輯混在一起,除非你能容忍混亂而且不影響開發效率,否則介面跟程式碼邏輯就要分開。那介面提到哪裡去呢,就是模板了,就是一個html檔案,這裡演示一下。

先mkdir建立一個templates資料夾,以後就放html檔案了,然後建立一個main.html,這樣設計這個介面(好簡單!):

<h1>hello,{{yourname}}</h1>

{{yourname}}表示引用一個變數,變數名叫yourname,注意要用雙符號來引用變數。在介面中使用變數,這太尋常了,那變數的定義還有值從哪裡來的?就是業務邏輯給的呀,這就是介面與邏輯分離的表現,即介面使用邏輯給的變數值,邏輯給介面提供資料。

好了,然後,自然是要在程式碼中定義這個yourname變量了,而且程式碼中要展示這個html,程式碼如下:

from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from django.shortcuts import render

def dosomething(request):
    dict = {}
    dict['yourname'] = '廣州小程'
    return render(request, 'main.html', dict)

urlpatterns = [
    #path('admin/', admin.site.urls),
    url(r'^$', dosomething)
]

在接到請求時,還是呼叫dosomething函式,然後返回一個render,看名字就知道是要渲染繪製一個介面出來,這個介面是什麼呢?就是第二個引數指定的main.html,然後第三個引數就是傳遞給介面的資料,它是一個鍵值對集,明顯,一定要包括yourname這個變數,而且事先給了變數值。

最後要注意一個路徑的問題,就是render怎麼找到main.html的問題,這個要在settings.py中進行設定,然後來看一下現在的目錄結構:

按這個結構,要指定的路徑就是:專案目錄+/myblog/templates

在settings.py中找到 TEMPLATES 這個dict,然後把DIRS的值改成這樣:

'DIRS': [BASE_DIR+'/myblog/templates',],

ok,一切就緒,瀏覽器請求一下,看到這樣的效果:

好了,介面你也知道怎麼寫了,不就是寫html嘛。但是,我要的部落格可沒有這麼簡單,需要一步步來開發嗎?

在你做一個事情,特別是一個常見的事情之前,看看別人是怎麼做的,或許能大大節省你的時間成本。於是,你會發現,部落格這種日常操作,在github上有大量的專案。

(二)部落格專案

於是,這裡我直接使用這個專案:https://github.com/liangliangyy/DjangoBlog

按這個地址的介紹來部署即可:https://www.lylinux.net/article/2019/8/5/58.html

這裡有個知識點,為什麼有了djangoblog,還要用到nginx跟gunicorn呢?它們是什麼關係呢?

djangoblog,簡單來說就是一個web應用,也可以說是一個web框架。作為一個應用,djangoblog當然可以runserver起來並且佔用80埠等,然後瀏覽器就可以訪問到他。但是,在實際資料互動的場景中,讓web應用把負載均衡、高併發之類的事情也做了,是不合適的,應用只應該做自己的業務。所以,還需要一個重要的角色,這個角色就是web伺服器,而nginx就是一個web伺服器,瀏覽器的所有請求先到達nginx,nginx先做一些前置的處理(比如靜態頁面攔截、負載平衡之類),但是,由於nginx不懂業務啊,所以它還是要呼叫到djangoblog(web框架或應用),但這個呼叫不是直接的呼叫,而是經過中介軟體,比如gunicorn。gunicorn或wsgi(閘道器介面),解決了nginx與django互動的問題,因為web伺服器與web框架的通訊,要遵守一種協議,而gunicorn正是實現了這種協議。實際上,gunicorn本身也能做為web伺服器(類似於nginx),但因能力有限,一般會把這個角色讓位於nginx等。所以,簡單來說,一種常見的後端結構就是:nginx+gunicorn+django。

另外,由於gunicorn支援nginx與django的通訊,不可或缺,如果它退出了,有必要即刻啟動起來,於是引入supervisor。supervisor監控gunicorn,保證後者的拉起,而且後者以子程序掛在supervisor程序內。於是這個結構也可以說是:nginx+supervisor+gunicorn+django。

最終用瀏覽器訪問,一個網站就出來了:

(三)後端知識

補充一些知識點。

(a)supervisor與gunicorn
supervisor是監控並管理gunicorn的,如果你想停止gunicorn,你只需要把對應的supervisor服務給stop掉就可以了,gunicorn程序會自動停止。

用這個命令先看一下supervisor監控了哪些服務:

supervisorctl status

然後就可以停止這個服務:

supervisorctl stop 服務名

這時服務對應的gunicorn會自動停止,用lsof -i:8000不再看到程序。 對應於stop,還有start、reload。

當然,如果想直接kill掉gunicorn程序,也可以,先找到它的根pid:

pstree -ap|grep gunicorn

再kill掉:

kill -9 pid

但是,如果supervisor是執行狀態,kill掉的gunicorn即刻就會被拉起,一個新的pid的gunicorn又會出現。

(b)supervisor的配置
諸多key-value的配置選項,請自行搜尋瞭解,這裡簡單說兩個。

command,就是supervisor要執行的命令,比如執行某個程式或指令碼,比如執行一句python語句等等,涉及到的檔案,你可以寫完整路徑,如果寫相對路徑則要組合directory這個選項。

directory,在執行command之前,先cd到這個目錄,看情況使用(也可不用)。

(c)supervisor的日誌
如果遇到supervisor有什麼異常而你一時想不出原因,這時看一下它的日誌輸出(包括你故意print出來的日誌--因為supervisor是python程式所以你當然可以print),也許能幫到你,那日誌在哪裡呢? 預設在/var/log/supervisor目錄下面。如果在配置supervisor時指定了標準輸出路徑,比如stdout_logfile欄位,那就多了一個日誌。對於分析問題,這兩個日誌都應該關注。

(d)supervisor的程序關係
這樣檢視supervisor的程序關係:

service supervisor status

如果已經設定好supervisor的配置,比如指定啟動gunicorn,那就可以看到在supervisor程序下面掛上了gunicorn程序(一般兩個,一主一從)。

(e)nginx的配置
nginx的所有配置都在:/etc/nginx 目錄,而你新增加的配置應該放在 /etc/nginx/sites-enabled 目錄下,這個目錄已經有一個叫default的預設配置檔案,你的新配置可以任意命名,都將替代default配置,但你需要重新啟動nginx。

可以這樣重啟nginx:

service nginx reload/restart 或:
/etc/init.d/nginx reload

如果不放心,也可以先stop(瀏覽器請求一下)再start:

service nginx stop
service nginx start

注意,nginx明明stop掉了,用ps也看不到程序了,這時瀏覽器再請求可能還是看到頁面,這可能是瀏覽器端的快取。

配置中的error_log欄位,指定了nginx出錯時的記錄檔案,這個檔案可以幫助你分析nginx的錯誤。預設不設定這個欄位的情況下,錯誤日誌檔案是/var/log/nginx/error.log。

如果只是想驗證nginx是否可以正常使用,可以寫一個最簡單的配置,比如這樣:

server {
        listen 80;
        server_name www.freep2p.cn;
        root /root/python;
    }

然後在/root/python目錄建立一個index.html檔案,比如檔案內容可以這麼簡單:

<html><p2>hello world</p2></html> 

重啟nginx後用 www.freep2p.cn 訪問它,就可以看到hello world。

對於nginx的執行情況,可以用下面的命令來檢視:

systemctl status nginx.service

(f)定位問題的一個關鍵
層級一多,問題定位就變得複雜。除了考慮去除層級,比如直接手動呼叫gunicorn不經supervisor等,這個辦法有效外,還有一個關鍵的點,就是分析日誌。

有兩個日誌要上心,一個是nginx的輸出日誌(在配置中有寫,或者使用預設的路徑即/var/log/nginx/error.log),另一個是supervisor的輸出日誌(如上介紹,有兩個),supervisor的日誌,包括了supervisor跟gunicorn的表現,還有請求應答的情況。

(g)可能遇到的問題

(1)Internal Server Error
對於nginx,如果提示“Internal Server Error”,是什麼原因呢? 這個提示(對應錯誤碼是500),意思是服務內部出問題了,但至少說明,你訪問到nginx了,只是觸發了錯誤。對於這裡的結構,nginx是要呼叫supervisor+gunicorn的,而gunicorn要呼叫djangoblog框架,是哪一步出了問題呢?

用lsof -i:8000,可以看到gunicorn已經執行起來了,而nginx的配置相對是簡單的,不太像會出問題,那gunicorn到djangoblog那一步怎麼樣?gunicorn的配置是不是有問題呢?

先把supervisor停止掉,按上面介紹的命令即可做到,supervisor給stop掉後,gunicorn也會自動結束(lsof -i:8000看不到程序),如果這時用瀏覽器請求一下,會看到這樣的提示:

502 Bad Gateway

也就是閘道器接口出問題了,而實際就是gunicorn給停止了。

嘗試用最簡單的nginx的配置,能正常訪問,所以排除是nginx的問題。

先把supervisor給stop掉,也就是不使用supervisor來啟用gunicorn,而是直接執行gunicorn_start.sh指令碼,再訪問nginx,發現,正常了!。

所以,從gunicorn到djangoblog沒有問題,問題出在supervisor啟用gunicorn引入了問題。

從理論來看,按這裡使用的supervisor的配置,supervisor解釋執行指令碼(不一定用bash),再以exec命令啟動gunicorn,而exec的意思就是不另起程序,而是使用當前程序,只要gunicorn不退出(本意就是不退出的),那麼當前程序宣告的變數以及用source切換至python虛擬環境就是生效的,不用懷疑source不生效。

這時,一定要分析日誌。 在supervisor的標準輸出/var/log/djangoblog.log中,可以看到這樣的提示:

也就是找不到HOST變數!

根據上面的提示,這個是database的設定,程式碼如下圖:

也就是os.environ.get不到環境變數。

手動執行sh指令碼,相當在shell中互動執行,實際是bash程序啟動了gunicorn,而supervisor是python程式,它解釋sh指令碼啟動了gunicorn,這兩種方式是不同的,至少bash跟supervisor使用的環境變數的配置就不同,這個下面就來證明。

先來測試一下supervisor當前的環境變數吧。

把supervisor執行的命令設定一下:

command=python3 -c "import os; print(os.environ)"

然後:

tail -10 /var/log/djangoblog.log

你可以看到已經有一些變量了,但是,沒有程式碼裡面的那三個變數,因為還沒有設定(設定到~/.bashrc中是無效的)。這樣設定到supervisor,同樣是在supervisor的配置中修改:

environment = DJANGO_MYSQL_USER='root',DJANGO_MYSQL_PASSWORD='xxx',...

也就是增加environment欄位,值就是新增的環境變數,以逗號分隔。

再啟supervisor,這個問題就得到解決。

(2)403 forbidden
如果error的log提示,“xxx” is forbidden,一個可能是在這個目錄下面找不到index.html。


總結一下,本文介紹了怎麼簡單寫helloworld介面,怎麼使用開源的部落格專案,也重點介紹了後端的知識點。

至此,解決了後端結構的部署問題,網站框架也好了,接下來就是頁面個性化類的問題了。

相關推薦

部落開發簡記3頁面結構部署

既然已經可以訪問django,那我們就可以搞點事情了哦,至少來個helloworld吧。 (一)helloworld 有兩個基本的知識點: 在瀏覽器發起一個請求(get),去到django,django呼叫urls.py來解析地址或引數,所以你可以改成urls.py,來決定對不同的引數作出不同的函式處理。

部落開發簡記2部落找個域名

承接上一節,給ubuntu上的django更新一下: ./manage.py migrate 好了,我連公網ip都有了,我可不想每次都以ip來訪問我的網站,那怎麼弄一個域名呢? (一)申請域名 不必研來研去了,直接在阿里雲提供的服務中購買域名吧,但在下單前,你先要完成域名的資訊模板的稽核,意思是,你要填完

Python開發環境3使用Eclipse+PyDev插件創建Django項目

ffffff postgresq 項目上線 右鍵 ont pat iat ngs ora OS:Windows 10家庭中文版,Python:3.6,Eclipse:Oxygen.1a Release (4.7.1a), PyDev:6.3.2,Django:2.0.3

iOS開發簡記1指定APP的圖標與啟動圖

appstore 技術分享 tps http data 對象 暫時 -c 系統 各位兄弟姐妹們,早上好,本人花了將近一個月的時間打造了一個完整的IOS版的App, 期間包括開發,測試,上線審核,現在花點時間把實現的過程分享給大家,“知音”app功能簡單,適合對象為初學者,後

iOS開發簡記2自定義tabbar

tabbar是放在APP底部的控制元件。常見的APP都使用tabbar來進行功能分類的管理,比如微信、QQ等等。 小程需要一個特殊一點的tabbar,要求突顯中間的那個按鈕,讓中間按鈕特別顯眼,從而引導使用者去點選。 所以,讓中間按鈕大於兩邊的按鈕,是一個基本的要求。 使用常規的UITabBar跟UIT

iOS開發簡記4錄音AVAudioRecorder

fail pst 記錄 通道 cdn amp enabled 廣州 指定 錄音,聲音的采集,一般有兩種實現辦法,一是使用AVAudioRecorder,一是使用AudioUnit。如果只是簡單的錄音,使用AVAudioRecorder就可以了,如果想更靈活地處理剛錄到的聲音

iOS開發簡記7網絡請求模塊

pin 註意 sea fmt 項目介紹 get img 做了 控制 主流的APP都少不了跟服務器交互,網絡請求是少不了的事情。 開源的網絡請求庫,有很多,比如:AFNetworking、YTKNetwork、PPNetworkHelper、ASIHttpRequest,等等

iOS開發簡記8資料持久化

資料持久化,也就是把資料儲存到磁碟,以後可以再讀取出來使用(也可以再次更改或刪除)。很多場景需要資料持久化,比如為了減輕伺服器的訪問與儲存壓力,客戶端需要在本地做一些資料持久化的工作。 iOS的資料持久化,有幾種方式,包括:自定義格式的檔案、plist、CoreData、FMDB等等。 這裡

iOS開發簡記9APPStore審核

oci HERE format call 並不會 如果 rod creates 3.1.1 "覓知音"這個APP的第一個版本從提交審核到上架,歷時三個星期,其中遇到一些審核上的問題,它的處理或許能幫助到遇到同樣問題的小夥伴們,所以這裏列舉出來,這三個星期

iOS開發簡記9APPStore稽核

"覓知音"這個APP的第一個版本從提交稽核到上架,歷時三個星期,其中遇到一些稽核上的問題,它的處理或許能幫助到遇到同樣問題的小夥伴們,所以這裡列舉出來,這三個星期如何跟蘋果的稽核團隊“鬥智鬥勇”。 (1)Guideline 2.1 - Information Needed 這是問題的標題,問

Python2語法簡記3運算子

3 運算子 支援運算子:算術、比較、賦值、邏輯、位、成員、身份 算術運算子 比較(關係)運算子 賦值運算子 邏輯運算子 位運算子 成員運算子 身份運算子 算術運算子:+,-,*,/,%,**冪,//取整數 加+、減-、乘*、除/、取模% 冪** -返回x的

iOS開發簡記1指定APP的圖示與啟動圖

各位兄弟姐妹們,早上好,本人花了將近一個月的時間打造了一個完整的IOS版的App, 期間包括開發,測試,上線稽核,現在花點時間把實現的過程分享給大家,“知音”app功能簡單,適合物件為初學者,後面我會把iOS客戶端原始碼、API介面原始碼“呈獻”給大家,謝謝大家的支援, 歡迎園友一起交流一起學習,廢話少說,裝

iOS開發簡記6storyboard的使用

從xib到storyboard,iOS介面開發的方式在變化。 這裡記錄怎麼使用storyboard來完成簡單的介面開發,比如實現一個“我”的簡單介面。 (1)新建storyboard 在新建檔案嚮導中,選擇storyboard並命名即可。 (2)拉入viewcontroller storyboard以vc為載

iOS開發簡記7網路請求模組

主流的APP都少不了跟伺服器互動,網路請求是少不了的事情。 開源的網路請求庫,有很多,比如:AFNetworking、YTKNetwork、PPNetworkHelper、ASIHttpRequest,等等。 這裡記錄AFNetworking的使用。 (1)安裝afnetworking 跟使用QMUIKit一

部落園裝飾——滾動到頁面頂部或底部

# 部落格園裝飾——(二)滾動到頁面頂部或底部 ## 一、功能描述 ### 1.1 文字描述 1. 當頁面向下滾動一定距離時,**向下滾動到底部**的按鈕以**淡入**的效果出現,並以**固定定位**顯示。且滾動到一定距離**(快接近所設定的底部)**時,該按鈕又會以**淡出**效果消失。 2. 當頁

【視訊】Kubernetes1.12零開始程式碼編譯到自動部署

作者: 李佶澳   轉載請保留:原文地址   釋出時間:2018/11/10 16:14:00 說明 kubefromscratch-ansible和kubefromscratch介紹 使用前準備

Windows Phone開發3棋子未動,先觀全局

csdn xaml hone activate 處理程序 為什麽 作業 單擊 不執行 在進行WP開發之前,與其它開發技術一樣,我們需要簡單了解一個WP應用序的生命周期,我們不一定要深入了解,但至少要知道在應用程序生命周期內的每一階段,我們應當做什麽,不推薦哪些操作等,這也是

grpc3使用 golang 開發 grpc 服務和client

ava 相互調用 相互 localhost rpcclient int err pri nec 1,關於grpc-go golang 能夠能夠做grpc的服務端

最佳實踐3Windows應用開發

這是Futurice公司的Windows 8.x 和 Windows Phone 8.x 應用開發者的經驗教訓。通過參考這些指南能夠避免重複造輪子。如果你對iOS或者Android開發感興趣,一定也要去看一下他們的《iOS開發最佳實踐》和《安卓開發最佳實踐》。 歡迎

android開發3列表listview的實現 | 下拉刷新

imp 就是 觸發 能夠 希望 封裝 介紹 組成 ctu APP裏面的列表太常用了,系統提供的listview或grideview可以做到。另外,我希望這個列表能夠下拉時觸發刷新,於是考慮使用封裝了這個功能的開源項目,這裏介紹這個:https://github.com/Ya