{"id":25887,"date":"2026-09-19T06:13:51","date_gmt":"2026-09-19T06:13:51","guid":{"rendered":"https:\/\/capskip.com\/?p=25887"},"modified":"2026-09-19T06:13:51","modified_gmt":"2026-09-19T06:13:51","slug":"aws-lambda-captcha","status":"publish","type":"post","link":"https:\/\/capskip.com\/zh\/aws-lambda-captcha\/","title":{"rendered":"\u5982\u4f55\u5728 AWS Lambda \u4e2d\u8bc6\u522b\u9a8c\u8bc1\u7801\u800c\u4e0d\u88ab\u8d85\u65f6\u6253\u65ad"},"content":{"rendered":"<p>An AWS Lambda captcha solve fails in two places, and neither of them is your code. API Gateway stops waiting for the function after 29 seconds, so a reCAPTCHA that takes 40 returns a 504 to the caller while the function is still working. And 127.0.0.1 inside the Lambda sandbox is the sandbox, so a client pointed at loopback finds nothing listening. CapSkip runs on a machine you own, which in this setup is never the one running your function. Fix the address first, then move the solve off the request path.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">What you need<\/h2>\n<ul>\n<li>CapSkip running on a Windows machine you control. It is a desktop application and it does not run inside Lambda. The function is the client here, nothing more.<\/li>\n<li>A Python 3.10 or newer Lambda runtime, with the CapSkip package in the deployment package or in a layer.<\/li>\n<li>Server mode switched on. Local mode answers on 127.0.0.1 for that device only, which is useless to a function running in AWS. Server mode listens on your network address or public IP so the function can reach it over the same API, and both live under <a href=\"https:\/\/capskip.com\/setup-guide\/#connection-settings\">connection settings<\/a>. A static public IP is recommended, with a firewall rule for the one address AWS will arrive from.<\/li>\n<li>A way to reach that address from the function. Step 2 covers the two shapes, because a function attached to a VPC behaves differently from one that is not.<\/li>\n<\/ul>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Why the API Gateway 29 second timeout decides the design<\/h2>\n<p>An AWS Lambda captcha solve has to fit inside three limits. Write them down before you write any code, because together they rule out the obvious design.<\/p>\n<table>\n<thead>\n<tr>\n<th>Limit<\/th>\n<th>Value<\/th>\n<th>Can you raise it<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>API Gateway integration timeout<\/td>\n<td>29 seconds by default<\/td>\n<td>On Regional and private REST APIs, by quota request. AWS warns the increase may cost you account throttle quota<\/td>\n<\/tr>\n<tr>\n<td>Lambda function timeout<\/td>\n<td>3 seconds by default, 900 seconds at most for a standard function<\/td>\n<td>Yes, up to that 15 minute ceiling<\/td>\n<\/tr>\n<tr>\n<td>CapSkip polling timeout<\/td>\n<td>300 seconds for reCAPTCHA, Turnstile and GeeTest, 120 for image and ALTCHA<\/td>\n<td>Yes, both are constructor options<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>So a synchronous API call cannot cover a slow reCAPTCHA. The function has room for it and the gateway in front does not, and the caller sees a 504 while the solve is still running and still being billed.<\/p>\n<p>The workaround people reach for next is worse. Returning early and finishing the solve on a background thread does not work, because after the handler returns, Lambda freezes the execution environment. AWS says it plainly: background processes or callbacks that did not complete when the function ended resume if Lambda reuses the environment. Resume, not continue. Your thread wakes up minutes later, halfway through polling for a CAPTCHA whose token expired long ago, inside an invocation that has nothing to do with it. Nothing errors. The work simply lands in the wrong place. AWS spells out the lifecycle in <a href=\"https:\/\/docs.aws.amazon.com\/lambda\/latest\/dg\/lambda-runtime-environment.html\" rel=\"nofollow noopener\" target=\"_blank\">its execution environment guide<\/a>.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Step 1: package the SDK and configure the function<\/h2>\n<p>Install into a folder and zip it with your handler, or install into a folder named python, zip that, and attach it as a layer. Pin the platform and the interpreter to what the function runs, not to what your laptop runs, or the import fails at cold start with nothing useful in the log. Without those flags pip resolves wheels for your local Python, and a wheel built for a newer interpreter will not load on the runtime.<\/p>\n<div data-no-translation>\n<pre data-enlighter-language=\"bash\" class=\"EnlighterJSRAW\"># pip install capskip\npip install capskip --target package\/ \\\n  --platform manylinux2014_x86_64 --implementation cp \\\n  --python-version 3.12 --only-binary=:all:\n\ncp lambda_function.py package\/\ncd package &amp;&amp; zip -r ..\/function.zip . &gt; \/dev\/null &amp;&amp; cd ..\n\naws lambda update-function-code \\\n  --function-name solve-captcha --zip-file fileb:\/\/function.zip<\/pre>\n<\/div>\n<p>Then set the timeout and the connection details as configuration rather than in code, so the same package runs against a test solver and a production one.<\/p>\n<div data-no-translation>\n<pre data-enlighter-language=\"bash\" class=\"EnlighterJSRAW\"># Timeout in seconds, and the Server mode address\naws lambda update-function-configuration \\\n  --function-name solve-captcha \\\n  --timeout 330 \\\n  --environment &quot;Variables={CAPSKIP_HOST=203.0.113.10,CAPSKIP_PORT=8080}&quot;<\/pre>\n<\/div>\n<p>Set the function timeout slightly above the client&#8217;s own polling timeout, not below it. Below, and Lambda kills the invocation first, which gives you a bare task timeout in CloudWatch instead of the TimeoutException that would have told you what happened.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Step 2: give the function a NAT gateway and an Elastic IP<\/h2>\n<p>This is the step that decides whether anything works, and the answer depends on one setting you may not have thought about as networking.<\/p>\n<table>\n<thead>\n<tr>\n<th>Function configuration<\/th>\n<th>What it can reach<\/th>\n<th>What you allow on your firewall<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Not attached to a VPC<\/td>\n<td>The public internet, straight away<\/td>\n<td>Nothing useful. Egress comes from AWS-owned addresses that change, so no single IP can be allowlisted<\/td>\n<\/tr>\n<tr>\n<td>Attached to a VPC, no NAT gateway<\/td>\n<td>Only what is inside that VPC. Your solver is not<\/td>\n<td>Nothing. The connection times out rather than being refused<\/td>\n<\/tr>\n<tr>\n<td>Attached to a VPC, routed through a NAT gateway<\/td>\n<td>The public internet, from one address<\/td>\n<td>The NAT gateway&#8217;s Elastic IP, which is the shape you want<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Lambda documents the first two rows directly: functions have public internet access by default, and attaching one to a VPC limits it to resources inside that VPC until the function&#8217;s subnets have a route out. That route is a NAT gateway sitting in a public subnet, described in <a href=\"https:\/\/docs.aws.amazon.com\/lambda\/latest\/dg\/configuration-vpc-internet.html\" rel=\"nofollow noopener\" target=\"_blank\">the Lambda internet access guide<\/a>. The side effect is the useful part. A NAT gateway holds an Elastic IP, so every solve arrives at your machine from one stable address and your firewall rule can be a single line.<\/p>\n<p>Attach the function to the private subnets, not the public one. This is the trap that produces a hang with a NAT gateway already in place: a function attached to a public subnet has no internet access, whatever the route table says, so the packets simply go nowhere. The same guide repeats that twice.<\/p>\n<p>A NAT gateway is the simplest shape that gives you one stable source address, not the only one. A Site-to-Site VPN or Direct Connect from the same VPC reaches a solver on your own network without exposing its port to the internet at all, and both are worth the setup if the machine is somewhere you would rather not open a port. Either way, keep the solver&#8217;s port closed to everything else. Server mode is still your hardware and still unmetered: it only changes where the solver listens so that something other than the same desktop can call it.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Step 3: move the solve off the request path<\/h2>\n<p>Given the limits above, an AWS Lambda captcha job belongs on a queue rather than on the request. The handler that answers API Gateway should not be the handler that solves: accept the job, put it on a queue, and answer immediately. A second function reads the queue and does the work with a timeout that suits a CAPTCHA rather than a web request.<\/p>\n<div data-no-translation>\n<pre data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">import json, os, uuid, boto3\n\nsqs = boto3.client(&quot;sqs&quot;)\nQUEUE_URL = os.environ[&quot;QUEUE_URL&quot;]\n\ndef lambda_handler(event, context):\n    &quot;&quot;&quot;API Gateway calls this. It never solves anything.&quot;&quot;&quot;\n    body = json.loads(event[&quot;body&quot;])\n    job_id = str(uuid.uuid4())\n    sqs.send_message(\n        QueueUrl=QUEUE_URL,\n        MessageBody=json.dumps({\n            &quot;job_id&quot;: job_id,\n            &quot;sitekey&quot;: body[&quot;sitekey&quot;],\n            &quot;pageurl&quot;: body[&quot;pageurl&quot;],\n        }),\n    )\n    return {&quot;statusCode&quot;: 202,\n            &quot;body&quot;: json.dumps({&quot;job_id&quot;: job_id})}<\/pre>\n<\/div>\n<p>The job id is there so the caller has something to ask about later. Design the consumer to finish the work itself rather than to hand a token back, because a token that waits for a second HTTP round trip usually expires on the way.<\/p>\n<p>Use a queue rather than an asynchronous invoke. Lambda retries a failed asynchronous invocation twice by default, and a CAPTCHA solve is the wrong thing to retry blindly: the second attempt starts from a sitekey whose page context has moved on, and you pay for the solve either way. A queue does not remove the retries, it makes them visible and bounded. You get a visibility timeout you control, a redrive policy, and a dead letter queue where a job that keeps failing lands somewhere you can look at it. AWS recommends a maximum receive count of at least five, which leaves room for a throttled retry before the message is parked.<\/p>\n<p>Set the queue&#8217;s visibility timeout to at least six times the consumer function&#8217;s timeout, which AWS recommends for the same throttling reason. The ordering is not optional: Lambda validates the event source mapping and refuses it if the function timeout is larger than the visibility timeout. With the 330 second function above, that means a visibility timeout near 1980 seconds.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Full working example<\/h2>\n<p>The consumer. It builds the client once, outside the handler, so a warm environment reuses it rather than reconnecting on every message.<\/p>\n<div data-no-translation>\n<pre data-enlighter-language=\"python\" class=\"EnlighterJSRAW\"># pip install capskip\nimport json, os\nfrom urllib.parse import urlencode\nfrom urllib.request import urlopen\nfrom capskip import (CapSkip, ApiException, NetworkException,\n                     TimeoutException, ValidationException)\n\n# Built at cold start and reused while the environment stays warm.\nsolver = CapSkip(\n    host=os.environ[&quot;CAPSKIP_HOST&quot;],      # Server mode address\n    port=int(os.environ.get(&quot;CAPSKIP_PORT&quot;, 8080)),\n    recaptchaTimeout=300,\n)\n\ndef lambda_handler(event, context):\n    failures = []\n    for record in event[&quot;Records&quot;]:\n        job = json.loads(record[&quot;body&quot;])\n        try:\n            result = solver.recaptcha(\n                sitekey=job[&quot;sitekey&quot;],\n                url=job[&quot;pageurl&quot;],\n            )\n        except NetworkException:\n            # No route to the solver. Retry this one message.\n            failures.append({&quot;itemIdentifier&quot;: record[&quot;messageId&quot;]})\n            continue\n        except (ApiException, TimeoutException, ValidationException) as exc:\n            print(&quot;giving up on this job:&quot;, exc)\n            continue\n\n        # Use the token here. It is short lived, so do not park it.\n        urlopen(job[&quot;pageurl&quot;], data=urlencode(\n            {&quot;g-recaptcha-response&quot;: result[&quot;code&quot;]}).encode())\n\n    # Needs ReportBatchItemFailures on the event source mapping.\n    return {&quot;batchItemFailures&quot;: failures}<\/pre>\n<\/div>\n<p>Report the failed message rather than raising. Raising fails the whole batch, and SQS then returns every message in it to the queue, including the ones you already solved, which is the duplicate-solve problem the table below warns about. A partial batch response retries only the record that failed, and it needs the report batch item failures setting on the event source mapping to be honoured.<\/p>\n<p>Retry a NetworkException and swallow the other three. No route to the solver means the job can succeed later, while an unsolvable CAPTCHA, a timeout or a bad parameter will fail the same way on every attempt and retrying it just spends the same time again. All four SDK exceptions derive from CapSkipError if you would rather catch one thing.<\/p>\n<p>That submit is the point of the whole design: do the thing the token is for inside the same invocation. A reCAPTCHA token is good for about two minutes, so writing it to a database for a later step to collect usually means collecting something that has already expired. The details of that window are in <a href=\"https:\/\/capskip.com\/recaptcha-v2-solver\/\">the reCAPTCHA v2 solver guide<\/a>, and the raw endpoints behind every SDK call are documented on <a href=\"https:\/\/capskip.com\/api-docs\/\">the API reference<\/a>.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Common errors and what they mean<\/h2>\n<table>\n<thead>\n<tr>\n<th>What you see<\/th>\n<th>Cause<\/th>\n<th>Fix<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>A 504 from API Gateway after 29 seconds, while CloudWatch shows the function still running<\/td>\n<td>The integration timeout, not the function timeout<\/td>\n<td>Answer the request immediately and solve on a queue<\/td>\n<\/tr>\n<tr>\n<td>Task timed out after 3.00 seconds<\/td>\n<td>The default function timeout, which nobody changes until it bites<\/td>\n<td>Raise it above the client&#8217;s polling timeout<\/td>\n<\/tr>\n<tr>\n<td>A NetworkException naming 127.0.0.1<\/td>\n<td>Loopback inside the sandbox reaches the sandbox, and CapSkip is not in there<\/td>\n<td>Switch to Server mode and set the host environment variable<\/td>\n<\/tr>\n<tr>\n<td>A connection that hangs until the function times out<\/td>\n<td>The function is attached to a VPC with no route out, so packets go nowhere rather than being refused<\/td>\n<td>Add a NAT gateway. Detaching from the VPC also restores internet access, but then your firewall cannot allowlist a single address<\/td>\n<\/tr>\n<tr>\n<td>The same hang with a NAT gateway already in place<\/td>\n<td>The function is attached to the public subnet rather than the private ones<\/td>\n<td>Attach it to the private subnets, which are the ones routed at the NAT gateway<\/td>\n<\/tr>\n<tr>\n<td>It works from your laptop and not from the function<\/td>\n<td>Your home address is allowed through the firewall and the AWS one is not<\/td>\n<td>Allow the NAT gateway&#8217;s Elastic IP<\/td>\n<\/tr>\n<tr>\n<td>Every job in a batch solved twice<\/td>\n<td>One record raised, so SQS returned the whole batch, including the records that had already succeeded<\/td>\n<td>Report the failed record instead of raising, and turn on report batch item failures<\/td>\n<\/tr>\n<tr>\n<td>Lambda refuses to create the event source mapping<\/td>\n<td>The function timeout is larger than the queue&#8217;s visibility timeout, which Lambda validates<\/td>\n<td>Raise the visibility timeout to at least six times the function timeout<\/td>\n<\/tr>\n<tr>\n<td>A solve that completes during an unrelated invocation<\/td>\n<td>A background thread was frozen when the handler returned and thawed on the next call<\/td>\n<td>Finish the solve before returning. There is no fire and forget here<\/td>\n<\/tr>\n<tr>\n<td>A TimeoutException naming 300 seconds<\/td>\n<td>CapSkip did not answer inside the reCAPTCHA polling timeout<\/td>\n<td>Check the solver is running and not saturated. Raising the ceiling only delays the same answer<\/td>\n<\/tr>\n<tr>\n<td>CAPCHA_NOT_READY in a hand-rolled polling loop<\/td>\n<td>The answer is not ready yet, which is a normal intermediate state and not an error<\/td>\n<td>Let the SDK poll, or read <a href=\"https:\/\/capskip.com\/capcha-not-ready\/\">the guide to that code<\/a><\/td>\n<\/tr>\n<tr>\n<td>Unable to import module lambda_function, no module named capskip<\/td>\n<td>The package was installed for the wrong architecture or interpreter, or it sits at the wrong path in the layer<\/td>\n<td>Install with the platform, implementation and python version flags, and put layer content under python at the root of the zip<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">FAQ<\/h2>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">Can CapSkip itself run inside Lambda?<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">No, and it does not need to. CapSkip is a Windows application that runs on hardware you own, and the SDK in your function is a thin client for it over HTTP. Turn on Server mode, point the function at that address, and the function calls it exactly as a script on the same desk would. The solving stays on your machine, which is also why the number of solves is not metered by anybody.<\/p>\n<\/details>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">Can I solve behind API Gateway at all?<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">Sometimes, and it depends on the type rather than on your configuration. An image CAPTCHA or an ALTCHA proof of work often finishes in a second or two, which fits inside 29 seconds with room to spare. A reCAPTCHA or a Turnstile challenge page frequently does not, and when it does not, the caller gets a 504 while the work continues and bills. If the whole product is one synchronous endpoint, request the integration timeout increase for your REST API and measure what your own traffic actually takes. The queue shape is still the one that does not surprise you at three in the morning.<\/p>\n<\/details>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">How do I let only my function reach the solver?<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">Attach the function to a VPC, route its outbound traffic through a NAT gateway, and allow that gateway&#8217;s Elastic IP on your firewall. That is the simplest shape that gives you one stable source address, because a function outside a VPC leaves from AWS-owned addresses that change under you. A Site-to-Site VPN or Direct Connect does the same job without opening a port to the internet at all. Keep the solver&#8217;s port closed to everything else, and treat the API key as a second lock rather than the only one.<\/p>\n<\/details>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">Does a long solve make the function expensive?<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">Lambda bills wall-clock duration, so a function that sits waiting for an answer is paid for at the same rate as one doing arithmetic. That is a second argument for the queue: the consumer does not need a large memory size, since it is waiting on the network rather than computing, and nothing upstream is blocked while it waits. The solve itself costs you nothing per CAPTCHA, because it happens on your own machine. The same trade-off shows up on other hosted platforms, and <a href=\"https:\/\/capskip.com\/azure-functions-captcha\/\">the Azure Functions guide<\/a> works through the equivalent there.<\/p>\n<\/details>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">The short version<\/h2>\n<p>An AWS Lambda captcha solve needs three decisions and they are all made before you write the handler. Switch CapSkip to Server mode, because loopback in the Lambda sandbox reaches nothing. Attach the function to a VPC and route it through a NAT gateway so your firewall has one Elastic IP to allow. Then stop solving on the request path: API Gateway gives you 29 seconds, a slow reCAPTCHA needs more, and returning early does not help because the environment freezes the moment your handler does. Queue the job, solve it in a consumer whose timeout sits above the client&#8217;s, and use the token in the same invocation that earned it.<\/p>\n<p>Every method the Python package exposes, with the options each one takes, is listed on <a href=\"https:\/\/capskip.com\/python-captcha-solver\/\">the Python CAPTCHA solver page<\/a>.<\/p>\n<p>One last point about the economics, because it is what makes the queue design comfortable. A discarded job costs you the Lambda milliseconds and nothing else: the <a href=\"https:\/\/capskip.com\/\">captcha bypass<\/a> work happens on hardware you already paid for, so retrying a job or throwing an expired token away never shows up on an invoice from anyone.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u6709\u4e24\u4ef6\u4e8b\u4f1a\u7ec8\u7ed3 serverless \u8bc6\u522b\uff1aAPI Gateway \u5728 29 \u79d2\u540e\u5c31\u4e0d\u518d\u7b49\u5f85\uff0c\u800c Lambda sandbox \u5185\u7684 127.0.0.1 \u6839\u672c\u8fde\u4e0d\u5230\u4efb\u4f55\u4e1c\u897f\u3002\u8fd9\u91cc\u8bf4\u660e\u8bc6\u522b\u5e94\u8be5\u653e\u5728\u54ea\u91cc\uff0c\u4ee5\u53ca\u5982\u4f55\u4e3a\u4e00\u4e2a AWS \u5730\u5740\u5f00\u51fa\u901a\u5f80\u4f60\u81ea\u5df1\u673a\u5668\u7684\u8def\u7531\u3002<\/p>","protected":false},"author":1,"featured_media":25886,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"AWS Lambda CAPTCHA: Beat the 29s Cap | CapSkip","rank_math_description":"An aws lambda captcha solve is cut off at 29 seconds behind API Gateway, and loopback reaches nothing. Move the solve to a queue and switch to Server mode.","rank_math_focus_keyword":"aws lambda captcha","footnotes":""},"categories":[70],"tags":[],"class_list":["post-25887","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-captcha"],"_links":{"self":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts\/25887","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/comments?post=25887"}],"version-history":[{"count":1,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts\/25887\/revisions"}],"predecessor-version":[{"id":25889,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts\/25887\/revisions\/25889"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/media\/25886"}],"wp:attachment":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/media?parent=25887"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/categories?post=25887"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/tags?post=25887"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}