Skip to content

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

Image

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ı

Image

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;

Image

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:

Image

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:

Image

[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:

Image

[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:

Image

[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;
  1. 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:

Image

  • [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:

Image

  • [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:

Image

  • [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:

Image

  • [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:

Image

  • [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:

Image

# Telif hakkı (c) 1993-2009 Microsoft Corp.
#
# Bu, Windows için Microsoft TCP/IP tarafından kullanılan örnek bir dosyadır.
#
# Bu dosya, IP adreslerinin ana bilgisayar adlarına eşlemelerini içerir. Her bir
# girişi ayrı bir satırda tutulmalıdır. IP adresi
# ilk sütuna yazılmalı ve ardından ilgili ana bilgisayar adı gelmelidir.
# IP adresi ile ana bilgisayar adı arasında en az bir
# boşlukla ayrılmalıdır.
#
# Ayrıca, (bunlar gibi) açıklamalar tek tek
# satırlara veya '#' sembolüyle belirtilen makine adının arkasına eklenebilir.
#
# Örneğin:
#
#       102.54.9    4.97 rhino.         acme.com # kaynak sunucu
#        38.25.    63.10 x             .acme.com # x istemci ana bilgisayarı

# localhost ad çözümlemesi, DNS'in kendi içinde gerçekleştirilir.
#     127.0.0.1       localhost
#     ::1             localhost

127.0.0.1      projet-test.test     #Laragon sihri!   
  • 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:

Image

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:

Image

  • [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:

Image

Geleneksel bir tarayıcıda olduğu gibi aynı sayfayı alıyoruz. Şimdi Postman konsolunda (Ctrl-Alt-C) istemci/sunucu diyaloğuna bakalım:

GET / HTTP/1.1
User-Agent: PostmanRuntime/7.26.2
Accept: */*
Cache-Control: no-cache
Postman-Token: d153f711-ad99-4e1d-93c3-61c25374d1be
Host: projet-test.test
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

HTTP/1.1 200 OK
Date: Fri, 14 Aug 2020 09:19:24 GMT
Server: Apache/2.4.35 (Win64) OpenSSL/1.1.1b PHP/7.2.19 mod_wsgi/4.7.1 Python/3.8
Content-Length: 161
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html;charset=UTF-8
  • 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:

Image

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"

  1. 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:
1
2
3
4
5
6
7
8
GET / HTTP/1.1
User-Agent: PostmanRuntime/7.26.2
Accept: */*
Cache-Control: no-cache
Postman-Token: d153f711-ad99-4e1d-93c3-61c25374d1be
Host: projet-test.test
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

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:

Image

[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.

  1. 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.

Image

[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:

# Telif hakkı (c) 1993-2009 Microsoft Corp.
#
# Bu, Microsoft HOSTS dosyası, Windows için TCP/IP tarafından kullanılan bir örnektir.
#
# Bu dosya, IP adreslerinin ana bilgisayar adlarına eşlemelerini içerir. Her bir
# girişi ayrı bir satırda tutulmalıdır. IP adresi
# ilk sütuna yazılmalı ve ardından ilgili ana bilgisayar adı gelmelidir.
# IP adresi ile ana bilgisayar adı arasında en az bir
# boşlukla ayrılmalıdır.
#
# Ayrıca, (bunlar gibi) açıklamalar tek tek
# satırlara veya '#' sembolüyle belirtilen makine adının arkasına eklenebilir.
#
# Örneğin:
#
#       102.54.9    4.97 rhino.         acme.com # kaynak sunucu
#        38.25.    63.10 x             .acme.com # x istemci ana bilgisayarı

# localhost ad çözümlemesi, DNS'in kendi içinde gerçekleştirilir.
#     127.0.0.1       localhost
#     ::1             localhost

127.0.0.1    flask-impots-withmysql        # Python kursu - MySQL ile vergi uygulaması
127.0.0.1    flask-impots-withpgres        # Python dersi - PostgreSQL ile vergi uygulaması
127.0.0.1    date-time-server            # Python dersi - şu anki saat ve tarih
127.0.0.1           projet-test.test                #Laragon sihirbazlığı!
  1. 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:

Image

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

Image

  • [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:

Image

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

Image

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;

Image

  • [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

  1. 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

  1. 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):

# bu dosyanın bulunduğu klasör
import os
script_dir = os.path.dirname(os.path.abspath(__file__))

# Aşağıdaki import işleminin mümkün olması için syspath'e eklenir
import sys
sys.path.insert(0, script_dir)

# [app] adlı Flask uygulamasını [application] adıyla içe aktarıyoruz
from main_withmysql import app as application

[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):

Image


# .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:

Image

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

Image

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:

Image

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)
  1. 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)
  1. 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()
  1. 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.