物联网控制台数据同步--客户端PHP、Golang脚本

2021-08-02 14:16:16 浏览数 (1)

用户的个性化业务需求需要将产品下所有设备上报的数据传输至用户自有的服务器上进行处理,平台提供了 HTTP 转发服务,将设备上报数据实时 POST 到用户的 HTTP 服务器的能力。

客户需要一个HTTP的服务器去接收控制台传过来的设备信息。http服务器需要具备的功能如下:

  • 通过token验证签名
  • 增加第三方http服务确认 请求来自物联网平台,编写在 body 中原样返回 Echostr 参数内容的示例
  • 接收控制台同步的设备信息

操作步骤

  1. 登录 物联网开发平台 ,选择【公共实例】或您购买的【标准企业实例】。
  2. 进入项目列表页面,单击【项目 ID】进入项目详情页。
  3. 单击左侧菜单【数据同步】 进入数据同步配置页面,数据同步在未设置时,默认生效状态都为关闭,HTTP 服务地址为空。
  4. 选择需要设置数据同步的产品,单击设备列表中的【设置】,即可设置该产品需要同步的 HTTP 服务地址。

5.弹出设置弹窗,输入需要设置的 HTTP 服务 URL以及token,并单击【保存】。

6.URL 保存成功后,跳转到列表页,可开启该产品的【生效状态】,完成该产品的数据同步配置。

7.如需配置项目中的多个产品,需要逐一对产品进行配置。

示例

用户收到的token验证的get请求如下:

代码语言:javascript复制
GET / HTTP/1.1
Host: **.**.**.**:4443
User-Agent: Go-http-client/1.1
Content-Type: application/json
Echostr: UPWIAFASvDUFcTEE
Nonce: testrance
Signature: abb6c316a8134596d825c5a1295bfa6f7657664d
Timestamp: 1623149590
Accept-Encoding: gzip

用户收到返回的验证参数是:

代码语言:javascript复制
HTTP/1.1 200 OK
Date: Tue, 08 Jun 2021 10:53:10 GMT
Content-Length: 16
Content-Type: text/plain; charset=utf-8

UPWIAFASvDUFcTEE
转发报文格式

平台转发至用户 HTTP 服务的报文格式如下:

代码语言:javascript复制
{
"payload": {
    "clientToken": "DEP****YAS4-38",
    "method": "report",
    "params": {
        "brightness": 58,
        "color": 2,
        "name": "dev001",
        "power_switch": 1
    }
},
"seq": 1000000000,
"timestamp": 1579055948,
"topic": "$thing/up/property/DEP****YAS4/dev001",
"devicename": "dev001",
"productid": "DEP****YAS4"
}

开发示例Golang代码如下:

代码语言:javascript复制
package main

import (
	"crypto/sha1"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"sort"
	"strings"
	"time"
)

func jsonReqRsp(w http.ResponseWriter, r *http.Request) {
	var Token string
	var arr []string
	var Signature  string
	var Echostr string
	//用户设置token
	Token = "test"
	arr = append(arr, Token)
	if r.Method =="GET"{
		//解析 header
		if len(r.Header) > 0 {
			for k,v :=range r.Header {
				fmt.Printf("%s=%sn", k, v[0])
				if k =="Echostr"{
					Echostr = v[0]
				}
				if k== "Signature"{
					Signature = v[0]
				}
				if k=="Timestamp"{
					arr = append(arr,string(v[0]))
				}
				if k=="Nonce"{
					arr = append(arr,string(v[0]))
				}
			}
		}
		//验签
		sort.Slice(arr, func(i, j int) bool {
			return arr[i] < arr[j]
		})
		tmpstr := strings.Join(arr,"")
		h := sha1.New()
		h.Write([]byte(tmpstr))
		tmpsignature := h.Sum(nil)
		result := hex.EncodeToString(tmpsignature)
		fmt.Println("tmpsignature %s: ",result)
		if result == Signature {
			fmt.Println("验签成功")
		} else {
			fmt.Println("验签失败")
		}

		// 返回json字符串给客户端
		w.WriteHeader(http.StatusOK)
		w.Header().Set("Content-Type", "application/json")
		io.WriteString(w, Echostr)
	} else if r.Method=="POST"{
		// 调用json包的解析,解析请求body
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			fmt.Println("解析失败")
			return
		}
		log.Println("req json: ",  string(body))
		//将body写入文件
		fl , err := os.OpenFile("device_report.txt",os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.ModeAppend)
		if err != nil {
			fmt.Println("失败!!!")
			return
		}
		defer fl.Close()
		n, err := fl.Write(body)
		if err != nil && n < len(body) {
			fmt.Println("失败!!!")
			fmt.Println("err:",err)
		}
	} else {
		w.WriteHeader(404)
	}


}
func main() {
	//设置监听的端口
	http.HandleFunc("/test",jsonReqRsp)
	s := &http.Server{
		Addr:           ":9090",
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	err := s.ListenAndServe()
	if err != nil {
		log.Fatal("listenAndServe: ", err)
	}

}

开发示例PHP代码如下:

代码语言:javascript复制
<?php
ini_set('display_errors',1);            //错误信息  
ini_set('display_startup_errors',1);    //php启动错误信息  
error_reporting(-1);                    //打印出所有的 错误信息  

function microtime_float()
{
        list($usec, $sec) = explode(" ", microtime());
        return ((float)$usec   (float)$sec);
}

function microtime_format($tag, $time)
{
        list($usec, $sec) = explode(".", $time);
        $date = date($tag,$usec);
        return str_replace('x', $sec, $date);
}

function getAllHeaders(){
    $headers = array();
    foreach($_SERVER as $key=>$value){
        if(substr($key, 0, 5)==='HTTP_'){
            $key = substr($key, 5);
            $key = str_replace('_', ' ', $key);
            $key = str_replace(' ', '-', $key);
            $key = strtolower($key);
            $headers[$key] = $value;
        }
    }
    return $headers;
}
#验签函数
function checkSignature($signature='',$timestamp='',$nonce='')
{
    $postsignature = $signature;
    $posttimestamp = $timestamp;
    $postnonce = $nonce;
    # 用户设置token  在此填入设置的token 
    $token = "test";
    $tmpArr = array($token, $posttimestamp, $postnonce);
    sort($tmpArr, SORT_STRING);
    $tmpStr = implode( $tmpArr );
    $tmpStr = sha1( $tmpStr );
    
    if( $tmpStr == $signature ){
        return true;
    }else{
        return false;
    }
}

$url = $_SERVER["REQUEST_URI"];
$ctype = $_SERVER['CONTENT_TYPE'];
$raw_post_data = file_get_contents('php://input');
if( $_SERVER['REQUEST_METHOD'] === 'GET'){
	
			$header = getAllHeaders();
			$signature = $header['signature'];
			$timestamp = $header['timestamp'];
			$nonce = $header['nonce'];
			$echostr = $header['echostr'];
			#验签成功与否标志 $flag			
			$flag = checkSignature($signature,$timestamp,$nonce);
			#echo 'flag:',  $flag ;
			#if ($flag === true) {
			#	#echo '验签成功',"rn";
			#}else {
			#	#echo '验签失败',"rn";
			#}
			header('Content-Type: text/plain; charset=utf-8');
			$len = 'Content-Length: ';
			$len .= strlen($echostr);
			header($len);
			echo $header['echostr'] ;

}else if( $_SERVER['REQUEST_METHOD'] === 'POST') {		
			#echo microtime() ;
			$time = microtime_float();
			$strtime = microtime_format('Ymd-His.x ', $time);
			$ctype = $_SERVER['CONTENT_TYPE'];
			echo $strtime , '#post body:' , $raw_post_data , "rn";
			file_put_contents("demo.log" ,"$strtime TYPE:$ctype BODY: $raw_post_datarn",FILE_APPEND); 
        }else{
			
		}
?>

0 人点赞