37. Uygulama alıştırması: sürüm 17

Bu yeni sürümde aşağıdaki değişiklikler yapılmıştır:
- Apache / Windows sunucusuna taşınacak;
- bu taşıma işlemini gerçekleştirmek için sürüm 17, ihtiyaç duyduğu tüm bağımlılıkları [impots / http-servers/ 12] klasöründe barındırmaktadır. Önceki sürümlerin bağımlılıklarını [python-flask-2020] projesinin farklı klasörlerinden aldığını hatırlatırız;
37.1. Uygulamanın bağımlılıklarının yeniden konumlandırılması

Uygulamanın bağımlılıklarının yönetimi, [syspath] komut dosyasında gerçekleştirilir. Önceki sürümde bu komut dosyası şu şekildeydi:
def configure(config: dict) -> dict:
import os
# bu dosyanın bulunduğu klasör
script_dir = os.path.dirname(os.path.abspath(__file__))
# kök dizin
root_dir = "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020"
# bağımlılıklar
absolute_dependencies = [
# proje klasörleri
# BaseEntity, MyException
f"{root_dir}/classes/02/entities",
# InterfaceImpôtsDao, InterfaceImpôtsMétier, InterfaceImpôtsUi
f"{root_dir}/impots/v04/interfaces",
# AbstractImpôtsdao, ImpôtsConsole, ImpôtsMétier
f"{root_dir}/impots/v04/services",
# ImpotsDaoWithAdminDataInDatabase
f"{root_dir}/impots/v05/services",
# AdminData, ImpôtsError, TaxPayer
f"{root_dir}/impots/v04/entities",
# Sabitler, dilimler
f"{root_dir}/impots/v05/entities",
# Günlük Kaydedici, SendAdminMail
f"{root_dir}/impots/http-servers/02/utilities",
# ana komut dosyası klasörü
script_dir,
# yapılandırmalar [database, layers, parameters, controllers, views]
f"{script_dir}/../configs",
# denetleyiciler
f"{script_dir}/../controllers",
# yanıtlar HTTP
f"{script_dir}/../responses",
# görünüm şablonları
f"{script_dir}/../models_for_views",
]
# syspath'ı ayarlıyoruz
from myutils import set_syspath
set_syspath(absolute_dependencies)
# yapılandırmayı geri yükleme
return {
"root_dir": root_dir,
"script_dir": script_dir
}
Mutlak adı 8. satırdaki [root_dir] değişkenine bağlı olan tüm bağımlılıkları, yani 13-26. satırları yeniden konumlandırmak gerekir.
Yeni sürümdeki [syspath] komut dosyası şu şekilde olacaktır:
def configure(config: dict) -> dict:
import os
# bu dosyanın klasörü
script_dir = os.path.dirname(os.path.abspath(__file__))
# bağımlılıklar
absolute_dependencies = [
# uygulama varlıklarını
f"{script_dir}/../entities",
# katman [dao]
f"{script_dir}/../layers/dao",
# katman [métier]
f"{script_dir}/../layers/métier",
# yardımcı programlar
f"{script_dir}/../utilities",
# ana komut dosyası klasörü
script_dir,
# yapılandırmalar [database, layers, parameters, controllers, views]
f"{script_dir}/../configs",
# denetleyiciler
f"{script_dir}/../controllers",
# yanıtlar HTTP
f"{script_dir}/../responses",
# görünüm şablonları
f"{script_dir}/../models_for_views",
]
# syspath ayarlanıyor
import sys
# projenin mutlak bağımlılıklarını ekleniyor
for directory in absolute_dependencies:
# klasörün varlığı kontrol ediliyor
existe = os.path.exists(directory) and os.path.isdir(directory)
if not existe:
# geliştiriciye uyarı verilir
raise BaseException(f"[set_syspath] le dossier du Python Path [{directory}] n'existe pas")
else:
# klasörü syspath'ın başına eklenir
sys.path.insert(0, directory)
# yapılandırma gerçekleştiriliyor
return {
"script_dir": script_dir,
}
- 8-27. satırlar: Artık tüm bağımlılıklar 5. satırdaki [script_dir] değişkenine göre belirlenmektedir;
- 42-45. satırlar: [root_dir] değişkeni syspath yapılandırmasından kaldırılmıştır;
- 10. satır: Uygulamanın bileşenleri [entities] [1] klasöründedir;
- 12. satır: [dao] katmanı, [layers/dao] ve [2] klasörlerinde yer almaktadır;
- 14. satır: [métier] katmanı, [layers/métier] ve [2] klasörlerinde yer almaktadır;
- 16. satır: [Logger, SendMail] yardımcı programları, [utilities] ve [3] klasörlerinde yer almaktadır;
- 29-40. satırlar: [myutils] modülünü içe aktarmadan uygulamanın Python Yolu hesaplanır;

37.2. Testler
Bu aşamada, sürüm 17'nin çalışması gerekir. Bunu kontrol edin.
37.3. Bir Python / Flask uygulamasının Apache / Windows sunucusuna taşınması
37.3.1. Kaynaklar
Bir Flask uygulamasını Apache / Windows'a taşımak için internette araştırma yapmak zorunda kaldım. İşte başlangıçta bana yardımcı olan bağlantı: [https://medium.com/@madumalt/flask-app-deployment-in-windows-apache-server-mod-wsgi-82e1cfeeb2ed];
Apache sunucusunun yapılandırması hariç, bu bağlantıdaki bilgileri kullandım. Yapılandırma için ise Laragon'un Apache sunucusu yapılandırma örneğini kullandım.
37.3.2. mod_wsgi Python modülünün kurulumu
Geliştirdiğimiz Python / Flask uygulaması, Flask ile birlikte gelen WSGI (Web Server Gateway Interface) [werkzeug] sunucusunu kullanıyordu. Bu sunucu |ici|'te açıklanmaktadır. [https://www.fullstackpython.com/wsgi-servers.html] bağlantısı, WSGI sunucularının çalışma şeklini açıklamaktadır. Farklı |serveurs WSGI| türleri mevcuttur. Bunlardan biri, WSGI modunda çalışan Apache sunucusudur. Burada bu çözüm benimsenmiştir çünkü kurduğumuz Laragon, bir Apache sunucusuyla birlikte gelir.
Apache sunucusunun bir Python uygulamasını barındırabilmesi için Python modülünü yüklememiz gerekir. Bu modülün kurulumu biraz zahmetlidir, çünkü kurulum sırasında bir C++ derlemesi gerçekleşir. Kurulumu başarıyla tamamlamak için bir Microsoft C++ derleyicisi gereklidir. Basit bir çözüm, Visual Studio Community'nin güncel sürümünü [https://visualstudio.microsoft.com/fr/vs/community/] olarak yüklemektir.
[mod_wsgi] dışında Visual Studio’ya ihtiyacınız yoksa, kurulumu C++ ortamıyla sınırlayabilirsiniz:

C++ derleyicisi kurulduktan sonra, [mod_wsgi] modülünün kurulumu PyCharm terminalinde gerçekleştirilir:
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\http-servers\11>SET MOD_WSGI_APACHE_ROOTDIR=C:\MyPrograms\laragon\bin\apache\httpd-2.4.35-win64-VC15
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\http-servers\11>pip install mod_wsgi
Collecting mod_wsgi
Using cached mod_wsgi-4.7.1.tar.gz (498 kB)
Using legacy setup.py install for mod-wsgi, since package 'wheel' is not installed.
Installing collected packages: mod-wsgi
Running setup.py install for mod-wsgi ... done
Successfully installed mod-wsgi-4.7.1
- 1. satır: [MOD_WSGI_APACHE_ROOTDIR] ortam değişkeninin değeri belirlenir. Bu değer, dosya sistemindeki Apache sunucusunun konumudur. Burada bu konum [<laragon>\bin\apache\httpd-2.4.35-win64-VC15]'tir; burada <laragon>, Laragon'un kurulum klasörüdür. Bu konumu çeşitli yollarla elde edebilirsiniz. Aşağıda, Laragon’un seçeneklerinden birini kullanarak elde edilen bir örnek verilmiştir:

[1-3] konumunda, [httpd.conf] dosyası Apache sunucusunun ana yapılandırma dosyasıdır. Söz konusu dosya bir metin düzenleyicide (aşağıda Notepad++) açılır:

[2]'te, Apache kurulum klasörü [conf\httpd.conf] dizesinin önündeki kısımdır.
[mod_wsgi] modülünün kurulumuna geri dönelim:
- 3-9. satırlar: [mod_wsgi] modülünün kurulumu;
37.3.3. Laragon Apache sunucusunun yapılandırılması
Laragon'un Apache sunucusunu yapılandıracağız. Öncelikle ana yapılandırma dosyası olan [httpd.conf] ile başlayalım:

[httpd.conf] dosyasının sonuna gidiyoruz:
…
IncludeOptional "C:/MyPrograms/laragon/etc/apache2/alias/*.conf"
IncludeOptional "C:/MyPrograms/laragon/etc/apache2/sites-enabled/*.conf"
Include "C:/MyPrograms/laragon/etc/apache2/httpd-ssl.conf"
Include "C:/MyPrograms/laragon/etc/apache2/mod_php.conf"
# python mod_wsgi
LoadModule wsgi_module "c:/data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages/mod_wsgi/server/mod_wsgi.cp38-win_amd64.pyd"
- 8. satır, [httpd.conf] dosyasının sonuna mevcut satırların arasına eklenmiştir. Bu satır, Apache sunucusuna az önce kurduğumuz [mod_wsgi] modülünün bir öğesinin nerede olduğunu belirtir;
- satırın yolunu bulmanın basit bir yolu, bir terminalde şu komutu çalıştırmaktır: PyCharm:
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\http-servers\11>mod_wsgi-express module-config
LoadModule wsgi_module "c:/data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages/mod_wsgi/server/mod_wsgi.cp38-win_amd64.pyd"
WSGIPythonHome "c:/data/st-2020/dev/python/cours-2020/python3-flask-2020/venv"
Bazı belgelerde, 2. ve 3. satırların [httpd.conf] dosyasının sonuna eklenmesi gerektiği belirtilmektedir. Benim durumumda, yukarıdaki 3. satır bir hataya neden oluyordu ([encodings] modülü eksik). Bu nedenle bu satır, [httpd.conf] dosyasına eklenmedi. Dosyaya yalnızca 2. satır eklendi. Apache yapılandırma dosyalarında kullanılabilen [mod_wsgi] modülünün çeşitli parametrelerinin anlamları, |ici| dosyasında açıklanmaktadır.
Ardından, Apache sunucusundaki HTTPS protokolünü etkinleştireceğiz:

- [1-4] dosyasında, Apache sunucusunun HTTPS protokolünü etkinleştiriyoruz;
Artık URL ve [https://serveur/chemin]'i kullanabileceğiz;
Apache'yi bir Flask uygulamasını sunacak şekilde yapılandırmak için, |plus haut| bağlantısında sanal sunucular kullanılır. Laragon da sanal sunucuları yönetme seçeneği sunar:

- [1-3]'te, Laragon'dan sanal ana bilgisayarları otomatik olarak oluşturmasını istiyoruz;
Bir sonraki adım, Laragon ile bir web projesi oluşturmaktır:
![]() |
![]() | ![]() |
- [1-3] komutunda, boş bir PHP projesi oluşturulur;
- [4-8]'te, Laragon, [sites-enabled] ve [7] klasörlerindeki [auto.projet-test.test.conf] ve [8] dosyalarıyla yapılandırılmış, [auto.projet-test.test] adlı bir sanal site oluşturmuştur. Bu klasör, [<laragon>\etc\apache2\sites-enabled] adresinde bulunur; burada [laragon], Laragon’un kurulum klasörüdür;
Şu anda yaptığımız işin kapsamına girmese de, az önce oluşturduğumuz [projet-test] adlı web sitesinin ne olduğunu merak edip bir göz atmak isteyebilirsiniz:

- [1-5] içinde boş bir proje oluşturuldu. Bu, [<laragon>/www] klasöründe bulunan PHP adlı bir projedir; burada [laragon], Laragon'un kurulum klasörüdür;
Şimdi, Laragon tarafından [<laragon>\etc\apache2\sites-enabled] klasöründe oluşturulan [auto.projet-test.test.conf] dosyasını inceleyelim:
define ROOT "C:/MyPrograms/laragon/www/projet-test/"
define SITE "projet-test.test"
<VirtualHost *:80>
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
<VirtualHost *:443>
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
SSLEngine on
SSLCertificateFile C:/MyPrograms/laragon/etc/ssl/laragon.crt
SSLCertificateKeyFile C:/MyPrograms/laragon/etc/ssl/laragon.key
</VirtualHost>
- 1. satır: Oluşturulan projenin dosya sistemindeki kök dizini;
- 2. satır: sanal sunucunun adı. Bu sunucu için URL dosyaları, [http(s)://projet-test.test/chemin] biçiminde olacaktır;
- satır 4-12: 80 numaralı bağlantı noktası (satır 4) ve HTTP protokolü için sanal sitenin yapılandırması;
- satır 14-27: 443 numaralı bağlantı noktası (satır 14) ve HTTPS protokolü için sanal sitenin yapılandırması;
Bir sanal sunucunun nasıl çalıştığına bir göz atalım. Öncelikle Apache sunucusunu ve PHP'i başlatalım:
Ardından bir tarayıcıyla URL [http://projet-test.test/] adresini çağırıyoruz:

- [1] adresinde, istenen URL;
- [2]'e dönüştürüldü; burada HTTP protokolü kullanıldı;
- [3]'te, [projet-test] projesi boş olduğu için, klasörünün dizini (içeriğinin listesi) elde edilir; bu dizin boştur;
Şimdi URL'i, [https://projet-test.test/]'in güvenli versiyonu olarak isteyelim:

- [1-2]'te, daha öncekiyle aynı yanıtı alıyoruz, ancak protokol HTTPS [1] şeklinde;
[projet-test.test] sanal sunucusunun oluşturulması, [<windows>/system32/drivers/etc/hosts] dosyasında yeni bir giriş oluşturdu:

- 23. satır: [projet-test.test] adlı sunucunun IP adresi 127.0.0.1'dir, yani [localhost]'in (20. satır) adresi, yani yerel makinedir. Dolayısıyla, bir tarayıcıya URL [http://projet-test.test/chemin] yazıldığında, istek 80 numaralı bağlantı noktası üzerinden 127.0.0.1 adresine gönderilir. Bu durumda yanıtı, yerel makinedeki (localhost) Apache sunucusu verir.
[http://projet-test.test/] isteği girildiğinde Apache sunucusunun neden [<laragon>\etc\apache2\sites-enabled\auto.projet-test.test.conf] dosyasındaki yapılandırmayı kullandığı merak edilebilir:

Bunu anlamak için, bu isteği yaptığımızda tarayıcının Apache sunucusuna ne gönderdiğine bakmamız gerekir. Postman ile bunu yapalım:

- [1-3] adresine, HTTPS [1] isteği gönderilir;
- [4]'e gönderdiğimizde, Postman güvenlik sertifikasını tanımadığını bildirir. HTTPS protokolü, web istemcisi (burada Postman) ile Apache sunucusu arasında şifreli bir bağlantı kurar. Bu şifreli bağlantı, istemci ile sunucu arasında değiş tokuş edilen sertifikalar aracılığıyla kurulur. Şifreli bağlantı kurma sürecini başlatan, istemciye bir güvenlik sertifikası göndererek sunucudur. Bu sertifikanın istemci tarafından kabul edilebilmesi için imzalanmış olması, yani güvenlik sertifikası verme yetkisine sahip şirketlerden satın alınmış olması gerekir. Laragon’un HTTPS protokolünü etkinleştirdiğimizde, Laragon güvenlik sertifikasını kendisi oluşturdu. Bu durumda sertifikanın “kendinden imzalı” olduğu söylenir. Çoğu web istemcisi, kendinden imzalı bir sertifika aldığında bir uyarı verir. Postman, [4] örneğinde bunu yapar. Çoğu web istemcisi bu durumda, sunucu tarafından gönderilen güvenlik sertifikasının doğrulanmasını devre dışı bırakmayı önerir. Postman, [5] örneğinde bunu önerir;
[5] bağlantısına tıklayarak SSL (Secure Sockets Layer) doğrulamasını devre dışı bırakıyoruz. SSL / TSL (Transport Layer Security), internet üzerindeki iki makine arasında güvenli bir iletişim kanalı oluşturan bir güvenlik protokolüdür. Bu, burada Apache tarafından kullanılan protokoldür. Yanıt şu şekildedir:

Geleneksel bir tarayıcıda olduğu gibi aynı sayfayı alıyoruz. Şimdi Postman konsolunda (Ctrl-Alt-C) istemci/sunucu diyaloğuna bakalım:
- 6. satır: HTTP [Host] başlığı, web istemcisinin hedeflediği sunucunun adını belirtir. Sanal sunucuların çalışma prensibi budur. Aynı IP adresinde (burada 127.0.0.1), bir web sunucusu farklı adlara sahip birden fazla web sitesini barındırabilir. HTTP [Host] başlığı, istemcinin hangi sunucuya (burada 127.0.0.1 adresindeki) bağlanacağını belirtmesini sağlar;
Peki Apache ne yapar?
Başladığında Apache, [[<laragon>\etc\apache2\sites-enabled]] klasöründe bulunan tüm yapılandırma dosyalarını okur:

Her yapılandırma dosyası bir sanal sunucuyu tanımlar. Örneğin, [auto.projet-test.test.conf] dosyasında şu satır bulunur:
define ROOT "C:/MyPrograms/laragon/www/projet-test/"
define SITE "projet-test.test"
…
- satır, [projet-test.test] adlı sanal sunucuyu tanımlar. [auto.projet-test.test.conf] dosyası ise bu sanal sunucunun yapılandırma dosyasıdır. Apache sunucusu, başlangıçta [<laragon>\etc\apache2\sites-enabled] klasöründeki tüm yapılandırma dosyalarını okuduğu için, [projet-test.test] adlı bir sanal sunucunun var olduğunu bilir. Böylece, Postman istemcisinden HTTPS isteğini aldığında:
bu isteğin [projet-test.test] sanal sunucusuna (6. satır) yönlendirildiğini ve bu sunucunun mevcut olduğunu anlar. Ardından, Postman istemcisine yanıt vermek için [projet-test.test] sanal sunucusunun yapılandırmasını kullanır.
37.4. İlk Apache sanal sunucusunun oluşturulması
Artık sanal sunucuların ne işe yaradığını ve nasıl tanımlanacağını bildiğimize göre, bir tane oluşturacağız. Bu sunucu, Apache sunucusunda dağıtımı devam eden sürüm 17’nin [Apache] klasörüne kurulu bir Python Flask uygulamasını çalıştırmak için kullanılacak:
|lien| paragrafında geliştirdiğimiz, tarih/saat web hizmeti olan uygulamayı [http-servers/12/apache/exemple] klasörüne yerleştirdik:

[date_time_server.py] sunucusu şu şekildedir:
# ithalatlar
import os
import sys
import time
# modüllerin bulunduğu klasörü Python yoluna eklememiz gerekiyor
# Windows Apache'ye taşıma için
sys.path.insert(0, "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages")
from flask import Flask, make_response, render_template
# Flask uygulaması
script_dir = os.path.dirname(os.path.abspath(__file__))
application = Flask(__name__, template_folder=f"{script_dir}")
# Ana Sayfa URL
@application.route('/')
def index():
# istemciye saat gönderme
# time.localtime : 01/01/1970'den bu yana geçen milisaniye sayısı
# time.strftime, saat ve tarihi biçimlendirmeye olanak tanır
# tarih-saat görüntüleme biçimi
# d: 2 basamaklı gün
# m: 2 basamaklı ay
# y: 2 basamaklı yıl
# H: saat 0,23
# M: dakika
# S: saniye
# o anki tarih / saat
time_of_day = time.strftime('%d/%m/%y %H:%M:%S', time.localtime())
# müşteriye gönderilecek belge oluşturulur
page = {"date_heure": time_of_day}
document = render_template("date_time_server.html", page=page)
print("document", type(document), document)
# Müşteriye HTTP yanıtı
response = make_response(document)
print("response", type(response), response)
return response
# sadece ana iş parçacığı
if __name__ == '__main__':
application.config.update(ENV="development", DEBUG=True)
application.run()
Flask uygulaması, [application] kimliği ile referanslandırılmıştır (14., 43. ve 44. satırlar). Bu ad zorunludur. Flask uygulamasına başka bir tanımlayıcıyla başvurulursa, uygulama çalışmayacak ve istenen URL'i bulamadığını belirten bir hata mesajı verecektir. Bu hata mesajı, hatanın kaynağına dair hiçbir ipucu vermez. Bu nedenle bu konuda dikkatli olunmalıdır.
- satırda referans verilen HTML dosyası şöyledir:
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Date et heure du moment</title>
</head>
<body>
<b>Date et heure du moment : {{page.date_heure}}</b>
</body>
</html>
- [date-time-server], bu uygulamayı barındıracak sanal sunucu olacaktır. Bu sunucu, QZXX2HTMLP008142ZQX dosyası ile yapılandırılacaktır (bu adın serbest olduğunu hatırlatırız – Apache, barındırılan sanal siteleri tespit etmek için [sites-enabled] içinde bulunan tüm dosyaları okur);
Bu dosyayı öncelikle [auto.projet-test.test.conf] dosyasını kopyalayarak elde ederiz, ardından üzerinde değişiklik yaparız.

[date-time-server.conf] dosyası şu şekilde olacaktır:
# uygulamanın python-flask betik klasörü
define ROOT "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/impots/http-servers/12/apache/exemple"
# bu dosya tarafından yapılandırılan web sitesinin adı
# burada adı date-time-server olacaktır
# URL, http(s)://date-time-server/yol şeklinde olacaktır
define SITE "date-time-server"
# c:/windows/system32/drivers/etc/hosts dosyasına, SITE sitesi için IP adresini 127.0.0.1 olarak girin
# URL HTTP
<VirtualHost *:80>
# takma adıyla / URL adresleri http(s)://tarih-saat-sunucusu/yol/... biçiminde olacaktır
WSGIScriptAlias / "${ROOT}/date_time_server.py"
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
# URL, HTTPS ile güvenli hale getirilmiştir
<VirtualHost *:443>
# takma adıyla / URL, http(s)://tarih-saat-sunucusu/yol/... biçiminde olacaktır
WSGIScriptAlias / "${ROOT}/date_time_server.py"
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
SSLEngine on
SSLCertificateFile C:/MyPrograms/laragon/etc/ssl/laragon.crt
SSLCertificateKeyFile C:/myprograms/laragon/etc/ssl/laragon.key
</VirtualHost>
- 7. satır: Dosya tarafından yapılandırılan sanal sunucuya bir ad verilir;
- 2. satır: 14. ve 27. satırlarda kullanılan [ROOT] değişkenine bir değer verilir;
- 14. ve 27. satırlar: Sanal sunucu bir istek aldığında çalıştırılması gereken Python betiğinin yolunu belirtir. Burada, [date-time-server] sunucusuna gelen isteklerin [date_time_server.py] Python betiği tarafından işleneceği belirtilir. [auto.projet-test.test.conf] dosyasıyla arasındaki bu fark, [auto.projet-test.test.conf] dosyasının bir PHP sunucusunu yapılandırırken, [date-time-server.conf] dosyasının bir Python sunucusunu yapılandırmasından kaynaklanmaktadır;
- 14. ve 27. satırlar: [WSGIScriptAlias /] özniteliği burada, [date-time-server] sunucusunun kök dizininin [/] olacağını belirtir. Böylece, uygulamanın URL dosyaları [http(s)://date-time-server/chemin] biçiminde olacaktır;
- 14. ve 27. satırlarda, uygulamaya örneğin [WSGIScriptAlias /show] gibi başka bir kök verilebilir. Bu durumda, uygulamanın URL değerleri [http(s)://show/date-time-server/chemin] biçimini alacaktır;
Ayrıca [<windows>/system32/drivers/etc/hosts] dosyasına bir satır eklememiz gerekiyor:
- satırı ekleyerek, IP [127.0.0.1] adresini [date-time-server] sanal sunucusuna atıyoruz.
Hadi tüm bunları kontrol edelim. Apache sunucusunu başlatıyoruz:

Ardından bir tarayıcıdan URL [https://date-time-server] adresini sorguluyoruz:

- [1] adresinde, istenen URL;
- [3] dosyasında, sunucudan gelen yanıt;
- [2] dosyasında, tarayıcı, Apache sunucusu tarafından gönderilen sertifikanın kendi kendine imzalanmış olduğunu tespit ettiği için HTTPS bağlantısının güvenli olmadığını belirtiyor;
Şimdi [date-time-server.conf] dosyasına, 14. ve 27. satırlara bir takma ad ekleyelim:
WSGIScriptAlias /show-date-time "${ROOT}/date_time_server.py"
Değişiklik, Apache sunucusu tarafından hemen dikkate alınmaz. Sunucuyu yeniden yüklemek gerekir:

Ardından URL [https://date-time-server/show-date-time] adresine erişelim. Sunucunun yanıtı şu şekildedir:

37.5. Apache / Windows üzerinde vergi hesaplama uygulamasının uyarlanması
[apache] [2] klasörü, başlangıçta [main] klasörünün kopyalanmasıyla elde edilir. [1]'ten [2]'e kopyalanan [syspath.py] betiğinin yollarının geçerli kalması için bu klasörlerin aynı düzeyde olması önemlidir. Çalışır durumdaki [impots / http-servers/ 12] uygulamasını etkilememek için, Apache sunucusu tarafından yürütülecek yapılandırmayı [apache] dosyasına yerleştiriyoruz;

- [2]'teki [config] dosyası, [1]'teki [config] dosyasıyla aynıdır;
- [2] dosyasının içindeki [syspath] dosyası, [1] dosyasının içindeki [syspath] dosyasıyla aynıdır;
- [2] dosyasından gelen [main_withmysql] dosyası, [1] dosyasından gelen [main] dosyasıdır ve aşağıdaki değişiklikler içermektedir:
Ana komut dosyası [main], hangi SGBD dosyasının kullanılacağını belirten [mysql / pgres] parametresini alıyordu. [main_withmysql] betiği, SGBD ve MySQL'i kullanır:
# mysql veya pgres parametresi bekleniyor
import os
import sys
# uygulama MySQL ile yapılandırılıyor
import config
config = config.configure({'sgbd': "mysql"})
# bağımlılıklar
from SendAdminMail import SendAdminMail
from Logger import Logger
from ImpôtsError import ImpôtsError
…
- satırda, SGBD değerini MySQL olarak ayarlıyoruz.
- [main_withpgres] dosyası, [2] dosyasının [main] dosyasıdır ve aşağıdaki değişiklikler yapılmıştır: SGBD ve PostgreSQL dosyalarını kullanır:
# mysql veya pgres parametresi bekleniyor
import os
import sys
# uygulama MySQL ile yapılandırılıyor
import config
config = config.configure({'sgbd': "pgres"})
# bağımlılıklar
from SendAdminMail import SendAdminMail
from Logger import Logger
from ImpôtsError import ImpôtsError
…
- satırda, SGBD dosyasını PostgreSQL olarak ayarlıyoruz.
Bu işlem tamamlandıktan sonra, aşağıdaki gibi [main_withmysql.wsgi] komut dosyasını oluşturun (kullanılan sonek önemli değildir):
[main_withmysql.wsgi] komut dosyası, Apache sunucusu tarafından WSGI modunda yürütülecek hedeftir:
- Apache sunucusunun hedefi, daha önce [date_time_server.py] betiğinde yapıldığı gibi [main_withmysql.py] betiği de olabilirdi. Ancak bunun için betiği biraz değiştirmek gerekirdi:
- konsol betiği ile çalıştırma modunun aksine, Apache'de [main_withmysql.py] hedefini içeren klasör Python Path'in bir parçası değildir. Bu nedenle, [main_withmysql.py] betiğinin 6. satırı bir hataya neden olur;
- yapılması gereken ikinci değişiklik ise, [main_withmysql] içinde Flask uygulamasının [app] tanımlayıcısıyla referanslandırılmasıdır. Apache / WSGI için de bu uygulamanın [application] tanımlayıcısıyla referanslanması gerektiği bilinmektedir;
- [main_withmysql.py] dosyasını değiştirmek yerine, Apache’nin hedefini değiştiriyoruz. Artık hedef, yukarıdaki [main_withmysql.wsgi] komut dosyası olacaktır:
- 1-7. satırlar: Komut dosyasının bulunduğu klasör Python Path’e eklenir. Böylece, [main_withmysql.py] dosyasının 6. satırı artık hata vermez;
- 9-10. satırlar: [main_withmysql.py] dosyasının içe aktarılması, dosyanın çalıştırılmasını sağlar. Ayrıca, [main_withmysql.py] içinde bulunan Flask uygulaması [app]’e, Apache’nin WSGI modunda ihtiyaç duyduğu [application] tanımlayıcısıyla başvurulur;
Aynı işlem [main_withpgres.wsgi] komut dosyası için de yapılır:
# bu dosyanın bulunduğu klasör
import os
script_dir = os.path.dirname(os.path.abspath(__file__))
# Aşağıdaki içe aktarma işleminin mümkün olması için bunu syspath'e ekliyoruz
import sys
sys.path.insert(0, script_dir)
# Flask uygulaması [app]'i [application] adıyla içe aktarıyoruz
from main_withpgres import app as application
Artık Apache sunucusu için çalıştırılabilir hedefler elimizde. Şimdi her hedef için birer tane olmak üzere iki sanal sunucu oluşturmamız gerekiyor.
[<laragon>\etc\apache2\sites-enabled] içinde, [flask-impots-withmysql.conf] dosyasını oluşturuyoruz (verilen adın önemi yoktur):

# .wsgi betiğinin bulunduğu klasör
define ROOT "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/impots/http-servers/12/apache"
# bu dosya tarafından yapılandırılan web sitesinin adı
# burada adı flask-impots-withmysql olacak
# URL, http(s)://flask-impots-withmysql/yol şeklinde olacaktır
define SITE "flask-impots-withmysql"
# c:/windows/system32/drivers/etc/hosts dosyasına, IP 127.0.0.1 adresini SITE sitesi için ekleyin
# Buraya kullanılacak Python kütüphanelerinin yollarını girin - virgülle ayırın
# buraya bir Python sanal ortamının kütüphanelerini yazın
WSGIPythonPath "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages"
# Python Home - yalnızca birden fazla Python sürümü yüklüyse gereklidir
# WSGIPythonHome "C:/Program Files/Python38"
# URL HTTP
<VirtualHost *:80>
# takma adıyla / URL, /{prefixe_url}/action/... biçiminde olacaktır
# /impots takma adıyla URL, /impots/{prefixe_url}/action/... biçiminde olacaktır
# burada [prefixe_url], parameters.py içinde tanımlanmıştır
WSGIScriptAlias / "${ROOT}/main_withmysql.wsgi"
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
# URL, HTTPS ile güvenli hale getirilmiştir
<VirtualHost *:443>
# takma adıyla / URL, /{prefixe_url}/action/... biçiminde olacaktır
# takma adı /impots olan URL, /impots/{prefixe_url}/action/... biçiminde olacaktır
# burada [prefixe_url], parameters.py içinde tanımlanmıştır
WSGIScriptAlias / "${ROOT}/main_withmysql.wsgi"
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
SSLEngine on
SSLCertificateFile C:/MyPrograms/laragon/etc/ssl/laragon.crt
SSLCertificateKeyFile C:/myprograms/laragon/etc/ssl/laragon.key
</VirtualHost>
- 2. satır: uygulamanın kök dizini, oluşturduğumuz [apache] klasörü;
- 23. ve 38. satırlar: Oluşturduğumuz [main_witmysql.wsgi] hedefi:
- 7. satır: sanal sunucunun adı [flask-impots-withmysql] olacaktır;
- 13. satır: [WSGIPythonPath] yönergesi, Python Path’e klasörler eklemeye olanak tanır. Burada Apache, uygulamayı geliştirmek için sanal bir ortam kullandığımızı ve uygulama tarafından kullanılan tüm modüllerin bu sanal ortamda bulunduğunu bilmiyor. Bu nedenle, 13. satırda, kullanılan sanal ortamdaki tüm modülleri içeren klasörü ekliyoruz. Bir seçenek, bu klasörü dosya sisteminin başka bir yerine kopyalayıp bu konuma referans vermektir. Diğer bir seçenek ise, bu klasörü doğrudan [main_witmysql.wsgi] hedefine Python Path’e eklemektir (bu muhtemelen daha iyi bir çözümdür);
- 16. satır: Apache’ye dosya sistemindeki Python kurulum klasörünü belirtebiliriz. Normalde bu, makinenin PATH dizinindedir ve genellikle bu satır gereksizdir (burada da durum böyleydi). Ancak makinede birden fazla Python kurulumu olabilir ve istenen kurulum makinenin PATH dizininde olmayabilir. Bu durumda bu satır sorunu çözer;
Aynı şekilde bir [flask-impots-withpgres.conf] dosyası oluşturulur:
# .wsgi betiğinin bulunduğu klasör
define ROOT "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/impots/http-servers/12/apache"
# bu dosya tarafından yapılandırılan web sitesinin adı
# burada adı flask-impots-withmysql olacaktır
# URL, http(s)://flask-impots-withmysql/yol şeklinde olacaktır
define SITE "flask-impots-withpgres"
# c:/windows/system32/drivers/etc/hosts dosyasına, IP 127.0.0.1 adresini SITE sitesi için ekleyin
# Buraya kullanılacak Python kütüphanelerinin yollarını girin - virgülle ayırın
# buraya bir Python sanal ortamının kütüphanelerini yazın
WSGIPythonPath "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages"
# Python Home - yalnızca birden fazla Python sürümü yüklüyse gereklidir
# WSGIPythonHome "C:/Program Files/Python38"
# URL HTTP
<VirtualHost *:80>
# takma adıyla / URL, /{prefixe_url}/action/... biçiminde olacaktır
# /impots takma adıyla URL, /impots/{prefixe_url}/action/... biçiminde olacaktır
# burada [prefixe_url], parameters.py içinde tanımlanmıştır
WSGIScriptAlias / "${ROOT}/main_withpgres.wsgi"
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
# URL, HTTPS ile güvenli hale getirilmiştir
<VirtualHost *:443>
# takma adıyla / URL, /{prefixe_url}/action/... biçiminde olacaktır
# takma adı /impots olan URL, /impots/{prefixe_url}/action/... biçiminde olacaktır
# burada [prefixe_url], parameters.py içinde tanımlanmıştır
WSGIScriptAlias / "${ROOT}/main_withpgres.wsgi"
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
SSLEngine on
SSLCertificateFile C:/MyPrograms/laragon/etc/ssl/laragon.crt
SSLCertificateKeyFile C:/myprograms/laragon/etc/ssl/laragon.key
</VirtualHost>
Tüm bu dosyaları kaydettikten sonra Apache sunucusunu ve SGBD, MySQL ile PostgreSQL dosyalarını çalıştırıyoruz. Uygulama, URL, [/do] ve [with_csrftoken=False] (CSRF jetonu yok) [configs/parameters.py]'te. URL ve [https://flask-impots-withmysql/do]'i talep ediyoruz. Sunucudan gelen yanıt şöyledir:

Şimdi URL ve [https://flask-impots-pgres/do]'i istiyoruz. Yanıt şu şekildedir:

Her iki uygulama da normal şekilde çalışıyor.
Şimdi [WSGIScriptAlias] parametresini [flask-impots-withmysql.conf] olarak değiştirelim:
# .wsgi betik dosyası
define ROOT "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/impots/http-servers/12/apache"
…
# URL HTTP
<VirtualHost *:80>
# takma adıyla / URL, /{prefixe_url}/action/... biçiminde olacaktır
# /impots takma adıyla URL, /impots/{prefixe_url}/action/... biçiminde olacaktır
# burada [prefixe_url], parameters.py içinde tanımlanmıştır
WSGIScriptAlias /impots "${ROOT}/main_withmysql.wsgi"
…
</VirtualHost>
# URL, HTTPS ile güvenli hale getirilmiştir
<VirtualHost *:443>
# takma adıyla / URL, /{prefixe_url}/action/... biçiminde olacaktır
# takma adı /impots olan URL, /impots/{prefixe_url}/action/... şeklinde olacaktır
# burada [prefixe_url], parameters.py içinde tanımlanmıştır
WSGIScriptAlias /impots "${ROOT}/main_withmysql.wsgi"
…
</VirtualHost>
- 11. ve 20. satırlarda, WSI takma adı artık [/impots] olarak değiştirilmiştir;
Apache sunucusunu durdurup yeniden başlattıktan sonra URL ve [https://flask-impots-withmysql/impots/do] adreslerini sorguluyoruz. Sunucudan gelen yanıt şöyledir:

Bir çökme meydana geldi. URL [1] hatası bunun nedenini gösteriyor. Bu değerin [https://flask-impots-withmysql/impots/do/afficher-vue-authentification] olması gerekirdi. WSGI takma adı eksik. Bu, uygulamamızdaki bir hatadır. Uygulamamız, URL önekini yönetebiliyor (/do mevcut). Uygulamamıza [/impots/do] önekini ekleyerek önceki sorunun çözüleceğini düşünebiliriz. Ancak öyle değil. Bu durumda başka türde sorunlarla karşılaşıyoruz. WSGI takma adı, URL önekine uygun şekilde davranmıyor.
Neler olduğunu anlamaya çalışalım. URL ve [https://flask-impots-withmysql/impots/do]’i talep ettik. Kimlik doğrulama ekranının açılmasını bekliyorduk. Yukarıdaki [1] örneğinde, uygulamanın bu ekranı talep ettiği ancak doğru URL değerini kullanmadığı görülüyor. [https://flask-impots-withmysql/impots/do] isteğinin izini sürelim.
Öncelikle şu yol (configs/routes.py) yürütüldü:
# Flask uygulamasının rotaları
# uygulamanın kök dizini
app.add_url_rule(f'{prefix_url}/', methods=['GET'],
view_func=routes.index)
Örneğimizde 3 numaralı hattın yolu [https://flask-impots-withmysql/impots/do] şeklindedir. Görüldüğü gibi, rotadan [https://flask-impots-withmysql/impots] kısmı çıkarılmış ve sadece [/do] haline gelmiştir. [https://flask-impots-withmysql] kısmı için bu normaldir, çünkü sunucu adı rotada yer almamaktadır. Ancak WSGI ve [/impots] takma adlarının da yoluna dahil edilmediğini görüyoruz. Bu önemli bir noktadır. WSGI takma adı olsa bile, başlangıçtaki yollarımız geçerliliğini korur.
Şimdi 4. satırdaki (configs/routes_without_csrftoken) [index] işlevinin ne yaptığını inceleyelim:
# uygulamanın kök dizini
def index() -> tuple:
# /init-session/html adresine yönlendirme
return redirect(url_for("init_session", type_response="html"), status.HTTP_302_FOUND)
- satırda, [init_session] işlevindeki URL işlevine yönlendiriliyoruz. [configs/routes.py]'te bu işlev, [/do/init-session/html] yoluyla ilişkilendirilmiştir:
# init-session
app.add_url_rule(f'{prefix_url}/init-session/<string:type_response>{csrftoken_param}', methods=['GET'],
view_func=routes.init_session)
- satırda, [csrftoken_param] testimizde dize boştur. Uygulama burada CSRF jetonunu işlemiyor.
[init_session] işlevi şu şekilde tanımlanmıştır (configs/routes_without_csrftoken):
# init-session
def init_session(type_response: str) -> tuple:
# eylemle ilişkili denetleyici çalıştırılır
return front_controller()
- satırda, [init-session] eyleminin işleme dizisi başlıyor. Bu dizi, [responses/HtmlResponse] içinde şu şekilde sona eriyor:
…
# şimdi, istenirse CSRF jetonunu da ekleyerek URL yönlendirme kodunu oluşturmak gerekiyor
if config['parameters']['with_csrftoken']:
csrf_token = f"/{generate_csrf()}"
else:
csrf_token = ""
# yönlendirme yanıtı
return redirect(f"{config['parameters']['prefix_url']}{ads['to']}{csrf_token}"), status.HTTP_302_FOUND
[init-session] eylemi, 9. satırda bir görünüme yönlendirmeyle sona eren bir ADS (Do Something Eylemi) eylemidir. Sorun da burada yatmaktadır. 9. satırdaki [redirect] işlevi, yönlendirme işlevi olan URL'e WSGI takma adını otomatik olarak eklemiyor. Yukarıdaki ekran görüntüsü de bunu göstermektedir. Yönlendirme nesnesi olan URL’te /impots takma adı eksiktir.
Aşağıdaki sürüm, WSGI takma adı sorununa bir çözüm sunuyor.


