php:異步請求實現方式有哪些?

前言

最近小編在開發過程中,遇到一些處理操作,並不需要實時返回結果,怎麼繞過等待?這個時候我們需要用到異步進行請求,長話短說。

 

一、ajax和img標籤

如果是web服務器返回html代碼給客戶端,我們可以使用一些特殊方法來實現所謂的異步,就是在返回給客戶端的HTML代碼中,嵌入ajax調用,或者,嵌入一個img標籤,src指向要執行的耗時腳本(還有一些類似script標籤)。如果客戶端不是html代碼,其實我們也可以拼接出完整的圖片鏈接(該鏈接包含處理,然後跳轉資源到圖片),然後客戶端進行展示。

 

二、使用popen()

resource popen ( string command, string mode );
//打開一個指向進程的管道,該進程由派生給定的 command 命令執行而產生。所以可以通過調用它,但忽略它的輸出。

pclose(popen("/home/xinchen/backend.php &", 'r'));

這個方法避免了第一個方法的缺點,並且也很快。但是問題是,這種方法不能通過HTTP協議請求另外的一個WebService,只能執行本地的腳本文件。並且只能單向打開,無法穿大量參數給被調用腳本。
並且如果,訪問量很高的時候,會產生大量的進程。如果使用到了外部資源,還要自己考慮競爭。

 

三、使用php的curl擴展

  • curl實現方式的本質是, 設置超時時間爲1秒或者n毫秒;
  • 注意: 如果設置超時時間爲毫秒,那麼要確認,CURL版本>=7.16.2, PHP 版本>=5.2.3.
   /**
     * 使用curl方式發送異步請求, put方式
     */
    public function _curl($url,$params) {
        $ch = curl_init();
        $headers = array("Content-type: application/json;charset='utf-8'",
            "Accept: application/json",
            "Cache-Control: no-cache","Pragma: no-cache");
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST,"PUT"); //設置請求方式
        curl_setopt($ch, CURLOPT_POSTFIELDS, $params);//設置提交的字符串
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);    //設置頭信息
        curl_setopt($ch, CURLOPT_URL, $url); // 要訪問的地址
        curl_setopt($ch, CURLOPT_RETURNTRANSFER , 1 );    //獲取的信息以文件流的形式返回
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);  //不進行ssl驗證
        curl_setopt($ch, CURLOPT_AUTOREFERER, 1); // 自動設置Referer
        //設置超時時間爲1秒,超過1秒則關閉連接
        curl_setopt($ch,CURLOPT_TIMEOUT,1);
        //curl_setopt($ch, CURLOPT_NOSIGNAL, 1);     //注意,毫秒超時一定要設置這個
        //curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200); //超時毫秒,cURL 7.16.2中被加入。從PHP 5.2.3起可使用
        curl_setopt($ch, CURLOPT_HEADER, 0); // 設置是否顯示返回頭信息  1返回 0不返回
        curl_setopt($ch, CURLOPT_NOBODY, 0); //不想在輸出中包含body部分,設置這個選項爲一個非零值
        $result = curl_exec($ch);
        curl_close($ch);
        return json_decode($result);
    }

這種方法的缺點就是你必須要等待1秒或者多少毫秒,如果程序執行很快,豈不是白等了?

 

四、使用exec

使用exec執行linux命令,交給後臺完成。

例:

exec("nohup curl xxxx.com &");

 

五、使用fsockopen

我們創建了一個基於fsockopen的函數,這個函數中利用fsockopen去訪問url,但是在訪問時,並不要求獲取url顯示的內容,而是僅僅發出訪問請求,請求到達後馬上關閉這個訪問,缺點是要拼接header。

get方式

path不需要拼接完整url,只需要路徑

<?php

$host = "xxxx.com";//主機地址,如localhost
$path = 'test/test.php';//要請求的url,如http://localhost/test/test.php
// $fp = fsockopen( 'ssl://'.$host , 443, $errno, $errstr, 30);//https請求方式
$fp = fsockopen($host , 80, $errno, $errstr, 30);
if(!$fp){
    exit('請求失敗');
}else{
    //拼接header部分
  $header = "GET $path?uid=28CSW6JO3B0N&chat_uid=2ABR5GZPRW6F&gift_id=".json_encode(['uniqid'=>2019110610157975])." / HTTP/1.1\r\n"; 
  $header .= "Host: $host\r\n"; 
  $header .= "Connection: Close\r\n\r\n";
  fwrite($fp, $header);
  // // 輸出請求結果(測試時用)
  //  $receive = '';
  //  while (!feof($fp)) 
  //  {
  //   	$receive .= ''.fgets($fp, 128);
  //  }
  //  echo "".$receive;
  fclose($fp);
}

post方式

$host = "xxx.com";//主機地址,如localhost
$path = 'http://xxx.com/test/test.php';//要請求的url
$fp = fsockopen( $host , 80, $errno, $errstr, 30);
if(!$fp){
    exit('請求失敗');
}else{
    //要發送的數據
    $data['name'] = '測試';
    $data['desc'] = '測試';
    $post = http_build_query($data);
    $len = strlen($post);

    //拼接header部分
    $header = "POST $path HTTP/1.1\r\n";
    $header .= "Host: $host\r\n";
    $header .= "Content-type: application/x-www-form-urlencoded\r\n";
    $header .= "Connection: Close\r\n";
    $header .= "Content-Length: $len\r\n";
    $header .= "\r\n";
    $header .= $post."\r\n";
    fwrite($fp, $header);
    // //輸出請求結果(測試時用)
    // $receive = '';
    // while (!feof($fp)) 
    // {
    //  $receive .= ''.fgets($fp, 128);
    // }
    // echo "".$receive;
    fclose($fp);
}

這種方法是比較好的,但是有一個缺點,你使用後會發現,偶發性請求無效,nginx狀態499。

參考:https://blog.csdn.net/panjiapengfly/article/details/103010517  解決上述問題。

 

小結:小編這裏說的其實都是比較輕便的方法,如果一些要求比較高的,可以使用隊列形式來完成。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章