HTTPS請求HTTP介面被瀏覽器阻塞,python實現websocket客戶端,websocket伺服器,跨域問題,dwebsocket,https,攔截,服務端
阿新 • • 發佈:2020-09-16
HTTPS請求HTTP介面被瀏覽器阻塞,python實現websocket客戶端,websocket伺服器,跨域問題,dwebsocket,https,攔截,服務端
發表時間:2020-03-05
1 背景
由於公司前端的頁面部署在以https(加了證書)協議的域名下,去請求http協議的域名的某個服務,並且該http域名下的服務,不僅要處理普通請求(POST、GET),還需要處理websocket請求。由於瀏覽器禁止https域名的內容請求http的服務,甚至嵌入子頁面都禁止,因為瀏覽器會認為http的內容是不安全的,所以為解決該問題,研究出如下解決方案。
2 解決辦法
由於瀏覽器禁止,但是伺服器並不會禁止,所以,我在https的域名下,解析一臺代理伺服器,由該代理伺服器去代替https去請求,再把結果返給前端。
3 開發環境
PyCharm,語言:Python3,服務框架:django
4 用到的庫
pip3 install Django==1.11.3 django-cors-headers==3.2.1 dwebsocket==0.5.12 websocket==0.2.1 websocket-client==0.57.0
5 settings.py配置
# 允許訪問的host為所有 ALLOWED_HOSTS = ['*'] # 配置跨域請求問題 CORS_ALLOW_CREDENTIALS = True CORS_ORIGIN_ALLOW_ALL = True CORS_ALLOW_METHODS = ( 'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'VIEW', ) CORS_ALLOW_HEADERS = ( 'XMLHttpRequest', 'X_FILENAME', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with', ) INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', #'myapp.apps.MyappConfig', # 添加當前的app 'myapp', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 去除csrf校驗 # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
6 urls.py配置:
from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from myapp import views
urlpatterns = [
path('admin/', admin.site.urls),
# 配置攔截/proxy 對映到 views.py中的方法
url(r'^proxy$',views.proxy),
]
7 views.py程式碼:仔細看註釋
from django.shortcuts import render from django.shortcuts import HttpResponse import requests from dwebsocket.decorators import accept_websocket import logging from websocket import create_connection import time # 設定日誌格式 LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s" DATE_FORMAT = "%m/%d/%Y %H:%M:%S %p" fs = logging.StreamHandler() logging.basicConfig(level=logging.INFO, format=LOG_FORMAT, datefmt=DATE_FORMAT, handlers=[fs]) # Create your views here. # 新增dwebsocket的裝飾器,該裝飾器會對request屬性新增websocket屬性 # 並新增 send()推資料 close()關閉連線 is_websocket()是否是websocket請求 等方法 @accept_websocket def proxy(request): # 判斷請求是否是websocket if not request.is_websocket(): # 收到的請求的格式是 https://devlab.edu.huaweicloud.com/proxy?url=http://ip:8000/senddata?model=workload-read-mostly # 我們將這個服務部署到加了證書的伺服器上,即可。 # 其中,引數url=後面是要代理的url ,我們將其擷取下來,並重新請求。 url = request.get_full_path().split('url=')[1] logging.info('proxy url : {}'.format(url)) # 進行GET請求和POST請求的分別處理 # if request.method == 'GET': # logging.info('processing a url GET request !') # 其中省略了將請求的 header/cookie 傳遞給代理請求的 header/cookie ,由於我們業務不需要這些,我就不加了。 # res = requests.get(url) # else: # logging.info('processing a url POST request !') # res = requests.post(url) # 由於我們的業務都是g GET 請求,所以就直接處理就好了 res = requests.get(url) # 將代理請求的結果返回給真正的請求 logging.info('revc : {}'.format(res.content.decode())) return HttpResponse(res.content.decode()) else: # 收到的請求的格式是 wss://devlab.edu.huaweicloud.com/proxy?url=ws://ip:8000/senddata?model=workload-read-mostly # 其中,引數url=後面是要代理的url ,我們將其擷取下來,並重新請求。 url = request.get_full_path().split('url=')[1] logging.info('proxy url : {}'.format(url)) try: # 這裡的header 必須要加上, 或者將 request中的header拿出來逐一存入list中, # 由於request中儲存的headers的格式是dict,websocket中需要的headers是list,所以需要自行轉化, # websocket的header的格式如下, 由於業務沒有強制header 是什麼,所以我就自己寫的,但是注意, # 需要將以下的header的內容都要補充完整,否則會報 header...相關的錯誤,返回200或者其他狀態碼的錯誤, # 200在websocket是錯誤,在http裡面是成功,需要注意一下。 header = ['Accept-Encoding: gzip, deflate', 'Connection: Upgrade', 'Pragma: no-cache', 'Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits', 'Sec - WebSocket - Version: 13', 'Upgrade: websocket', 'Access-Control-Allow-Origin: *', 'Access-Control-Allow-Headers: X-Requested-With', 'Access-Control-Allow-Methods: GET,POST,OPTIONS', 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36'] # 建立長連線/websocket ws = create_connection(url,header=header) # 每1秒就收一下訊息 while True: # 接收訊息,如果訊息中帶有Finished,表示訊息都接收完畢,跳出迴圈。 res = ws.recv() if 'Finished' in res: logging.info('revc : {}'.format(res)) # 該服務,即作為服務端(接收並處理請求並響應方),又做為客戶端(傳送請求並接收另一個服務的響應) # 所以將代理服務推過來的結果再推給瀏覽器 request.websocket.send(res) # 除錯的時候,瀏覽器端好像收不到最後一條訊息,所以我在以這種方式再發送一遍吧 # return HttpResponse(res) # websocket 相當佔用網路資源,請及時關閉,由於生產環境中,網路資源的不穩定性, # 可能資料還沒推出去,就把websocket關閉了,會造成資料的丟失。 time.sleep(5) ws.close() request.websocket.close() break if not res == None: logging.info('revc : {}'.format(res)) # 如果有資料, 將代理服務推過來的結果再推給瀏覽器 request.websocket.send(res) time.sleep(1) # websocket 相當佔用網路資源,請及時關閉,其實邏輯是走不到這裡的,但是還是加上保險 ws.close() request.websocket.close() except BaseException as e: logging.error(e)
8 部署
python3 manage.py runserver 0.0.0.0:8080