Angular 5 Material按钮点击生成Token时触发无效数组长度错误
我正在尝试用Angular 5搭配PHP实现JWT Token生成功能,测试阶段用CryptoAESJs库加密userid变量后通过POST请求发送到PHP脚本,但点击按钮触发方法时控制台抛出了数组长度无效的错误。
我的代码实现
Angular组件代码(app.component.ts)
// Imports import { Component, OnInit } from '@angular/core'; import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import * as crypto from 'crypto-js'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { constructor(private http: HttpClient) {} ngOnInit() {} getToken() { let userid = 123; let key = "coded"; let encUserID = crypto.AES.encrypt(userid, key); const headerOptions = new HttpHeaders().set ('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); const params = new HttpParams().set('userID', encUserID); this.http.post('http://aff.local/jwtTest.php', params, { headers: headerOptions, responseType: 'json' }).subscribe( res=>{ console.log(res); }, error=>{ console.log(error); } ) } }
Angular模板代码(app.component.html)
<button mat-raised-button (click)='getToken()'>Click Me</button>
PHP脚本(jwtTest.php)
<?php header('Access-Control-Allow-Origin: *'); header('Content-Type: application/JSON'); header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS'); header('Access-Control-Allow-Headers: *'); error_reporting(E_ALL); require_once "CryptoJSAES.php"; require_once('JWT.php'); ini_set('log_errors', 0); ini_set('display_errors', 1); $key = "coded"; $id = $_POST['userID']; $token = CryptoJSAES::decrypt($id,$key); $jwt = JWT::encode($token, $key); $jwtDecode = JWT::decode($jwt, $key, array('HS256')); echo json_encode($jwtDecode); ?>
错误信息
点击按钮后控制台抛出:
ERROR RangeError: Invalid array length
at WordArray.init.clamp (core.js:272)
at WordArray.init.concat (core.js:237)
at Object.pad (cipher-core.js:415)
at Object._doFinalize (cipher-core.js:492)
at Object.finalize (cipher-core.js:163)
at Object.encrypt (cipher-core.js:675)
at Object.encrypt (cipher-core.js:833)
at Object.encrypt (cipher-core.js:201)
at AppComponent.push../src/app/app.component.ts.AppComponent.getToken (app.component.ts:20)
at Object.eval [as handleEvent] (AppComponent.html:1)
我想知道这个错误是Material组件、浏览器的问题,还是Angular与PHP之间的传值问题?
问题根源分析
先给你明确结论:这个错误和Material组件、浏览器完全无关,错误堆栈已经把问题指向了crypto-js的加密逻辑——具体是在WordArray的clamp方法里触发了数组长度无效的异常,核心问题出在你调用加密方法的姿势上。
仔细看你代码里的crypto.AES.encrypt(userid, key):你直接传入了数字类型的123,但crypto-js的AES.encrypt方法要求第一个参数必须是字符串或者WordArray对象。当你传入数字时,内部处理会出现类型不兼容的问题,进而导致后续数组操作抛出长度无效的错误。
另外还有个隐藏坑:crypto.AES.encrypt返回的是一个CipherParams对象,不是直接的加密字符串,你直接把这个对象传给HttpParams.set,Angular在序列化参数时会把它转成[object Object],PHP端接收后肯定无法解密,这也是后续会踩的雷。
解决方案
修改你的Angular代码中的getToken方法,做两处关键调整:
- 将数字类型的
userid转为字符串后再加密; - 调用
encUserID.toString()获取加密后的字符串,而不是直接传递CipherParams对象:
getToken() { let userid = 123; let key = "coded"; // 把数字转为字符串,同时获取加密后的字符串 let encUserID = crypto.AES.encrypt(userid.toString(), key).toString(); const headerOptions = new HttpHeaders().set ('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); const params = new HttpParams().set('userID', encUserID); this.http.post('http://aff.local/jwtTest.php', params, { headers: headerOptions, responseType: 'json' }).subscribe( res=>{ console.log(res); }, error=>{ console.log(error); } ) }
额外验证点
另外建议你检查PHP端的CryptoJSAES.php是否和crypto-js的加密逻辑完全兼容——比如加密模式、填充方式(默认crypto-js用的是CBC模式、PKCS7填充),如果后续解密还是有问题,需要确保两端的加密配置完全匹配。
内容的提问来源于stack exchange,提问作者alim1990

