zoukankan      html  css  js  c++  java
  • HTTPS请求HTTP接口被浏览器阻塞,python实现websocket客户端,websocket服务器,跨域问题,dwebsocket,https,拦截,服务端

    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
    

    https://www.pythonf.cn/read/51639

  • 相关阅读:
    .NET Framework类库大概
    CTS、CLS、CIL与CLR
    .NETFramework、CLR、.NET Framework class library、托管代码是什么
    万维网三大核心技术
    Clang、GCC和LLVM是什么
    常见开源许可证、开源协议GPL、BSD、MIT、Mozilla、Apache和LGPL之间区别
    编译原理之变量、名字与标识符
    编译原理之静态策略与动态策略
    Jupyter Notebook打开任意文件
    修改VsCodes的语言为中文
  • 原文地址:https://www.cnblogs.com/geoffreygao/p/13681044.html
Copyright © 2011-2022 走看看