<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Ведение Блога on kenji.blog</title><link>http://kenji.blog/ru/categories/%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B1%D0%BB%D0%BE%D0%B3%D0%B0/</link><description>Recent content in Ведение Блога on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ru</language><copyright>kenjinote</copyright><lastBuildDate>Wed, 16 Jul 2025 23:36:27 +0900</lastBuildDate><atom:link href="http://kenji.blog/ru/categories/%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B1%D0%BB%D0%BE%D0%B3%D0%B0/index.xml" rel="self" type="application/rss+xml"/><item><title>Как отправлять сообщения в Slack с помощью Slack App + OAuth2</title><link>http://kenji.blog/ru/p/%D0%BA%D0%B0%D0%BA-%D0%BE%D1%82%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D1%8F%D1%82%D1%8C-%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B2-slack-%D1%81-%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%D1%8C%D1%8E-slack-app--oauth2/</link><pubDate>Wed, 16 Jul 2025 23:36:27 +0900</pubDate><guid>http://kenji.blog/ru/p/%D0%BA%D0%B0%D0%BA-%D0%BE%D1%82%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D1%8F%D1%82%D1%8C-%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B2-slack-%D1%81-%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%D1%8C%D1%8E-slack-app--oauth2/</guid><description>&lt;img src="http://kenji.blog/p/slack-app--oauth2-%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6-slack-%E3%81%AB%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E6%8A%95%E7%A8%BF%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/img.png" alt="Featured image of post Как отправлять сообщения в Slack с помощью Slack App + OAuth2" />&lt;h2 id="-как-отправлять-сообщения-с-использованием-токена-доступа-slack-web-api">✅ Как отправлять сообщения с использованием токена доступа (Slack Web API)
&lt;/h2>&lt;p>«OAuth Token (например, xoxb- и т.д.)» от Slack — это ключ для публикации сообщений с помощью &lt;a class="link" href="https://api.slack.com/methods/chat.postMessage" target="_blank" rel="noopener"
>Web API&lt;/a> от Slack.
В этом случае, в отличие от Webhook, вы выполняете &lt;code>POST&lt;/code> запрос к &lt;strong>конечной точке API Slack&lt;/strong> с заголовком &lt;code>Authorization: Bearer&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="-необходимые-условия">🔑 Необходимые условия
&lt;/h2>&lt;p>Вы должны включить &lt;strong>&lt;code>chat:write&lt;/code> в область действия OAuth&lt;/strong> в вашем приложении Slack:&lt;/p>
&lt;h3 id="шаги-настройки">Шаги настройки
&lt;/h3>&lt;ol>
&lt;li>Перейдите на &lt;a class="link" href="https://api.slack.com/apps" target="_blank" rel="noopener"
>https://api.slack.com/apps&lt;/a>&lt;/li>
&lt;li>Создайте приложение или выберите существующее&lt;/li>
&lt;li>В «OAuth &amp;amp; Permissions» &amp;gt; &lt;code>Scopes&lt;/code>
→ Добавьте &lt;code>chat:write&lt;/code>&lt;/li>
&lt;li>Выполните «Install to Workspace» или «Reinstall», чтобы получить &lt;code>Access Token&lt;/code> (например: &lt;code>xoxb-xxxxxxxxxx&lt;/code>)&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="-код-на-c-отправка-в-slack-api-через-winhttp">💻 Код на C++ (Отправка в Slack API через WinHTTP)
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;windows.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;winhttp.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#pragma comment(lib, &amp;#34;winhttp.lib&amp;#34;)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">bool&lt;/span> &lt;span class="nf">PostSlackMessage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">wstring&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">accessToken&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">channel&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">const&lt;/span> &lt;span class="kt">wchar_t&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">host&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;slack.com&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">const&lt;/span> &lt;span class="kt">wchar_t&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;/api/chat.postMessage&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">HINTERNET&lt;/span> &lt;span class="n">hSession&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">WinHttpOpen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;SlackPoster/1.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WINHTTP_ACCESS_TYPE_DEFAULT_PROXY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WINHTTP_NO_PROXY_NAME&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WINHTTP_NO_PROXY_BYPASS&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">hSession&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">HINTERNET&lt;/span> &lt;span class="n">hConnect&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">WinHttpConnect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hSession&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">host&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">INTERNET_DEFAULT_HTTPS_PORT&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">hConnect&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">HINTERNET&lt;/span> &lt;span class="n">hRequest&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">WinHttpOpenRequest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hConnect&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;POST&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">path&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">WINHTTP_NO_REFERER&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WINHTTP_DEFAULT_ACCEPT_TYPES&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WINHTTP_FLAG_SECURE&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Заголовок Authorization и Content-Type
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">wstring&lt;/span> &lt;span class="n">headers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;Content-Type: application/json&lt;/span>&lt;span class="se">\r\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">headers&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;Authorization: Bearer &amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">accessToken&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\r\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Тело JSON
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">body&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">R&lt;/span>&lt;span class="s">&amp;#34;({&amp;#34;&lt;/span>&lt;span class="n">channel&lt;/span>&lt;span class="s">&amp;#34;:&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s">&amp;#34; + channel + R&amp;#34;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;,&amp;#34;&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="s">&amp;#34;:&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s">&amp;#34; + text + R&amp;#34;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;})&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">BOOL&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">WinHttpSendRequest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hRequest&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">headers&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="n">DWORD&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="n">LPVOID&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">body&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">body&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">result&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="n">WinHttpReceiveResponse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hRequest&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Ошибка отправки&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Проверка кода статуса
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">DWORD&lt;/span> &lt;span class="n">statusCode&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">DWORD&lt;/span> &lt;span class="n">size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">statusCode&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WinHttpQueryHeaders&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hRequest&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WINHTTP_QUERY_STATUS_CODE&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="n">WINHTTP_QUERY_FLAG_NUMBER&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WINHTTP_HEADER_NAME_BY_INDEX&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">statusCode&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">WINHTTP_NO_HEADER_INDEX&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WinHttpCloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hRequest&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WinHttpCloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hConnect&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WinHttpCloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hSession&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">statusCode&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">wstring&lt;/span> &lt;span class="n">token&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;xoxb-ваш-токен-доступа&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Токен доступа
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">channel&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;ID-канала-или-#general&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Пример: &amp;#34;#general&amp;#34; или &amp;#34;C0123456789&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;Попытка отправки в Slack из C++!&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">PostSlackMessage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">channel&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Успешная отправка!&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Ошибка при отправке.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="-как-получить-id-канала">📌 Как получить ID канала
&lt;/h2>&lt;p>Использование только имени канала (например, &lt;code>#general&lt;/code>) иногда может привести к ошибке.
Более надежный способ — использовать ID из URL страницы канала в Slack.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">https://app.slack.com/client/Txxxxx/C0123456789
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ↑ Эта часть — ID канала
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="-о-типах-токенов-дополнительно">✅ О типах токенов (Дополнительно)
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Формат токена&lt;/th>
&lt;th>Назначение&lt;/th>
&lt;th>Пример&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>xoxb-...&lt;/code>&lt;/td>
&lt;td>Bot Token (Рекомендуется)&lt;/td>
&lt;td>Публикация, редактирование, удаление&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>xoxp-...&lt;/code>&lt;/td>
&lt;td>User Token (Не рекомендуется)&lt;/td>
&lt;td>Операции не связанные с ботом&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Refresh Token&lt;/td>
&lt;td>Для обновления долгосрочного токена&lt;/td>
&lt;td>Обычно не используется&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="-заключение">📝 Заключение
&lt;/h2>&lt;ul>
&lt;li>Для публикации в Slack из C++ метод Slack Web API + Bearer Token является наиболее надежным&lt;/li>
&lt;li>Используйте конечную точку &lt;code>chat.postMessage&lt;/code> с HTTPS POST&lt;/li>
&lt;li>Токен необходимо передавать в заголовке Bearer&lt;/li>
&lt;li>Канал надежнее всего указывать &lt;strong>по ID&lt;/strong>&lt;/li>
&lt;/ul></description></item><item><title>О знаке обязательного заполнения в формах ввода</title><link>http://kenji.blog/ru/p/%D0%BE-%D0%B7%D0%BD%D0%B0%D0%BA%D0%B5-%D0%BE%D0%B1%D1%8F%D0%B7%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE-%D0%B7%D0%B0%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B2-%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%85-%D0%B2%D0%B2%D0%BE%D0%B4%D0%B0/</link><pubDate>Mon, 14 Jul 2025 13:47:51 +0900</pubDate><guid>http://kenji.blog/ru/p/%D0%BE-%D0%B7%D0%BD%D0%B0%D0%BA%D0%B5-%D0%BE%D0%B1%D1%8F%D0%B7%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE-%D0%B7%D0%B0%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B2-%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%85-%D0%B2%D0%B2%D0%BE%D0%B4%D0%B0/</guid><description>&lt;img src="http://kenji.blog/p/%E5%85%A5%E5%8A%9B%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%AE%E5%BF%85%E9%A0%88%E3%83%9E%E3%83%BC%E3%82%AF%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/img.png" alt="Featured image of post О знаке обязательного заполнения в формах ввода" />&lt;p>Мы обобщили информацию об отметках &amp;ldquo;обязательно&amp;rdquo; в зарубежных пользовательских интерфейсах (формах) вместе с материалами руководств по UI.&lt;/p>
&lt;hr>
&lt;h2 id="-основные-знаки-обязательного-заполнения-и-лучшие-практики">📌 Основные знаки обязательного заполнения и лучшие практики
&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Использование звездочки (*)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Это наиболее распространенный и широко используемый способ, когда обязательные поля помечаются символом &amp;ldquo;*&amp;rdquo;.&lt;/li>
&lt;li>Однако &lt;em>&lt;em>в начале формы обязательно должно быть пояснение, например, &amp;ldquo;&lt;/em> — обязательное поле&amp;rdquo;&lt;/em>* (&lt;a class="link" href="https://www.nngroup.com/articles/required-fields/?utm_source=chatgpt.com" title="Marking Required Fields in Forms - NN/g"
target="_blank" rel="noopener"
>Nielsen Norman Group&lt;/a>, &lt;a class="link" href="https://www.csun.edu/universal-design-center/web-accessibility-criteria-required-fields?utm_source=chatgpt.com" title="Web Accessibility Criteria - Required Fields - CSUN"
target="_blank" rel="noopener"
>California State University, Northridge&lt;/a>).&lt;/li>
&lt;li>Также есть примеры использования цвета для выделения (например, красный текст).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Явное указание &amp;ldquo;Required&amp;rdquo; или &amp;ldquo;(required)&amp;rdquo; в метке&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Добавление слова &amp;ldquo;Required&amp;rdquo; в текстовую метку (label) делает его понятным для программ чтения с экрана, что улучшает доступность (&lt;a class="link" href="https://www.deque.com/blog/anatomy-of-accessible-forms-required-form-fields/?utm_source=chatgpt.com" title="The Anatomy of Accessible Forms: Required Form Fields"
target="_blank" rel="noopener"
>Deque&lt;/a>).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Совместное использование атрибутов ARIA и атрибута &lt;code>required&lt;/code> в HTML5&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>В дополнение к визуальному отображению использование &lt;code>aria-required=&amp;quot;true&amp;quot;&lt;/code> и &lt;code>&amp;lt;input required&amp;gt;&lt;/code> позволяет программно передать обязательность поля (&lt;a class="link" href="https://www.deque.com/blog/anatomy-of-accessible-forms-required-form-fields/?utm_source=chatgpt.com" title="The Anatomy of Accessible Forms: Required Form Fields"
target="_blank" rel="noopener"
>Deque&lt;/a>).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Использование &amp;ldquo;(optional)&amp;rdquo; для явного указания необязательных полей&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Вместо обязательных полей можно использовать &amp;ldquo;(optional)&amp;rdquo; для указания необязательных, что эффективно при их смешивании.&lt;/li>
&lt;li>Однако Nielsen‑Norman отмечает, что &amp;ldquo;легче принимать решения, когда обязательные поля также четко обозначены&amp;rdquo; (&lt;a class="link" href="https://www.tpgi.com/doing-whats-required-indicating-mandatory-fields-in-an-accessible-way/?utm_source=chatgpt.com" title="Doing what&amp;#39;s required: Indicating mandatory fields in an accessible ..."
target="_blank" rel="noopener"
>TPGi&lt;/a>).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="-краткое-изложение-руководств-по-ui">✅ Краткое изложение руководств по UI
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Источник&lt;/th>
&lt;th>Содержание&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>NN/g: Marking Required Fields in Forms&lt;/strong>&lt;/td>
&lt;td>Рекомендуется комбинация звездочки и пояснительного текста; отображение только необязательных полей считается недружелюбным (&lt;a class="link" href="https://www.nngroup.com/articles/required-fields/?utm_source=chatgpt.com" title="Marking Required Fields in Forms - NN/g"
target="_blank" rel="noopener"
>Nielsen Norman Group&lt;/a>).&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Deque (Anatomy of Accessible Forms)&lt;/strong>&lt;/td>
&lt;td>・Использование строки &amp;ldquo;Required&amp;rdquo; или изображения внутри метки.&lt;br>・Четко указано, что одной лишь цветовой индикации недостаточно.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>W3C Techniques (H90)&lt;/strong>&lt;/td>
&lt;td>Примеры включения звездочки или &amp;ldquo;(required)&amp;rdquo; в метку с определением значения в начале формы.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>TPGi (Doing what&amp;rsquo;s required)&lt;/strong>&lt;/td>
&lt;td>С учетом доступности комбинация звездочки, атрибута ARIA и текстовой вставки в метку оценивается как оптимальная.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Contensis Руководство по UX форм&lt;/strong>&lt;/td>
&lt;td>Кратко отмечено, что важна последовательная разметка (например, * или (optional)) .&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="-рекомендуемый-подход-к-реализации">✅ Рекомендуемый подход к реализации
&lt;/h2>&lt;ul>
&lt;li>
&lt;p>Добавьте пояснительный текст &lt;strong>в начале формы&lt;/strong> :&lt;/p>
&lt;blockquote>
&lt;p>Fields marked with * are required.
(Или все вместе: &amp;ldquo;All fields are required&amp;rdquo;, а если есть необязательные: &amp;ldquo;unless marked optional&amp;rdquo;)&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Добавление меток (Label)&lt;/strong> :&lt;/p>
&lt;ul>
&lt;li>Напишите, например, &lt;code>First Name *&lt;/code> или &lt;code>Email (required)&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Атрибуты ARIA и HTML5&lt;/strong> :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">label&lt;/span> &lt;span class="na">for&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Email &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">abbr&lt;/span> &lt;span class="na">title&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;required&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>*&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">abbr&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">label&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;email&amp;#34;&lt;/span> &lt;span class="na">required&lt;/span> &lt;span class="na">aria-required&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;true&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>Не полагайтесь только на цвет&lt;/strong> : обеспечьте поддержку как визуально, так и программно.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="-полезные-ссылки-материалы-руководств-по-ui">🔗 Полезные ссылки (материалы руководств по UI)
&lt;/h2>&lt;ul>
&lt;li>NN/g: &lt;em>Marking Required Fields in Forms&lt;/em> (&lt;a class="link" href="https://www.csun.edu/universal-design-center/web-accessibility-criteria-required-fields?utm_source=chatgpt.com" title="Web Accessibility Criteria - Required Fields - CSUN"
target="_blank" rel="noopener"
>California State University, Northridge&lt;/a>, &lt;a class="link" href="https://www.nngroup.com/articles/required-fields/?utm_source=chatgpt.com" title="Marking Required Fields in Forms - NN/g"
target="_blank" rel="noopener"
>Nielsen Norman Group&lt;/a>, &lt;a class="link" href="https://www.deque.com/blog/anatomy-of-accessible-forms-required-form-fields/?utm_source=chatgpt.com" title="The Anatomy of Accessible Forms: Required Form Fields"
target="_blank" rel="noopener"
>Deque&lt;/a>)&lt;/li>
&lt;li>Deque: &lt;em>Anatomy of Accessible Forms&lt;/em> (&lt;a class="link" href="https://www.deque.com/blog/anatomy-of-accessible-forms-required-form-fields/?utm_source=chatgpt.com" title="The Anatomy of Accessible Forms: Required Form Fields"
target="_blank" rel="noopener"
>Deque&lt;/a>)&lt;/li>
&lt;li>W3C Techniques: &lt;em>H90 Indicating required form controls&lt;/em> (&lt;a class="link" href="https://www.w3.org/TR/WCAG20-TECHS/H90.html?utm_source=chatgpt.com" title="H90: Indicating required form controls using label or legend - W3C"
target="_blank" rel="noopener"
>W3C&lt;/a>)&lt;/li>
&lt;li>TPGi: &lt;em>Indicating mandatory fields accessibly&lt;/em> (&lt;a class="link" href="https://www.tpgi.com/doing-whats-required-indicating-mandatory-fields-in-an-accessible-way/?utm_source=chatgpt.com" title="Doing what&amp;#39;s required: Indicating mandatory fields in an accessible ..."
target="_blank" rel="noopener"
>TPGi&lt;/a>)&lt;/li>
&lt;li>Contensis: &lt;em>UX Forms Guidelines&lt;/em> (&lt;a class="link" href="https://www.contensis.com/community/blog/ux-forms-guidelines?utm_source=chatgpt.com" title="Build better web forms: 15 UX guidelines that work - Contensis"
target="_blank" rel="noopener"
>Contensis&lt;/a>)&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>При необходимости мы также можем предоставить конкретные примеры кода HTML/CSS, шаблоны дизайна компонентов UI для Sketch или Figma и т. д. Пожалуйста, обращайтесь к нам!&lt;/p></description></item></channel></rss>