为了账号安全,请及时绑定邮箱和手机立即绑定

如何处理 DirectLine 连接错误

如何处理 DirectLine 连接错误

阿波罗的战车 2023-03-03 15:19:51
我们使用 bot 框架运行一个 bot,并使用 JS 中的直线从我们的网站连接到它。我们从自定义 API 端点获取令牌,并将令牌存储在 sessionStorage 中。然后我们使用连接到机器人directLine = await window.WebChat.createDirectLine({  token,  conversationId,  watermark: "0"});一切正常,但是当我让页面打开的时间过长时,sessionStorage 中的令牌会过期。页面刷新或导航到不同的页面会导致方法内部出现 403 错误createDirectLine。只要 sessionStorage 持有该令牌,就会导致聊天机器人无法连接。这种行为对我来说并不奇怪,但我不知道如何处理。我想要的是简单地清除 sessionStorge,请求一个新令牌并在发生这种情况时开始新对话。但我不知道该怎么做。如何从该方法中获取 403 错误createDirectLine?或者有没有办法预先验证令牌?我已经尝试在该createDirectLine方法周围放置一个 try/catch 块,但是 403 错误没有出现在 catch 中。
查看完整描述

2 回答

?
红糖糍粑

TA贡献1815条经验 获得超6个赞

此解决方案仅用于解决令牌过期后发生的 403 错误(我认为在 30 分钟内)。更好的解决方案是将 conversationId 与令牌一起存储并使用它获取新令牌。检查官方机器人服务文档

// to shorten code, we store in sessionStorage as separate items.

const expirationDuration = 1000 * 60 * 30; // 30 minutes

const currentTime = new Date().getTime();

const timeTokenStored = sessionStorage.getItem("timeTokenStored") || currentTime;


// if token is stored over 30 minutes ago, ignore it and get a new one. Otherwise, use it.

if ((currentTime - timeTokenStored) > expirationDuration) {

      const res = await fetch('https://<yourTokenEndpoint>', { method: 'POST' });

      const { token } = await res.json();}

      const currentTime = new Date().getTime();

      sessionStorage.setItem("timeTokenStored", currentTime);

      sessionStorage.setItem('token', token);

else {

  const token = sessionStorage.getItem("token")

}

当您使用它时,您不妨将它存储在 localStorage 中。这样,您的机器人将跟随用户。


查看完整回答
反对 回复 2023-03-03
?
有只小跳蛙

TA贡献1824条经验 获得超8个赞

我找到了解决方案。我们可以通过刷新令牌来检查令牌是否有效。如果刷新导致错误,则令牌不再有效。如果刷新成功,令牌将再有效一个小时。


因此,我们向后端添加了(可重用的)函数以使用https://directline.botframework.com/v3/directline/tokens/refresh. 我们更改了前端代码以调用我们新的刷新功能。


前端代码:


// Gets a new token from the cloud.

async function requestToken() {

  if (!sessionStorage['webchatToken']) {

    const res = await fetch('https://' + serviceName + '.azurewebsites.net/api/token');

    // If the request was succesfull, store the token and userId.

    if (res.status == 200) {

      const jsonResult = await res.json();

      sessionStorage['webchatToken'] = jsonResult.token;

      sessionStorage['webchatUserId'] = jsonResult.userId;

      console.log(`Got token from cloud`);


      // refresh the token every 15 minutes.

      setTimeout(() => {

        refreshToken();

      }, 60000 * 15); // 15 minutes

    }

    // If the request was not succesfull, retry.

    else {

      console.log(`Tried to get token, but goterror ` + res.status + `. Retrying.`);

      await requestToken();

    }

  }

  // If there is already a token in storage, refresh the existing one instead of requesting a new one.

  else {

    console.log(`Got token from sessionStorage`);

    await refreshToken();

  }

}


// Refreshes an existing token so it doesn't expire.

async function refreshToken() {

  // Refresh the token if it exists in storage.

  if (sessionStorage['webchatToken']) {

    const res = await fetch('https://' + serviceName + '.azurewebsites.net/api/token/refresh?token=' + sessionStorage['webchatToken'],

    {

      method: 'POST'

    });

    // If refresh was succesfull we are done.

    if (res.status == 200) {

      console.log(`Refreshed token`);

    }

    // If refresh was not succesfull, clear the token from storage and request a new one. The token is probably expired.

    else {

      console.log(`Tried to refresh token, but got error ` + res.status + `. Requesting new token.`);

      sessionStorage.clear();

      await requestToken();

    }

  }

  // If there is no token in storage, request a new token.

  else {

    console.log(`Tried to refresh token, but token is not defined. Requesting new token.`);

    sessionStorage.clear();

    await requestToken();

  }

}

后端代码:


[HttpGet]

[Route("api/token")]

public async Task<ObjectResult> GetToken()

{

  HttpClient client = new HttpClient();


  HttpRequestMessage request = new HttpRequestMessage(

    HttpMethod.Post,

    $"https://directline.botframework.com/v3/directline/tokens/generate");

 

  request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _configuration.DirectLineKey);


  var userId = $"dl_{Guid.NewGuid()}";


  request.Content = new StringContent(

    JsonConvert.SerializeObject(new { User = new { Id = userId } }),

    Encoding.UTF8,

    "application/json");


  var response = await client.SendAsync(request);

  string token = String.Empty;

  int expiresIn = 0;


  if (response.IsSuccessStatusCode)

  {

    var body = await response.Content.ReadAsStringAsync();

    token = JsonConvert.DeserializeObject<DirectLineToken>(body).token;

    expiresIn = JsonConvert.DeserializeObject<DirectLineToken>(body).expires_in;

  }


  return Ok(new { token, userId, expiresIn });

}


[HttpPost]

[Route("api/token/refresh/")]

public async Task<ObjectResult> RefreshToken(string token)

{

  HttpClient client = new HttpClient();


  HttpRequestMessage request = new HttpRequestMessage(

    HttpMethod.Post,

    $"https://directline.botframework.com/v3/directline/tokens/refresh");


  request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);



  var response = await client.SendAsync(request);

  token = String.Empty;

  int expiresIn = 0;


  if (response.IsSuccessStatusCode)

  {

    var body = await response.Content.ReadAsStringAsync();

    token = JsonConvert.DeserializeObject<DirectLineToken>(body).token;

    expiresIn = JsonConvert.DeserializeObject<DirectLineToken>(body).expires_in;

  }


  if (string.IsNullOrEmpty(token))

    return Problem("Token incorrect");


  return Ok(new { token, expiresIn });

}

我希望发布这个可能对某人有用。


查看完整回答
反对 回复 2023-03-03
  • 2 回答
  • 0 关注
  • 185 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号