You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从User Event脚本调用Restlet遇INVALID_LOGIN_ATTEMPT错误咨询

问题描述

从User Event脚本调用Restlet时收到错误:

body":"error code: INVALID_LOGIN_ATTEMPT
error message: Invalid login attempt

疑问:

  • 是否需要传递凭证?
  • 应传递Client ID、Client Secret吗?
  • 还有其他可行方法吗?
  • 尝试使用url.resolveScript但未解决问题,附上代码:
/**
* @NApiVersion 2.x
* @NScriptType UserEventScript
* @NModuleScope Public
*/
define(["N/https", "N/log", "N/record", "N/url" ],

function(https, log, record, url) {


    function beforeLoad(context) {
        // log.debug('beforeLoad Triggered');
        // context.newRecord;
        // context.type;
        // context.form;
        return;
    }
    
    function afterSubmit(context) {
      log.debug('Before code');
      var record = context.newRecord;
  var requestBody = {
"recordId": record.id,
"recordType": record.type,
 };

   var output = url.resolveScript({
scriptId: '1157',
deploymentId: '1',
 });   
var output1 = 'https://12345-sb5.restlets.api.netsuite.com';
log.debug('After code', output );   
 var response = https.post({
url: output1 + output,
body: requestBody,
 });

 if (response.code === 200) {
// success!
 } else {
 // handle error
 }
      log.debug('After code', response );
        return;
    }
    
    function beforeSubmit(context) {
        // log.debug('beforeSubmit Triggered');
        // context.newRecord;
        // context.oldRecord;
        // context.type;
        return;
    }

    return {
            beforeLoad : beforeLoad,
            afterSubmit : afterSubmit,
            beforeSubmit : beforeSubmit
        }



    })
解决方案

错误原因

User Event脚本调用Restlet时,默认不会自动携带身份认证信息,必须显式处理认证逻辑,否则会触发INVALID_LOGIN_ATTEMPT错误。你之前用url.resolveScript无效,是因为手动拼接了外部域名,破坏了该方法自动生成的带认证参数的完整URL结构。

方法1:正确使用url.resolveScript(推荐同账号内调用)

url.resolveScript会自动生成包含NetSuite域名、脚本/部署ID,以及临时认证参数的完整URL,无需手动拼接域名。修正代码如下:

function afterSubmit(context) {
  log.debug('Before code');
  var record = context.newRecord;
  var requestBody = {
    "recordId": record.id,
    "recordType": record.type,
  };

  // 正确生成Restlet的完整认证URL
  var restletUrl = url.resolveScript({
    scriptId: '1157', // 建议使用自定义脚本ID(如customscript_my_restlet)而非数字ID
    deploymentId: '1', // 同理建议用customdeploy_my_restlet
    returnExternalUrl: false // 同账号内调用设为false,默认值,生成内部可访问的带认证URL
  });   
  log.debug('Restlet URL', restletUrl);   

  var response = https.post({
    url: restletUrl, // 直接使用生成的完整URL,无需额外拼接
    body: requestBody,
    headers: {
      'Content-Type': 'application/json' // 确保请求头正确,Restlet需要JSON格式的话要加这个
    }
  });

  if (response.code === 200) {
    log.debug('Success', response.body);
  } else {
    log.error('Error', response.body);
  }
  return;
}

方法2:使用Token-Based Authentication(TBA)传递Client ID/Secret

如果需要跨账号或更安全的认证方式,可配置TBA:

  1. 在NetSuite中创建集成记录,获取Client ID和Client Secret
  2. 创建访问令牌(Token ID和Token Secret)
  3. 在请求中生成签名并添加Authorization头

示例代码(简化版):

var oauth = require('N/oauth'); // 需要引入N/oauth模块

function afterSubmit(context) {
  // ... 其他代码 ...
  
  var tokenAuth = oauth.createToken({
    consumerKey: 'YOUR_CLIENT_ID',
    consumerSecret: 'YOUR_CLIENT_SECRET',
    token: 'YOUR_TOKEN_ID',
    tokenSecret: 'YOUR_TOKEN_SECRET'
  });

  var response = tokenAuth.post({
    url: 'https://12345-sb5.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=1157&deploy=1',
    body: requestBody,
    headers: {
      'Content-Type': 'application/json'
    }
  });

  // ... 处理响应 ...
}

方法3:使用Session认证(不推荐生产环境)

如果是同账号内且脚本运行在用户会话中,可尝试传递当前用户的会话参数,但安全性较低:

  • 在请求头中添加Cookie,值为当前会话的JSESSIONID和NS_ROUTING_VERSION
  • 但这种方式依赖会话有效期,容易失效,不建议生产使用
关键注意事项
  • 确保Restlet的部署设置中,允许调用User Event脚本的角色访问
  • 使用url.resolveScript时,不要手动拼接域名,否则会丢失自动生成的认证参数
  • 传递请求体时,务必设置正确的Content-Type头(如application/json),否则Restlet可能无法解析请求

内容的提问来源于stack exchange,提问作者Krunal Patel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 16:25:32