성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>.NET Core HttpClient의 HTTP/2 지원</h1> <p> 지난 글까지 HTTP/2의 서버 측 지원을 알아봤는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > IIS의 HTTP/2 지원 여부 - h2, h2c ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12495'>https://www.sysnet.pe.kr/2/0/12495</a> ASP.NET Core(Kestrel)의 HTTP/2 지원 여부 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12500'>https://www.sysnet.pe.kr/2/0/12500</a> </pre> <br /> 그렇다면 클라이언트 측도 마저 다뤄야겠지요. ^^ 쉬운 테스트를 위해 서버는 nghttp2.org로 정했고, HttpClient는 기본적인 구성부터 시작해 .NET Core 3.1 환경으로 테스트를 해보겠습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // .NET Core 3.1 using System; using System.Net.Http; using System.Threading.Tasks; class Program { private static readonly HttpClient _client; static Program() { _client = new HttpClient(); } static async Task Main() { try { { using var response = await _client.GetAsync("<span style='color: blue; font-weight: bold'>http</span>://nghttp2.org"); Console.WriteLine(response.Version); } { using var response = await _client.GetAsync("<span style='color: blue; font-weight: bold'>https</span>://nghttp2.org"); Console.WriteLine(response.Version); } } catch (HttpRequestException ex) { Console.WriteLine(ex.ToString()); } } } /* 출력 결과 1.1 1.1 */ </pre> <br /> http와 https 모두 1.1 응답을 받고 있는데요, 왜냐하면 HttpClient의 기본 버전은 1.1이고 TLS 협상 시 h2 식별자를 사용하지 않기 때문입니다. 따라서, 명시적으로 HTTP/2 통신을 하려면 버전을 지정해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > static Program() { _client = new HttpClient() { // curl의 --http2-prior-knowledge 옵션과 유사한 역할 <span style='color: blue; font-weight: bold'>DefaultRequestVersion = new Version(2, 0),</span> }; } /* 출력 결과 1.1 2.0 */ </pre> <br /> 그래도 https의 경우에만 2.0으로 통신이 되었고 http의 경우에는 여전히 1.1로 됩니다. 이유는 애당초 HttpClient는 h2c 모드를 지원하지 않기 때문입니다. 다행히 마이크로소프트는 이를 위해 .NET Core 3.0에서 "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport" 전역 설정을 추가했는데요,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > static Program() { <span style='color: blue; font-weight: bold'>AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);</span> SocketsHttpHandler handler = new SocketsHttpHandler(); _client = new HttpClient(handler) { DefaultRequestVersion = new Version(2, 0), }; } /* 출력 결과 2.0 2.0 */ </pre> <br /> 이제야 비로소 http와 https에 대해 모두 HTTP/2 통신을 할 수 있게 됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그런데, .NET 5부터 이런 정책이 바뀌었습니다. 위의 예제 코드를 실행하면, 다시 "1.1"과 "2.0" 출력을 확인할 수 있는데요, 결국 "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport" 옵션 설정이 아무런 효력을 내지 못하고 있는 것입니다. (달리 말해, 하위 호환성이 깨지므로, HTTP/2 통신을 하는 기존 코드는 .NET 5로 마이그레이션 시 반드시 코드 변경을 해야 합니다.)<br /> <br /> 이에 대해서는 아래의 문서에서 언급하고 있으며,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > HTTP/2 - Version Selection ; <a target='tab' href='https://devblogs.microsoft.com/dotnet/net-5-new-networking-improvements/#version-selection'>https://devblogs.microsoft.com/dotnet/net-5-new-networking-improvements/#version-selection</a> </pre> <br /> 따라서 .NET 5부터는 VersionPolicy 속성을 통해 이를 제어해야 합니다. 가령, 기존의 .NET Core 3.x 코드를 .NET 5로 마이그레이션한다면 다음과 같이 HttpVersionPolicy.RequestVersionExact 옵션을 설정하면 동일하게 동작할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > static Program() { SocketsHttpHandler handler = new SocketsHttpHandler(); _client = new HttpClient(handler) { // curl의 --http2-prior-knowledge 옵션과 유사한 역할 <span style='color: blue; font-weight: bold'>DefaultVersionPolicy = HttpVersionPolicy.RequestVersionExact,</span> DefaultRequestVersion = new Version(2, 0), }; } </pre> <br /> 버전 선택 정책에 대한 좀 더 자세한 동작 방식은 다음의 글에 별도로 정리했으니 참고하시고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .NET 5부터 HTTP/1.1, 2.0 선택을 위한 HttpVersionPolicy 동작 방식 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12501'>https://www.sysnet.pe.kr/2/0/12501</a> </pre> <br /> 한 가지 유의할 것은, HttpClient의 경우 h2c 협상에 준하는 동작은 없다는 점입니다. 즉, 처음부터 HTTP/2 또는 HTTP/1.1로 통신을 게시하는 방식입니다.<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1718&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1924
(왼쪽의 숫자를 입력해야 합니다.)