iT邦幫忙

0

laravel 項目ajax 請求成功執行取得數據,卻回報error

請教前輩大神!任何回應都感謝在先。
我在register.blade.php中

@extends('common.basic')

@section('jsLink')
<script src="{{ asset('js/common/jQuery.3.5.1.js') }}"></script>
@stop

@section('content')
.....省略

@endsection

@section('js_body')
<script>
    $(function() {
        // .....省略
        
        // 發簡訊 獲取 驗證碼
        $("#phone-label").on('click', function() {
            var phone = thePhone;
            $("#phone").attr('disabled', true);
            $.ajax({
                type: "post",
                url: "https://" + host + "/getMsn",
                data: {
                    phone: phone,
                    '_token':'{{csrf_token()}}'
                },
                success: function(result) {
                    if (result.code == 200) {
                        $("#password").removeAttr("disabled");
                        var msnTimer = null;
                        var count = 120;
                        $("#pass").addClass("pass");
                        $("#phone-label").hide();
                        msnTimer = setInterval(function() {
                            if (count == 0) {
                                clearInterval(msnTimer);
                                $("#info").hide();
                            } else {
                                $("#info").removeClass("alert-warning").addClass("alert-ok")
                                    .html(result.message + count + " 秒後失效");
                                --count
                            }
                        }, 1000) //每1秒
                    } else {
                        $("#phone-label").hide();
                        $("#info").html(result.message);
                    }
                },
                error: function(result) {
                    var result = "系統不允許的操作,2秒後系統將自動導向首頁";
                    $("#info").removeClass("alert-ok").addClass("alert-warning").html(result);
                    setTimeout(function() {
                        window.location = '/';
                    }, 2000);
                }
            })
        })
        
        // .....省略
    })
</script>
@stop

定義路由:

Route::post('getMsn', 'RegisterController@getMsn');

然後再 registerController 的 getMsn() 中

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Jenssegers\Agent\Agent;
use App\Models\Auth\GetMsnRecord;
// .....省略

class RegisterController extends Controller
{
    // .....省略
    /**
     * 點擊 #getMsn 按鈕 發 ajax 請求送出簡訊 並生成 簡訊紀錄.
     *  
     * @param  $phone
     * @return \App\Http\Auth\RegisterController
     */
    public function getMsn(Request $request)
    {
        if ($request->ajax()) {
            $agent = new Agent();
            $path = $request->path();
            $device = $agent->device();
            $browser = $agent->browser();
            // 防偽造 獲取 ip      
            if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
                $ip = $_SERVER['HTTP_CLIENT_IP'];
            } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
            } else {
                $ip = $_SERVER['REMOTE_ADDR'];
            }
            $phone = $request->phone;
            // 生成verifyCode
            $str = Str::random(1);
            $num = mt_rand(1000000, 9999999);
            $verifyCode = $str . $num;
            // 設置到期時間戳 
            $configTime = env('MESSAGE_LIVE');
            $expireTime = time() + $configTime;
            // 資料寫入 get_msn_records 資料表中
            $record = GetMsnRecord::create([
                'phone' => $phone, 'verify_code' => $verifyCode, 'config_time' => $configTime,
                'expire_time' => $expireTime, 'from_path' => $path, 'from_ip' => $ip,
                'user_device' => $device, 'user_browser' => $browser
            ]);
            $curl = curl_init();
            $url = 'https://smsapi.mitake.com.tw/api/mtk/SmSend?';
            $url .= 'CharsetURL=UTF-8';
            // parameters
            $username = config('app.message_username');
            $password = config('app.message_password');
            $data = 'username=' . $username;
            $data .= '&password=' . $password;
            $data .= '&dstaddr=' . $phone;
            $data .= '&smbody=' . $record->verify_code . ' 此驗證碼 也是 登入您帳戶的 密碼,請立即填入以 完成認證
            ( 提醒您:為了您帳戶的安全 登入後,請盡速修改 密碼 )';
            // 設定curl網址
            curl_setopt($curl, CURLOPT_URL, $url);
            // 設定Header
            curl_setopt(
                $curl,
                CURLOPT_HTTPHEADER,
                array("Content-type: application/x-www-form-urlencoded")
            );
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
            curl_setopt($curl, CURLOPT_HEADER, 0);
            // 執行 
            $output = curl_exec($curl);
            curl_close($curl);
            //echo $output;
            return ['code' => 200, 'message' => '簡訊已傳送 驗證碼 至您的手機,'];
        } else {
            return '請共同維護 網路安全 切勿進行惡意操作';
        }
    }
    // .....省略
}

執行後,能夠接收到簡訊,network 中也正確顯示 return 的訊息,但回到 register.blade.php 卻是走到 error: 中
執行結果如下圖:
https://ithelp.ithome.com.tw/upload/images/20210621/201217548fPN7cUmwZ.png

令我非常不解,因此,特向前輩大大門請教一下,希望能獲得幫助。謝謝!

0
㊣浩瀚星空㊣
iT邦超人 1 級 ‧ 2021-06-21 22:23:35
最佳解答

去理解一下 淺水員大 說的東西啦!!
一眼就看到問題了。你居然還不知道。

我在提示一下好了。你拿到的是字串還是JSON?
再提點一個。你覺得JAVASCRIPT能return東西。
最後多提點。

laravel的return最後會變成輸出你知道嘛?
(雖然這得視情況)

最後,用laravel 跑 ECHO或print是一件很蠢的事。
提點那麼多了,看你能否意會出來了。

看更多先前的回應...收起先前的回應...

我需要想想謝謝您

@㊣浩瀚星空㊣ 大大!
對於 ajax 請求已經被成功執行,而為何會走 error,真的非常不解。
照程式執行邏輯:一行一行執行程式碼,而已經走到 return['code' =>200 'message'=>......]
不是表示已經執行了成功的路嗎?
不好意思!我真是愚鈍的讓人會抓狂!

echo $output; 這一行是註解掉的,不慎沒有去除!歹勢!

多提點你一下好了。看在你還有用F12看回應的情況。
只是你看到回應的情況還不知道問題點在哪。確實基礎不好

1.AJAX只會依瀏覽器所有的回應會回傳值。
2.AJAX可以指定回應的型態,未指定則依預設值文字為主。

先告訴你這兩點。
也就是說你將後端語言及前端語言混著使用。
我認為你覺得你回應 retun []
前端就該是JSON或陣列。
這是很不好的想法。

當然,認真來說就不算你的錯。因為 laravel 發生會依照最後的回應值。自動轉換及解析成前端語言可以用的模式。(大多數都是JSON就是了)

可惜你犯了二大錯誤,才會造成你的問題。

其一就是你的AJAX,並未宣告要回傳值的類型。所以會用預設的文字模式回傳。但你又用物件方式來做判斷。導致錯誤。
這是你第一個錯誤。

再來就是你第二個錯誤。
laravel已經很貼心的幫你轉換需要的東西。你偏偏還自主的加上ECHO。
這也是我為何說你蠢的原因。
(不要覺得我說話很重,因為我以前不會用DD,也是用ECHO。是被用罵的。你犯的錯我也犯過。)

這是laravel無法判斷的點。所以你拿到的回傳。會有你那段ECHO的字串值。再加上laravel幫你轉好的JSON值。(從network中也可以很明顯的看出來先有一段字串值,再來一段JSON值)
這才是你最大的錯誤。

以上,我已經幫你將你的錯誤指點出來了。你自已再好好的看好。
這些都是基本的東西,並不是中高階的知識。要能聽懂進去好好學。

我忘了說了。補充一下AJAX要宣告回傳類型。是用dataType

非常感謝?!首先跟您道歉:我沒有使用echo那是我疏忽忘了刪除,我會再仔細想想或再多查查資料的,太晚了不好意思打擾,晚安??

問題已經解決,謝謝 @㊣浩瀚星空㊣ 大的提醒!
解決之道就是取消:
// return ['code' => 200, 'message' => '簡訊已傳送 驗證碼 至您的手機,'];
然後register.blade 不用if () 判斷,直接顯示即可

淺水員 iT邦研究生 1 級 ‧ 2021-06-22 10:00:00 檢舉

可以試試看恢復

return ['code' => 200, 'message' => '簡訊已傳送 驗證碼 至您的手機,'];

說不定還是可以正常(如果昨天真的只是因為頁面尚未更新)

我試過
return ['code' => 200, 'message' => '簡訊已傳送 驗證碼 至您的手機,'];
以及
return $output
都會走到error 中去
目前解決方法
只有寫一個
return

淺水員 iT邦研究生 1 級 ‧ 2021-06-22 11:56:39 檢舉

走到 error 我會直接想到兩種原因,提供參考

  • 狀態碼不是 200
  • 設定 dataType: 'json' 但回傳的資料不符合 json 格式

好的,我再來試試看,謝謝!

我看他的AJAX並沒宣告 dataType
所以回傳的資料會用文字處理。
然後用物件方式判斷

if(result.code==200)

另外新的圖片是報419錯誤。那就是TOKEN的問題。

也就是說,其實你改來改去,會一直碰到不同的錯誤。

首先你要先做以下事

1.AJAX,先宣告好 dataType : 'json'。這樣確保你要拿到JSON的東西。
2.回傳的值統一都是陣列的格式。laravel會幫你轉成JSON輸出。
不要像這邊

return ['code' => 200, 'message' => '簡訊已傳送 驗證碼 至您的手機,'];
        } else {
            return '請共同維護 網路安全 切勿進行惡意操作';
        }

又回傳陣列,又回傳字串。理論上你的

return '請共同維護 網路安全 切勿進行惡意操作';

因該也是要改成

return ['code' => 500, 'message' => '請共同維護 網路安全 切勿進行惡意操作'];

的陣列格式才對。

不要以為前端能幫你處理。

剛剛試了2次重開

return ['code' => 200, 'message' => '簡訊已傳送 驗證碼 至您的手機,'];

模板寫法2次:

contentType: 'application/x-www-form-urlencoded',
以及
dataType: 'application/x-www-form-urlencoded',

但是一樣都跑error,在F12 network response 中顯示:

{"code":200,"message":"\u7c21\u8a0a\u5df2\u50b3\u9001 \u9a57\u8b49\u78bc \u81f3\u60a8\u7684\u624b\u6a5f\uff0c"}

我猜一定是我的寫法不對,導致解析錯誤才會跑到 error,但這樣寫都不對的話,還能怎麼寫呢?
我還蠻想改回來的。

昏了!!
有多少人跟你說是

dataType :'json',

為何你會自創成

dataType: 'application/x-www-form-urlencoded',

改正好一個錯誤??然後自已再追加一個錯誤??
你是怎麼了??

歹勢!因為回應數受限,回覆晚了,目前我的狀況已經改善到理想狀態了,最重要的是:我在Controller 中加了一段代碼如下:curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
加了之後就完全沒問題??

0
淺水員
iT邦研究生 1 級 ‧ 2021-06-21 21:00:36
  1. 回傳的 status code 是什麼?
  2. 這邊需要 echo 嗎?
echo $output;
return ['code' => 200, 'message' => '簡訊已傳送 驗證碼 至您的手機,'];
看更多先前的回應...收起先前的回應...

是的,需要讓使用者清楚步驟!

人家在點你了還不自覺。
還回答的理所當然

我只是據實說明我的確需要將已經送出簡訊的通知,而走到了error讓我的訊息會出錯,也許我一時之間無法體會@潛水員大大的意思!還希望大大們能不耐其煩,詳細說明一下!謝謝?!

淺水員 iT邦研究生 1 級 ‧ 2021-06-22 00:01:45 檢舉

我指的是看一下回應的狀態碼是多少(參考下圖紅框)
https://ithelp.ithome.com.tw/upload/images/20210621/20112943AckOznBEJH.png

要知道,狀態碼不是寫 'code' => 200 就是 200
那個 'code' => 200 只是說穿了只算是內文(response body)
不一定會是實際的狀態碼
(jquery 的 ajax 遇到狀態碼不是200的話,會視為 error)

至於 echo 又 return 有可能會導致 laravel 要設定 header 時發生錯誤,或是 js 嘗試解析為 json 時出錯。
至於是哪個環節我還沒測試,所以才問狀態碼是多少。

@淺水員 前輩 補上 2張 F12的訊息圖,我沒有ECHO ,真的不知道哪裡寫錯導致 ajax 判定為 error,還希望前輩費心幫我看一下。謝謝!
https://ithelp.ithome.com.tw/upload/images/20210622/20121754rFIxgNm4Yh.png
https://ithelp.ithome.com.tw/upload/images/20210622/20121754rcdjd8FAgf.png

@淺水員 前輩 補上 2張 F12的訊息圖,我沒有ECHO ,真的不知道哪裡寫錯導致 ajax 判定為 error,還希望前輩費心幫我看一下。謝謝!
https://ithelp.ithome.com.tw/upload/images/20210622/20121754VkSMgPiCMj.png

https://ithelp.ithome.com.tw/upload/images/20210622/20121754eTTKpm1iMu.png

淺水員 iT邦研究生 1 級 ‧ 2021-06-22 09:49:52 檢舉
  1. 419 是 laravel 自己定義的狀態碼,意思是 csrf 有問題。這部份建議真的去解決它。
  2. jquery 的 ajax 或是 XMLHttpRequest 是用 dataType : 'json',而 application/json 通常是伺服器端送的,很少出現在 javascript。
淺水員 iT邦研究生 1 級 ‧ 2021-06-22 09:57:20 檢舉

我猜有可能你之前沒有寫 '_token':'{{csrf_token()}}'
後來有補上,但是網頁還沒更新
一直用舊的頁面在呼叫 api

有可能自己測試太多次,改來改去而遺漏了,謝謝您讓我從中領會到新知識

0
小魚
iT邦大師 1 級 ‧ 2021-06-21 22:15:00

1.在success的地方印看看result會不會出來, 是不是result.code出錯?
2.你有看過error回傳回來的result是甚麼嗎?
3.後端嘗試改成return json_encode(...)試試
要通靈真的很難.

小魚大!我剛剛測試console.log (result)結果如下圖:
非常感謝費心!
https://ithelp.ithome.com.tw/upload/images/20210621/20121754mQ682th0c7.png

https://ithelp.ithome.com.tw/upload/images/20210621/20121754IfyX3j5L68.png

0
japhenchen
iT邦大師 1 級 ‧ 2021-06-22 08:22:05

你的$.ajax沒有給dataType
看你的getMsn後面串了個json string猜測你應該是要在$.ajax裡加個

  $.ajax({
                type: "post",
                dataType : 'json', // ←←←←←←←← 這個
                url: "https://" + host + "/getMsn",
                data: {
                    phone: phone,
                    '_token':'{{csrf_token()}}'
                },
看更多先前的回應...收起先前的回應...

mermer..... 我蠻討厭javascript一堆加都不知道是加數字還是加字串....所以我會這樣寫

url: `https://${host}/getMsn`,

string interpolation 字串插補

謝謝您的協助回應,這問題似乎跟url無關,而且目前問題已經解決。
還是謝謝您!

加了dataType : 'json', 會報錯!
我有追加這個
contentType: 'application/x-www-form-urlencoded',

字串插補不是解決你的問題的方法啦,只是我不喜歡在我的網頁背後看到一堆 +

ps .. 如果你直接使用$.post就可以不用加contentType

喔!現在才領會了前輩的意思,我會試試看您的意見,感恩

我要發表回答

立即登入回答