{"id":1142,"date":"2025-05-27T14:47:32","date_gmt":"2025-05-27T06:47:32","guid":{"rendered":"https:\/\/www.hyy.net\/?p=1142"},"modified":"2025-05-27T14:47:32","modified_gmt":"2025-05-27T06:47:32","slug":"ultimate-asp-net-core-web-api-22-working-with-options-and-head-requests","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=1142","title":{"rendered":"Ultimate ASP.NET Core Web API 22 WORKING WITH OPTIONS AND HEAD REQUESTS"},"content":{"rendered":"<p>22 WORKING WITH OPTIONS AND HEAD REQUESTS<br \/>\n22 \u4f7f\u7528 OPTIONS \u548c HEAD \u8bf7\u6c42<\/p>\n<p>In one of the previous chapters (Method Safety and Method Idempotency), we talked about different HTTP requests. Until now, we have been working with all request types except OPTIONS and HEAD. So, let\u2019s cover them as well.\u200c<br \/>\n\u5728\u524d\u9762\u7684\u4e00\u7ae0\uff08\u65b9\u6cd5\u5b89\u5168\u548c\u65b9\u6cd5\u5e42\u7b49\u6027\uff09\u4e2d\uff0c\u6211\u4eec\u8ba8\u8bba\u4e86\u4e0d\u540c\u7684 HTTP \u8bf7\u6c42\u3002\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u6211\u4eec\u4e00\u76f4\u5728\u5904\u7406\u9664 OPTIONS \u548c HEAD \u4e4b\u5916\u7684\u6240\u6709\u8bf7\u6c42\u7c7b\u578b\u3002\u90a3\u4e48\uff0c\u8ba9\u6211\u4eec\u4e5f\u4ecb\u7ecd\u4e00\u4e0b\u5b83\u4eec\u3002<\/p>\n<h2>22.1 OPTIONS HTTP Request<\/h2>\n<p>22.1 OPTIONS HTTP \u8bf7\u6c42<\/p>\n<p>The Options request can be used to request information on the communication options available upon a certain URI. It allows consumers to determine the options or different requirements associated with a resource. Additionally, it allows us to check the capabilities of a server without forcing action to retrieve a resource.\u200c<br \/>\nOptions \u8bf7\u6c42\u53ef\u7528\u4e8e\u8bf7\u6c42\u6709\u5173\u7279\u5b9a URI \u4e0a\u53ef\u7528\u7684\u901a\u4fe1\u9009\u9879\u7684\u4fe1\u606f\u3002\u5b83\u5141\u8bb8\u4f7f\u7528\u8005\u786e\u5b9a\u4e0e\u8d44\u6e90\u5173\u8054\u7684\u9009\u9879\u6216\u4e0d\u540c\u8981\u6c42\u3002\u6b64\u5916\uff0c\u5b83\u8fd8\u5141\u8bb8\u6211\u4eec\u68c0\u67e5\u670d\u52a1\u5668\u7684\u529f\u80fd\uff0c\u800c\u65e0\u9700\u5f3a\u5236\u4f5c\u6765\u68c0\u7d22\u8d44\u6e90\u3002<\/p>\n<p>Basically, Options should inform us whether we can Get a resource or execute any other action (POST, PUT, or DELETE). All of the options should be returned in the Allow header of the response as a comma- separated list of methods.<br \/>\n\u57fa\u672c\u4e0a\uff0cOptions \u5e94\u8be5\u544a\u8bc9\u6211\u4eec\u662f\u5426\u53ef\u4ee5\u83b7\u53d6\u8d44\u6e90\u6216\u6267\u884c\u4efb\u4f55\u5176\u4ed6\u4f5c\uff08POST\u3001PUT \u6216 DELETE\uff09\u3002\u6240\u6709\u9009\u9879\u90fd\u5e94\u5728\u54cd\u5e94\u7684 Allow \u6807\u5934\u4e2d\u4f5c\u4e3a\u9017\u53f7\u5206\u9694\u7684\u65b9\u6cd5\u5217\u8868\u8fd4\u56de\u3002<\/p>\n<p>Let\u2019s see how we can implement the Options request in our example.<br \/>\n\u8ba9\u6211\u4eec\u770b\u770b\u5982\u4f55\u5728\u793a\u4f8b\u4e2d\u5b9e\u73b0 Options \u8bf7\u6c42\u3002<\/p>\n<h2>22.2 OPTIONS Implementation<\/h2>\n<p>22.2 OPTIONS \u5b9e\u73b0<\/p>\n<p>We are going to implement this request in the CompaniesController \u2014 so, let\u2019s open it and add a new action:\u200c<br \/>\n\u6211\u4eec\u5c06\u5728 CompaniesController \u4e2d\u5b9e\u73b0\u6b64\u8bf7\u6c42 \u2014 \u56e0\u6b64\uff0c\u8ba9\u6211\u4eec\u6253\u5f00\u5b83\u5e76\u6dfb\u52a0\u65b0\u4f5c\uff1a<\/p>\n<pre><code>[HttpOptions] public IActionResult GetCompaniesOptions() { Response.Headers.Add(&quot;Allow&quot;, &quot;GET, OPTIONS, POST&quot;); return Ok(); }<\/code><\/pre>\n<p>We have to decorate our action with the HttpOptions attribute. As we said, the available options should be returned in the Allow response header, and that is exactly what we are doing here. The URI for this action is \/api\/companies, so we state which actions can be executed for that certain URI. Finally, the Options request should return the 200 OK status code. We have to understand that the response, if it is empty, must include the content-length field with the value of zero. We don\u2019t have to add it by ourselves because ASP.NET Core takes care of that for us.<br \/>\n\u6211\u4eec\u5fc5\u987b\u4f7f\u7528 HttpOptions \u5c5e\u6027\u6765\u88c5\u9970\u6211\u4eec\u7684 action\u3002\u6b63\u5982\u6211\u4eec\u6240\u8bf4\uff0c\u53ef\u7528\u9009\u9879\u5e94\u8be5\u5728 Allow \u54cd\u5e94\u6807\u5934\u4e2d\u8fd4\u56de\uff0c\u8fd9\u6b63\u662f\u6211\u4eec\u5728\u8fd9\u91cc\u6240\u505a\u7684\u3002\u6b64\u4f5c\u7684 URI \u662f \/api\/companies\uff0c\u56e0\u6b64\u6211\u4eec\u8bf4\u660e\u53ef\u4ee5\u9488\u5bf9\u8be5\u7279\u5b9a URI \u6267\u884c\u54ea\u4e9b\u4f5c\u3002\u6700\u540e\uff0cOptions \u8bf7\u6c42\u5e94\u8fd4\u56de 200 OK \u72b6\u6001\u4ee3\u7801\u3002\u6211\u4eec\u5fc5\u987b\u4e86\u89e3\uff0c\u5982\u679c\u54cd\u5e94\u4e3a\u7a7a\uff0c\u5219\u5fc5\u987b\u5305\u542b\u503c\u4e3a\u96f6\u7684 content-length \u5b57\u6bb5\u3002\u6211\u4eec\u4e0d\u5fc5\u81ea\u5df1\u6dfb\u52a0\u5b83\uff0c\u56e0\u4e3a ASP.NET Core \u4f1a\u4e3a\u6211\u4eec\u5904\u7406\u8fd9\u4e9b\u3002<\/p>\n<p>Let\u2019s try this:<br \/>\n\u8ba9\u6211\u4eec\u8bd5\u8bd5\u8fd9\u4e2a\uff1a<br \/>\n<a href=\"https:\/\/localhost:5001\/api\/companies\">https:\/\/localhost:5001\/api\/companies<\/a><\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/2201.jpg\" alt=\"alt text\" \/><\/p>\n<p>As you can see, we are getting a 200 OK response. Let\u2019s inspect the Headers tab:<br \/>\n\u5982\u60a8\u6240\u89c1\uff0c\u6211\u4eec\u6536\u5230\u4e86 200 OK \u54cd\u5e94\u3002\u6211\u4eec\u6765\u68c0\u67e5 Headers \u9009\u9879\u5361\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/2202.jpg\" alt=\"alt text\" \/><\/p>\n<p>Everything works as expected.<br \/>\n\u4e00\u5207\u90fd\u6309\u9884\u671f\u8fdb\u884c\u3002<\/p>\n<p>Let\u2019s move on.<br \/>\n\u8ba9\u6211\u4eec\u7ee7\u7eed\u524d\u8fdb\u3002<\/p>\n<h2>22.3 Head HTTP Request<\/h2>\n<p>22.3 \u5934 HTTP \u8bf7\u6c42<\/p>\n<p>The Head is identical to Get but without a response body. This type of request could be used to obtain information about validity, accessibility, and recent modifications of the resource.\u200c<br \/>\nHead \u4e0e Get \u76f8\u540c\uff0c\u4f46\u6ca1\u6709\u54cd\u5e94\u6b63\u6587\u3002\u8fd9\u79cd\u7c7b\u578b\u7684\u8bf7\u6c42\u53ef\u7528\u4e8e\u83b7\u53d6\u6709\u5173\u8d44\u6e90\u7684\u6709\u6548\u6027\u3001\u53ef\u8bbf\u95ee\u6027\u548c\u6700\u8fd1\u4fee\u6539\u7684\u4fe1\u606f\u3002<\/p>\n<h2>22.4 HEAD Implementation<\/h2>\n<p>22.4 HEAD \u5b9e\u73b0<\/p>\n<p>Let\u2019s open the EmployeesController, because that\u2019s where we are going to implement this type of request. As we said, the Head request must return the same response as the Get request \u2014 just without the response body. That means it should include the paging information in the response as well.\u200c<br \/>\n\u8ba9\u6211\u4eec\u6253\u5f00 EmployeesController\uff0c\u56e0\u4e3a\u8fd9\u662f\u6211\u4eec\u8981\u5b9e\u73b0\u6b64\u7c7b\u8bf7\u6c42\u7684\u5730\u65b9\u3002\u6b63\u5982\u6211\u4eec\u6240\u8bf4\uff0cHead \u8bf7\u6c42\u5fc5\u987b\u8fd4\u56de\u4e0e Get \u8bf7\u6c42\u76f8\u540c\u7684\u54cd\u5e94 \u2014 \u53ea\u662f\u6ca1\u6709\u54cd\u5e94\u6b63\u6587\u3002\u8fd9\u610f\u5473\u7740\u5b83\u8fd8\u5e94\u8be5\u5728\u54cd\u5e94\u4e2d\u5305\u542b\u5206\u9875\u4fe1\u606f\u3002<\/p>\n<p>Now, you may think that we have to write a completely new action and also repeat all the code inside, but that is not the case. All we have to do is add the HttpHead attribute below HttpGet:<br \/>\n\u73b0\u5728\uff0c\u60a8\u53ef\u80fd\u8ba4\u4e3a\u6211\u4eec\u5fc5\u987b\u7f16\u5199\u4e00\u4e2a\u5168\u65b0\u7684\u4f5c\u5e76\u91cd\u590d\u5176\u4e2d\u7684\u6240\u6709\u4ee3\u7801\uff0c\u4f46\u4e8b\u5b9e\u5e76\u975e\u5982\u6b64\u3002\u6211\u4eec\u6240\u8981\u505a\u7684\u5c31\u662f\u5728 HttpGet \u4e0b\u9762\u6dfb\u52a0 HttpHead \u5c5e\u6027\uff1a<\/p>\n<pre><code>[HttpGet] [HttpHead] public async Task&lt;IActionResult&gt; GetEmployeesForCompany(Guid companyId, [FromQuery] EmployeeParameters employeeParameters)<\/code><\/pre>\n<p>We can test this now:<br \/>\n\u6211\u4eec\u73b0\u5728\u53ef\u4ee5\u6d4b\u8bd5\u4e00\u4e0b\uff1a<\/p>\n<p><a href=\"https:\/\/localhost:5001\/api\/companies\/C9D4C053-49B6-410C-BC78-2D54A9991870\/employees?pageNumber=2&amp;pageSize=2\">https:\/\/localhost:5001\/api\/companies\/C9D4C053-49B6-410C-BC78-2D54A9991870\/employees?pageNumber=2&pageSize=2<\/a><\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/2203.jpg\" alt=\"alt text\" \/><\/p>\n<p>As you can see, we receive a 200 OK status code with the empty body.Let\u2019s check the Headers part:<br \/>\n\u5982\u60a8\u6240\u89c1\uff0c\u6211\u4eec\u6536\u5230\u4e00\u4e2a 200 OK \u72b6\u6001\u4ee3\u7801\uff0c\u5176\u4e2d\u6b63\u6587\u4e3a\u7a7a\u3002\u8ba9\u6211\u4eec\u68c0\u67e5\u4e00\u4e0b Headers \u90e8\u5206\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/2204.jpg\" alt=\"alt text\" \/><\/p>\n<p>You can see the X-Pagination link included in the Headers part of the response. Additionally, all the parts of the X-Pagination link are populated \u2014 which means that our code was successfully executed, but the response body hasn\u2019t been included.<br \/>\n\u60a8\u53ef\u4ee5\u770b\u5230\u54cd\u5e94\u7684 Headers \u90e8\u5206\u4e2d\u5305\u542b\u7684 X-Pagination \u94fe\u63a5\u3002\u6b64\u5916\uff0cX-Pagination \u94fe\u63a5\u7684\u6240\u6709\u90e8\u5206\u90fd\u5df2\u586b\u5145 \u2014 \u8fd9\u610f\u5473\u7740\u6211\u4eec\u7684\u4ee3\u7801\u5df2\u6210\u529f\u6267\u884c\uff0c\u4f46\u54cd\u5e94\u6b63\u6587\u5c1a\u672a\u5305\u542b\u3002<\/p>\n<p>Excellent.<br \/>\n\u975e\u5e38\u597d\u3002<\/p>\n<p>We now have support for the Http OPTIONS and HEAD requests.<br \/>\n\u6211\u4eec\u73b0\u5728\u652f\u6301 Http OPTIONS \u548c HEAD \u8bf7\u6c42\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>22 WORKING WITH OPTIONS AND HEAD REQUESTS 22 \u4f7f\u7528 OPTIONS \u548c HEAD \u8bf7\u6c42 In one of the previous chapters (Method Safety and Method Idempotency), we talked about different HTTP requests. Until now, we have been working with all request types except OPTIONS and HEAD. So, let\u2019s cover them as well.\u200c \u5728\u524d\u9762\u7684\u4e00\u7ae0\uff08\u65b9\u6cd5\u5b89\u5168\u548c\u65b9\u6cd5\u5e42\u7b49\u6027\uff09\u4e2d\uff0c\u6211\u4eec\u8ba8\u8bba\u4e86\u4e0d\u540c\u7684 HTTP \u8bf7\u6c42\u3002\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u6211\u4eec\u4e00\u76f4\u5728\u5904\u7406\u9664 OPTIONS \u548c [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1142","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/1142","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1142"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/1142\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1142"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1142"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1142"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}