前後端分離djangorestframework—— 線上視頻平臺接入第三方加密防盜錄視頻

来源:https://www.cnblogs.com/yangva/archive/2019/03/15/10530569.html
-Advertisement-
Play Games

加密視頻 在以後的開發項目中,很可能有做線上視頻的,而線上視頻就有個問題,因為線上播放,就很有可能視頻數據被抓包,如果這個線上視頻平臺有付費視頻的話,這樣就會有人做點倒賣視頻的生意了,針對這個問題,目前國內有很多不錯的加密視頻平臺,可以把你平臺的視頻放在他們那裡,然後通過他們的機制進行加密,然後做一... ...


 

加密視頻

在以後的開發項目中,很可能有做線上視頻的,而線上視頻就有個問題,因為線上播放,就很有可能視頻數據被抓包,如果這個線上視頻平臺有付費視頻的話,這樣就會有人做點倒賣視頻的生意了,針對這個問題,目前國內有很多不錯的加密視頻平臺,可以把你平臺的視頻放在他們那裡,然後通過他們的機制進行加密,然後做一套機制,當用戶使用平臺播放時,其實是平臺去加密視頻方請求過來的加密視頻,這樣就可以保證視頻的安全性了

常用加密視頻平臺

鄙人聽說的,有保利威,金盾,還有很多很多我叫不上名,搜索引擎一搜就有一大堆的,本次教程說的是保利威

 

保利威

官網:傳送門   有直播和點播的服務,直播是什麼不用多說了吧,點播的意思就是我上面說的,把錄製好的視頻放到平臺那種

 

本教程只介紹使用雲點播功能

 

 

文檔手冊

點擊使用手冊的雲點播:使用手冊文檔:傳送門

 

 

選到h5視頻播放:當然你也可以使用flash,但是現在的平臺基本都用的是h5了,所以本次選用h5的

 

 

官方文檔案例演示

 

 複製這段代碼放到一個html文檔里,直接點那個瀏覽器標識打開測試:

 

 

 

這個頁面整個都是保利威給我我們提供的,可以加速播放,可以查看視頻參數,可以看列表,然後還有個【test】這個就是跑馬燈,相信有過購買視頻的朋友都知道,你看你的付費視頻時,都有自己的用戶名啥的,假如你自己私自錄製,傳出去,就是用這個跑馬燈就可以追蹤到你的,他官方給的實例就是這樣

 

但其實,因為我電腦裝了IDM工具,且它這個視頻只是展示,還沒有真正的加密(看到後面的你就知道為什麼沒有真正的加密了),所以我的IDM自動嗅探視頻地址

 

且還支持持斷點播放

 

但是這個由於是案例,所以利用IDM直接就可以下載,且播放時還沒有水印:

 

 

好的,演示的視頻就是這樣了。

 

代碼實現

 

前期準備:

你需要註冊一個保利威的賬號,然後拿到id和secret,點設置 - API介面:

 

 

註意id和secretkey以及token,這裡的token有讀的和寫的,後期會用到 

 

上傳視頻

上傳一個測試的視頻,上傳的時候設置加密參數

 

上傳之前開啟加密設置

把加密設置打開,然後下麵的移動端加密按你自己的需求來,我這裡暫且不設置 

 

相關的更多的視頻配置參數:傳送門

 

好的,我這裡開始上傳,我上傳了一首歌的MV:

 

 上傳完之後平臺自動解碼,然後就會有一個視頻加密的id了:

轉碼之後,審核:

 

在審核的時候你就可以做一些相關的視頻設置:

 

這裡還有很多的設置,不一一展示,自己體驗了

 

 

等待大概一兩分鐘之後,顯示已發佈,表示可以用了:

 

其他參數配置

這裡還有一些設置,比如播放功能變數名稱設置,這些就自己去體驗了,我這裡這些都直接用預設的

 

 

 

查看官方文檔:

傳送門

 

看文檔得知有兩個步驟:

  • 服務端獲取token,將token給客戶端
  • 客戶端拿到token,開始播放視頻

 

 

獲取token

 

 

他官方文檔給的是php的,不存在,後面重構成Python的就行了

 

播放:

 播放有兩種播放形式,一種是直接在playsafe里傳一個token,一種是給一個函數,函數必須帶視頻id和next,next是一個函數,在獲取token之後將token傳到next里即可,而這官方給的文檔是next(playsafe),這裡有個坑,不是傳playsafe,而是傳token,我在這卡了很久

 

 

再次強調:視頻如果是加密的,需要設置加密參數 playsafe,playsafe有兩種形式,一個是傳token,一個是傳函數+next回調函數,且函數必須把token作為值傳進去

 

下麵還有更多的配置,切換視頻之類的,不一一展示了,自己研究

 

代碼實現:

創建一個djangorestframework的項目,項目名為EncryptVideo,app名為app:

 

url:

 

polyv對象,在項目根目錄創建utils文件夾,該文件夾下創建polyv文件,定義一個Polyv對象

 

利用了設計模式里的單例模式返回一個polyv_video對象

 

  

view:request.META.get('REMOTE_ADDR') 可以獲取客戶端的IP地址    導入那個polyv對象

 

 

 html,註意返回數據的層級,這個得根據你返回的數據來定

在這之前,我建議最好寫一個解決跨域請求的中間件,也放在utils目錄下:

 

 

啟動項目:Python manage.py runserver localhost:8000

 

那個html文件利用pycharm的功能從瀏覽器打開:

 

展示結果,朋友們,如果你遇到了這些坑,可以按我的方法試試

 

第一個坑

(為了不浪費大家時間,我上面給的截圖其實已經是我修改過並且正確的了)

發現返回的結果,sign params invild,意思就是說sign參數無效,那麼再看官方文檔:

sign的計算規則根本由這個concated生成的:

但是這句話,有歧義,按照ASCII升序拼接,到底是先拼接了之後再按ASCII升序還是先按ASCII升序之後再拼接,而且他這句,按照ASCKII升序 key + value + key + value ... +value 拼接,確實不知道到底怎麼拼接,所以我是這樣的:

當然你也可以用列表生成式,反正怎麼舒服怎麼來,反正拼接順序就是先按key排序之後再key+value組合

 

 

第二個坑,這個坑我個人認為操作的問題,其實不算坑,如果你遇到跟我一樣的問題,那恭喜你 嘻嘻

(上面的截圖也是正確的了,不浪費大家時間)

可以顯示,但是點擊播放放不了,打開控制台,報錯了:

(ip地址可以忽略,這是我之前測試的時候遇到的問題 )

這個問題,我跟你說,看似是同源策略的問題,其實並不是,就是我前面標註的那裡:

就是因為兩個url沒有統一導致的,所以必須要統一,要嘛都在結束符【/】,要嘛都不帶

 

第三個坑,錯誤的以為保利威方給你報同源策略錯誤

(上面截圖也是已經是正確的了)

 

展示結果還是不能播放,並且連視頻縮略圖都沒了,而且如圖: 

 

這個問題我是耗在這耗時最久的,報錯的意思就是跨域請求了,瀏覽器同源策略的問題,但是我把本地的啟動ip改成了我區域網的ip【192.168.0.8:8000】,html部分axios非同步請求那裡的也是【192.168.0.8:8000】,然後在django配置文件的這裡,我添加了這個

 

中間價對response的設置前面也設置了,啟動還是不行,後面突然醒悟過來,列印看token是否有拿到,確實有拿到

 

而且在我們這個平臺,保利威,客戶三者之間的關係,其實是這樣的:

 

也就是說,這個問題就是因為第2步之後的第3步上卡住,產生了跨域請求,所以這跟我們沒多大關係了,是保利威視頻那邊的問題。前面這句話前半句是對的(“第2步之後的第3步上卡住了”),後面的分析都是錯的,但是當時的我不知道啊,按著錯誤的思路,我想了想,我在保利威後臺設置了一個視頻功能變數名稱白名單:localhost:8000

 

有朋友回問,保利威那邊預設不就是對任何功能變數名稱都沒有限制的嗎?是啊,但是我還是設置了,設置之後,果然還是不行,我還溯源,準備從這個next參數的開始:

 

我還去分析了他們的那個js文件,想找找next到底是什麼:

 

 發現簡直無從下手的。最後我就真的以為是保利威那邊的問題功能變數名稱問題,就是要設置那個功能變數名稱才行,但是我這裡改下,那裡改下還成功了:

 

可以播放了,可以調播放速度啥的,註意,預設打開沒有聲,是因為預設音量按鈕沒開,自己點那個喇叭圖標打開音量

 

那按著這個錯誤的思路,有朋友會說,我設置功能變數名稱是127.0.0.1:8000,把項目的啟動ip也啟動為本地地址看看:

訪問:

 

所以還是不能直接是ip地址。

 

但是!但是,根據我的經驗,我還是不太放心,我又新建了一個django項目:

 

邏輯一樣,然後啟動的就是127.0.0.1:8001,然後保利威視頻功能變數名稱限制我也刪了:

 

發現照樣能播放:

最後經我的研究發現,還是獲取token那裡有問題,我把代碼重新寫的非常淺顯明瞭,什麼列表生成式的寫法都棄了,就為了讀代碼順暢(上面的代碼截圖給的已經是正確的了)

 

 

 

 

結果這樣確實可以正常獲取token,然後next函數傳入token就直接播放了。

所以我錯誤的以為保利威那邊的問題,饒了很久才發現。

以上是我個人的從分析問題,走錯分析的路掉進坑了,然後得到的總結,如果你們沒有遇到,一氣呵成,那麼你很棒,反正我是遇到了這些坑,最後不放心又測試了一次才找到根本問題的。當然以上都是我個人推斷,不代表絕對正確

 

 

好的,怎麼代表我們真的配置好了呢?再上傳一個視頻,然後播放看看,如果真的沒問題,那以後就沒問題了,我開始上傳,並修改html上的id

瀏覽器打開:

 

 

 

 

 

 

 

相關代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>保利威視頻測試</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script>

</head>
<body>
<div id="player"></div>
<script src="//player.polyv.net/script/player.js"></script>
<script>
    var player = polyvPlayer({
        wrap: '#player',
        width: 800,
        height: 533,
        vid: '2f57a436189b03930638e752c9a3761e_2',  // 視頻id,對應賬號里的視頻id
        playsafe: function (vid, next) {
            axios.request({
                url: "http://localhost:8000/polyv",
                method: "POST",
                data: {
                    vid: vid
                }
            }).then(function (data) {
                console.log(data.data);
                next(data.data.token);
            })
        }
    });
</script>

</body>
</html>
html
from django.contrib import admin
from django.urls import path
from app.views import Polyv

urlpatterns = [
    path('admin/', admin.site.urls),
    path('polyv', Polyv.as_view()),  # 這裡要與客戶端url對應,最後有沒有【/】要統一
]
urls
from django.conf import settings
import time
import requests
import json
import hashlib


class PolyvPlayer(object):
    userId = settings.POLYV_CONFIG['userId']
    secretkey = settings.POLYV_CONFIG['secretkey']

    def tomd5(self, value):
        """取md5值"""
        return hashlib.md5(value.encode()).hexdigest()

    # 獲取視頻數據的token
    def get_video_token(self, videoId, viewerIp, viewerId=None, viewerName='', extraParams='HTML5'):
        """
        :param videoId: 視頻id
        :param viewerId: 看視頻用戶id
        :param viewerIp: 看視頻用戶ip
        :param viewerName: 看視頻用戶昵稱
        :param extraParams: 擴展參數
        :param sign: 加密的sign
        :return: 返回點播的視頻的token
        """
        ts = int(time.time() * 1000)  # 時間戳
        plain = {
            "userId": self.userId,
            'videoId': videoId,
            'ts': ts,
            'viewerId': viewerId,
            'viewerIp': viewerIp,
            'viewerName': viewerName,
            'extraParams': extraParams
        }

        # 按照官方文檔,將參數 按照ASCKII升序 key + value + key + value... + value 拼接

        plain_sorted = {}
        key_temp = sorted(plain)
        for key in key_temp:
            plain_sorted[key] = plain[key]
        print(plain_sorted)

        plain_string = ''
        for k, v in plain_sorted.items():
            plain_string += str(k) + str(v)
        print(plain_string)

        sign_data = self.secretkey + plain_string + self.secretkey

        # 取sign_data的md5的大寫
        sign = self.tomd5(sign_data).upper()

        # 新的帶有sign的字典
        plain.update({'sign': sign})

        print('plain', plain)
        result = requests.post(
            url='https://hls.videocc.net/service/v1/token',
            headers={"Content-type": "application/x-www-form-urlencoded"},  # 一定要帶上這個請求頭
            data=plain
        ).json()
        data = {} if isinstance(result, str) else result.get("data", {})
        return {"token": data}

polyv_video = PolyvPlayer()
polyv.py
from django.utils.deprecation import MiddlewareMixin


class MyCorsMiddelware(MiddlewareMixin):
    def process_response(self, request, response):
        response["Access-Control-Allow-Origin"] = "*"
        if request.method == "OPTIONS":
            response["Access-Control-Allow-Headers"] = "*"
        return response
middlewares
# --------- 保利威視頻註冊用戶id和key--------

POLYV_CONFIG = {
    'userId': '您的id',  # polyv 提供的伺服器間的通訊驗證
    'secretkey': '您的secret'  # polyv 提供的介面調用簽名訪問的key
}
settings部分
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from django.http import HttpResponse
from utils.polyv import polyv_video
import json


class Polyv(APIView):

    def post(self, request):
        vid = request.data.get("vid")
        remote_addr = request.META.get("REMOTE_ADDR")
        user_id = 1
        user_name = "test"
        verify_data = polyv_video.get_video_token(vid, remote_addr, user_id, user_name)
        return Response(verify_data["token"])
views

 

 

播放跑馬燈

 

以上步驟其實已經可以滿足大部分用戶了,但是有朋友發現了,這裡還是可以用IDM直接下載啊:

 

所以接下來就要設置跑馬燈了

 

1.設置視頻授權跑馬燈

根據我的觀察,好像預設就開啟了跑馬燈的

 

2.設置一個授權地址

這個地址可以是本地的

 

3.創建一個html文件,名字隨意,存入如下代碼:

 

 

這裡的功能變數名稱部分,官方建議這樣設置,其實在後面我測試的時候,發現按照下麵這個設置,相容性不好,谷歌可以播放,IE瀏覽器放不了

 

4.url部分添加一個crossdomain.xml

指向test_bolyv視圖函數

視圖函數:

 

 

5.視頻介面/polyv添加get方法

這個get方法是保利威後臺自動調用的,不是我們這邊服務端要用的,也不是客戶端要用的

user_name部分就是要顯示的跑馬燈數據

 

6.在定義的polyv類里添加方法:

get_play_key和get_resp

 

get_play_key是獲取sign的,註意這裡的設置sign和上面獲取加密視頻的sign不太一樣

 

 

get_resp是做跑馬燈授權的:

 

 

 

7.引入新的js

 

這裡他給的例子是用的不加密的方式

 

我們要播放加密視頻,當然還是得使用playsafe參數播放,在templates目錄下新建一個tests.html,代碼如下,我標註出來的就是添加的參數,同樣的,註意返回數據的層級

 

 

 

啟動項目:

 

 通過pycharm虛擬一個客戶端出來,點擊那些瀏覽器圖標打開,我的電腦是windows,所以試了谷歌,火狐和IE

 

谷歌:谷歌預設打開是沒有聲音的,這是谷歌瀏覽器的策略問題,不是大問題,正常播放,且正常顯示跑馬燈

 

IE:

再次強調,如果在那個xml文件里,你如果按官方的建議設置成這樣:

然後你打開IE是播放不了的:

 

所以別按它建議的設置,就用預設的

 

 

火狐:

問題來了,就是這個問題,我折騰老久了,這個根本原因還是跨域請求問題,因為火狐瀏覽器預設安全性比較高,所以谷歌和IE可以,就是火狐不行,我查閱了很多,比如關閉火狐的跨域請求的,設置跨域請求的,設置了很多,還是沒用,最後使用了第三方庫django-cors-headers解決了,相關介紹安裝文章: 前後端分離djangorestframework——解決跨域請求  第5個方法

 

 

根據操作,重啟項目,火狐立馬播放:

 

  

然後現在你看我用IDM點下載:

 

我隨便選了一個:

 

提示:

 

 

最後再來個輔助測試,換個視頻id播放看看,換回這個視頻

 

火狐,谷歌,IE:

 

 

確實沒有問題了,這樣的操作是不是很6啊,我反正感覺很6

 

 

詳細的參數配置步驟就沒展開了,具體看官方文檔吧:傳送門

 

相關代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src='https://player.polyv.net/script/polyvplayer.min.js'></script>
    <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script>
</head>
<body>
<div id="player"></div>
<script>
    var player = polyvObject('#player').videoPlayer({
        wrap: '#player',
        width: 800,
        height: 533,
        forceH5: true,
        vid: '2f57a43618b400b4f9c84fcea9b103a8_2',
        code: 'myRandomCodeValue',
        playsafe: function (vid, next) {          // 向後端發送請求獲取加密的token
            console.log(vid);
            axios.request({
                url: "http://localhost:8000/polyv",
                method: "POST",
                data: {
                    vid: vid
                }
            }).then(function (data) {
                console.log(data);
                next(data.data.token)
            })

        }
    });
</script>

</body>
</html>
前端html
<cross-domain-policy>
<allow-access-from domain="*.polyv.net"/>
</cross-domain-policy>
bolyv_test.html
from django.conf import settings
import time
import requests
import json
import hashlib


class PolyvPlayer(object):
    userId = settings.POLYV_CONFIG['userId']
    secretkey = settings.POLYV_CONFIG['secretkey']

    def tomd5(self, value):
        """取md5值"""
        return hashlib.md5(value.encode()).hexdigest()

    # 獲取視頻數據的token
    def get_video_token(self, videoId, viewerIp, viewerId=None, viewerName='', extraParams='HTML5'):
        """
        :param videoId: 視頻id
        :param viewerId: 看視頻用戶id
        :param viewerIp: 看視頻用戶ip
        :param viewerName: 看視頻用戶昵稱
        :param extraParams: 擴展參數
        :param sign: 加密的sign
        :return: 返回點播的視頻的token
        """
        ts = int(time.time() * 1000)  # 時間戳
        plain = {
            "userId": self.userId,
            'videoId': videoId,
            'ts': ts,
            'viewerId': viewerId,
            'viewerIp': viewerIp,
            'viewerName': viewerName,
            'extraParams': extraParams
        }

        # 按照官方文檔,將參數 按照ASCKII升序 key + value + key + value... + value 拼接

        plain_sorted = {}
        key_temp = sorted(plain)
        for key in key_temp:
            plain_sorted[key] = plain[key]
        print(plain_sorted)

        plain_string = ''
        for k, v in plain_sorted.items():
            plain_string += str(k) + str(v)
        print(plain_string)

        sign_data = self.secretkey + plain_string + self.secretkey

        # 取sign_data的md5的大寫
        sign = self.tomd5(sign_data).upper()

        # 新的帶有sign的字典
        plain.update({'sign': sign})

        print('plain', plain)
        result = requests.post(
            url='https://hls.videocc.net/service/v1/token',
            headers={"Content-type": "application/x-www-form-urlencoded"},  # 一定要帶上這個請求頭
            data=plain
        ).json()
        data = {} if isinstance(result, str) else result.get("data", {})
        return {"token": data}

    def get_play_key(self, vid, username, code, status, ts):
        """
        :param vid: 視頻 vid
        :param username: 響應跑馬燈展示
        :param code: 自定義參數
        :param status: 是否可播放,  1、可播放 2、禁播
        :param ts: 時間戳
        :return: 返回跑馬燈視頻的key
        """
        return self.tomd5("vid={}&secretkey={}&username={}&code={}&status={}&t={}".format(
            vid, self.secretkey, username, code, status, ts)).lower()

    @staticmethod
    def get_resp(status, username, sign, msg="授權暫未通過"):
        res_str = {
            "status": status,
            "username": username,
            "sign": sign,
            "msg": msg,
            "fontSize": "18",
            "fontColor": "0xFF0000",
            "speed": "50",
            "filter": "on",
            "setting": "2",
            "alpha": "0.7",
            "filterAlpha": "1",
            "filterColor": "0x3914AF",
            "blurX": "2",
            "blurY": "2",
            "tweenTime": "1",
            "interval": "3",
            "lifeTime": "3",
            "strength": "4",
            "show": "on"
        }
        return res_str


polyv_video = PolyvPlayer()
polyv.py - 自定義的polyv類
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這個主要是自己遇到很多次了,每次都去網上查改哪裡,這次記到自己這裡吧,以後把遇到的vue工具的一些問題都整理到這裡 在vue中開發的項目有時候需要到手機上看效果,但是你配好本地埠之後,會出現訪問內容 Invalid Host header 這時候需要在 webpack-dev.config.js中 ...
  • 1.傳統方式 >原型鏈 (過多繼承了沒用的屬性) Grand.prototype.lastname = 'zhang' function Grand(); } var grand = new Grand(); Father.prototype = grand; function Father(){ ...
  • 什麼是BOM? bom即browser object model 也就是瀏覽器對象模型,BOM由多個對象組成,其中代表瀏覽器視窗的window對象是BOM的頂層對象,其他對象都是該對象的子對象。 頂層對象:window 子對象:location:location 對象包含有關當前 URL 的信息; ...
  • 概述 Prometheus的主要特點 組件 結構圖 適用場景 不適用場景 安裝node_exporter,系統性能指數收集(收集系統性能情況) 下載文件 解壓並複製node_exporter應用程式到/usr/local/bin 清理下載的文件和解壓的文件夾 添加自啟動服務 添加服務配置文件 寫入配 ...
  • 都說三十而立,但現在三十成了程式員的一道坎,如果近年來你有過求職的經歷,或是你關註過智聯、前程、獵聘等招聘平臺,你會發現平臺上數以萬計的招聘信息都會要求應聘者年齡在35歲以內,對於部分科技類初創企業,公司寧願放寬教育程度的要求。也就是說,如果你的年齡大於30歲,那就不要費神來申請了,因為你很可能在自 ...
  • 一、什麼是面向對象 在用面向對象思想寫代碼之前,先瞭解一下什麼是面向對象? 個人理解: 面向對象:把現實世界里的具體物體或者邏輯世界的邏輯物體,用抽象手段,把這些物體抽象成程式能夠識別的類,使類具備物體的屬性和行為,把物體與物體之間的關聯轉換成類與類之間的關聯,用編程邏輯把這些關聯表示出來設計成程式 ...
  • import java.util.Scanner;public class Main{public static void main(String[] args) {int maxn=1000000+5;int mod=10007;int[] Fibonacci=new int[maxn];Fibo ...
  • Python描述符的使用 前言 作為一位python的使用者,你可能使用python有一段時間了,但是對於python中的描述符卻未必使用過,接下來是對描述符使用的介紹 場景介紹 為了引入描述符的使用,我們先設計一個非常簡單的類: class Product(): def __init__(self ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...