2024 年秋招,我投的是 Shopee 的 Client 提前批。说句实话,看到题目之前,我以为“Client 岗”的笔试重点会是界面框架、组件化、状态管理或者渲染优化这类东西。真正坐到在线笔试页面里我才发现,这套题更看重的是一个客户端工程师对“从设备到服务端整条链路”的理解。整场做下来,网络协议、API 版本兼容、数据库客户端认证、消息中间件连接、安全传输上下文这些内容占了大头,最后还有一道实现网页内容抓取和一道与 MCP Client 连接 LLM 相关的题。这篇文章按我的记忆把考点归了一下类,也会写清楚每类题背后的原理和复盘思路,给准备走 Client 方向的同学做个参考。
1. 提前批笔试到底在考什么:Client 不是“写界面”那么简单
1.1 题型全貌:从选择填空到在线编程
我印象里整套卷子分成三个大块:客观题、简答/排查题、在线编程题。客观题不是单纯背概念,很多题目会给你一段客户端日志或者一条报错信息,让你判断根因。比如“firedac phys mysql client does not support authentication protocol requested”这种,问你应该怎么处理;再比如“client version 1.52 is too new, maximum supported api version is 1.43”,让你选客户端版本和 API Server 版本之间的兼容关系。这种考法比“什么是 TCP 三次握手”要狠得多,因为它默认你已经知道基础概念,直接跳到真实排障场景。
简答/排查题更偏向现场分析,我遇到的有“Oracle Instant Client 装了之后程序还是提示找不到客户端,可能是什么原因”“Kafka 客户端报 out of available brokers 怎么排查”“SAP OData gateway client 测试返回 405 是什么导致的”这类。每道题都需要你按排查链路去写,不能只给结论。编程题则是两道完整的小题,一道是实现网页内容抓取功能,另一道方向比较新,围绕 MCP Client 与 LLM 连接来出,我记得当时看到题目愣了一下,后来发现其实考的是对工具调用协议的理解,不算超纲。
我按考完后的回忆做了一个模块占比梳理,不一定准确,但能看个大概:
| 知识模块 | 出现形式 | 大致占比 |
|---|---|---|
| HTTP/HTTPS、TLS/mTLS 及安全上下文 | 客观题、简答题 | 20% 左右 |
| API 版本协商与客户端兼容 | 客观题 | 15% 左右 |
| 数据库客户端认证与连接配置 | 客观题、排查题 | 20% 左右 |
| Redis/Kafka 等中间件客户端 | 客观题、排查题 | 15% 左右 |
| 网页抓取与 HTTP 客户端实现 | 在线编程 | 15% 左右 |
| MCP client / LLM 工具调用 | 在线编程或扩展题 | 15% 左右 |
1.2 为什么 Client 岗要看这么宽
很多同学会对这个范围产生疑问:客户端开发不是写界面吗,为什么既要懂数据库认证协议,又要懂消息中间件、API 版本协商这些后端才常见的东西?
原因在于,Client 是分布式系统里离用户最近的那一层,但它不是孤立的。一个客户端要完成登录,就会涉及 TLS 握手、OAuth 客户端凭据、后端 API 版本匹配;要展示数据,就会连数据库或中间件,甚至要直连 Redis 做本地缓存;要做企业级功能,可能还要接 SAP、Oracle、虚拟化平台的管理接口。任何一个环节出问题,客户端表现出的就是“连不上”“登录失败”“请求报错”。所以笔试考的不是某个客户端框架的细枝末节,而是你能不能从一段报错里快速定位是客户端自身的问题,还是服务端、网络、协议版本的问题。这种能力,恰恰是业务量上来之后最值钱的排查能力。
2. 考场原题复盘:版本协商、认证协议与 405 报错
2.1 API 版本区间:version too new 和 version too old 是同一个坑
笔试里有一道题我印象特别深,题目给了两段报错:一段是“client version 1.52 is too new,maximum supported api version is 1.43”,另一段是“status 400: client version 1.24 is too old,minimum supported api version is 1.27”。让你判断这两个场景分别应该怎么处理。
这题背后是 API 的版本协商机制。很多云平台和基础组件在客户端接入时,并不会无条件兼容所有历史版本,而是维护一个最低支持版本和最高支持版本。客户端版本低于最低支持版本,服务端会直接拒绝,因为老客户端可能缺少必要的字段或安全补丁;客户端版本高于最高支持版本,服务端也会拒绝,因为新客户端可能会发送服务端根本不认识的请求参数。
我当时的解题思路是:先把“版本区间”这个概念画出来。假设服务端支持的区间是 [1.27, 1.43],那么 1.24 落在左侧之外,需要升级客户端到 1.27 及以上;1.52 落在右侧之外,要么升级服务端,让服务端支持到 1.52,要么把客户端降级到 1.43 及以下。笔试的选择题陷阱就在这里,很多人看到“too new”就条件反射说升级客户端,实际上太新和太旧的处理方向是相反的。做这类题,关键是看服务端报错里给的边界值,而不是凭直觉。
2.2 MySQL 客户端认证协议不兼容:从一道报错延伸出来的完整排障链路
“firedac phys mysql client does not support authentication protocol requested”这条报错,我猜不少做过数据库相关开发的人都见过。笔试把它放在了一个场景题里:某内部系统升级到 MySQL 8,随后所有用老版本 Firedac 物理连接的程序都连不上库,客户端直接报 authentication protocol requested,问怎么解决。
这题的根因在 MySQL 8 的默认认证插件变成了 caching_sha2_password,而老版本客户端在握手时只认识 mysql_native_password。服务端要求用 caching_sha2_password 完成认证,客户端协议不支持,于是握手失败。解决办法有几个方向:最稳妥的是升级客户端驱动,让它支持新的认证协议;如果业务系统不方便升级,可以临时把用户默认认证插件改回 mysql_native_password,但这会降低安全性;还有一种常见做法是给 JDBC 连接串加 allowPublicKeyRetrieval=true 配合 useSSL=false,让客户端可以通过 RSA 公钥交换密码。笔试里如果问“最安全的方式”,优先选升级驱动,而不是改服务端插件。
这里要补一个很容易被忽略的细节:老客户端连 MySQL 8 时,除了认证协议不兼容,还会出现“Public Key Retrieval is not allowed”的报错。这是因为 caching_sha2_password 在非 SSL 连接下需要获取服务端公钥,而客户端默认不允许自动获取。笔试时间充裕的话,可以把这两种报错放在一起答,会显得你对 MySQL 协议握手的过程真的有理解。
2.3 mTLS 和“ssl server requires client certificate”
有一道简答题问的是:客户端连接某个内部服务时,服务端返回“ssl server requires client certificate”,这是什么意思,客户端要做什么?这个考点是双向 TLS,也就是 mTLS。
正常 HTTPS 是客户端验证服务端证书,服务端不验证客户端。而 mTLS 要求客户端也要出示证书,由服务端来验证。服务端报“requires client certificate”,说明当前连接没有携带客户端证书,或者携带的证书不被信任。客户端需要做的事很简单:生成或申请一张客户端证书,然后在发起请求时把证书和私钥带上。不同语言实现不同,Java 里要配置 keystore,Python 里 requests 可以传 cert=(certfile, keyfile),Go 里用 tls.Config 的 Certificates 字段。
这类题考的不只是 API 怎么传参,而是让你理解“为什么需要客户端证书”。我当时答的是:客户端证书相当于门禁卡,服务端通过它确认“你是不是内部设备”,防止任何拿到服务端地址的人都能调用接口。这个类比在笔试里用上,面试官一般会认可。
2.4 SAP OData 网关客户端测试 405:HTTP 方法不是你想用就能用
热词里有一个“sap sgew gateway client 测试 405报错”,我实际笔试中也遇到类似的排查题。SAP 的 OData 服务通过 Gateway Client 测试时,如果直接用 GET 去调一个只允许 POST 的资源,或者没有在请求头带上 CSRF token,很容易返回 405 Method Not Allowed。
这道题我的排查思路是:先确认 URL 对应的 OData 服务是否真的支持当前 HTTP 方法;再检查是否缺少必需的请求头,比如 SAP 网关经常要求先发起一次 GET 获取 CSRF token,再在写操作里带上这个 token;最后看服务端日志,确认网关是否把请求正确路由到了后端。三个方向里,前两个在客户端本地就能验证,第三个需要看服务端。
笔试里这种题想拿高分,不能只答“方法不对”,要写出完整的排查顺序:客户端出错,先看请求方法,再看请求头,再看 URL 映射,最后看服务端日志。这个顺序本身比答案更有价值。
3. 数据库与消息中间件:连接不上的坑,面试官很爱反复问
3.1 Oracle Instant Client:环境变量错了就是连不上
Oracle Instant Client 的题目属于“看着简单,实际全是坑”的类型。笔试给了一个场景:下载了 19c+ 的 64 位 Instant Client,装好后程序仍然报找不到 Oracle 客户端,问你怎么排查。这题考的是对环境变量的理解。
在 Windows 上,Oracle Instant Client 解压后必须把目录加到 PATH 里,程序运行时才能找到 oci.dll;在 Linux 上,要设置 ORACLE_HOME 和 LD_LIBRARY_PATH(或者 ldconfig 配置),否则即使可执行文件存在,动态链接库也加载失败。这只是第一步。接下来还要确认 tnsnames.ora 的位置,以及程序是否配置了正确的 TNS 连接串。一个常见坑是:安装了 64 位 Instant Client,但应用本身是 32 位进程,两者不匹配仍然连不上。另一个是 NLS_LANG 没设置,导致中文乱码或字符集转换报错。
我当时把排查链路写成了四步:检查位数是否匹配、检查动态库路径、检查 tnsnames.ora 和网络连通性、检查字符集配置。笔试如果给你一段报错“OCIEnvCreate failed with return code -1”,要能想到多数是 ORACLE_HOME 或 LD_LIBRARY_PATH 的问题,而不是网络问题。
3.2 Redis Client:协议、连接池、超时,一个都不能少
Redis 是典型的客户端直连场景,笔试里容易出现选择题和简答题。我遇到的选择题是:一个 Redis 客户端连接池满了,新的请求一直阻塞,应该优先调整哪几个参数。这题如果没实际调过连接池,很容易选错。
连接池核心参数包括 maxTotal、maxIdle、minIdle、maxWaitMillis、testOnBorrow。maxTotal 决定最大连接数,maxIdle 决定空闲连接上限,maxWaitMillis 决定拿不到连接时最多等多久。如果所有连接都被占用而且 maxWaitMillis 为 -1,客户端会无限等待,最终表现就是请求卡死。合理的做法是设置一个有限的最大等待时间,同时结合 testOnBorrow 在取连接时做一次 PING 校验,避免拿到失效连接。
Redis 客户端还有一个隐藏考点是 RESP 协议。无论 jredis、go-redis 还是 redisson,底层都在按 RESP 协议解析服务端返回。笔试如果问“为什么 Redis 客户端快”,除了网络 IO 模型之外,也要提到 RESP 协议本身是文本协议,解析简单、性能开销低。如果你能随手写出一个极简 RESP 解析流程,比如把+OK\r\n映射为成功,把-ERR ...\r\n映射为错误,会显得你真的理解客户端实现。
3.3 Kafka 客户端“out of available brokers”:不要把锅全甩给网络
“client has run out of available brokers to talk to” 这条报错,笔试里出现的频率比我想象中高。它表面意思是客户端连不上任何 broker,但根因通常不只是网络不通。我建议按以下顺序排查:
第一,bootstrap.servers 配置是否正确,包括 host、port,以及是否有拼写错误。第二,broker 是否真的启动并能被客户端访问,可以在客户端机器上用 telnet 或者 nc 测端口。第三,客户端版本和 broker 版本是否兼容,过老或过新的客户端都可能导致握手失败。第四,如果走的是 TLS 或认证模式,还要检查证书、用户名密码是否配置正确。
笔试里这题容易答偏的原因是很多人只写“网络不通”。实际上,线上环境最常见的根因是 bootstrap.servers 只配了单点地址,而该 broker 宕机后客户端没有任何备选地址可用。哪怕只是多配几个 broker 地址,这个问题就能缓解。另一个常见根因是 Kafka 服务端启用了 SSL,但客户端仍然用明文协议去连接,导致握手被直接断开,表现为“no available brokers”。
3.4 SAP 不同 Client 配置传输:一个容易被忽略的企业级场景
热词里有“sap s4 不同client传输 po输出生成so的配置”,这个方向偏企业级应用。SAP 里的 Client 与通用软件里的 Client 语义不完全一样,它更多是系统内部的数据隔离层。企业里通常有开发 Client、测试 Client、生产 Client,配置或程序的变更需要从开发 Client 传输到生产 Client。
笔试里如果出现这类场景,一般不会考具体事务代码,而是考你对“客户端环境隔离 + 配置传输”这个概念的理解。比如 PO 输出生成销售订单(SO)的配置,在某个 Client 下生效,但另一个 Client 没生效,大概率是传输请求没有完整包含相关配置项。这类题更看重你有没有跨系统、跨环境联调的经验,能在排障时想到“是不是配置只落在单个 Client 上”而不是只盯着代码逻辑。
4. 编程题:从“实现网页抓取”到“MCP Client 连接 LLM”
4.1 实现网页内容抓取功能:代码要能跑,思路要完整
提前批笔试的编程题有一道是让实现抓取网页内容的功能。题干不会特别复杂,通常会要求你传入一个 URL,返回页面中的正文文本。我理解这道题的核心考察点不只是“会不会发 HTTP 请求”,而是你写出来的代码能不能处理真实网页里的各种意外情况。
我当时用 Python 写了个简化版本,思路是先请求页面,再解析 HTML,最后提取正文文本。核心代码如下:
import requests from bs4 import BeautifulSoup def fetch_page_text(url): headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } resp = requests.get(url, headers=headers, timeout=10) resp.raise_for_status() # 根据响应头里的 charset 处理编码,避免中文乱码 if resp.encoding is None or resp.encoding.lower() == "iso-8859-1": resp.encoding = resp.apparent_encoding soup = BeautifulSoup(resp.text, "html.parser") for tag in soup(["script", "style", "noscript"]): tag.decompose() return soup.get_text(separator="\n", strip=True)这里有几个细节很容易被忽略。第一个是 User-Agent,很多站点会拦截裸 requests 请求,加上常见浏览器的 User-Agent 是基础操作。第二个是编码问题,如果服务器返回的响应头没有指定 charset,或者错误地指定了 iso-8859-1,直接用 resp.text 可能中文乱码,所以要靠 apparent_encoding 做兜底。第三个是异常处理,笔试环境网络不一定稳定,请求超时、连接失败、404 都要能兜住,不能让整个程序崩溃。
如果你选择用 Java 写,核心逻辑也类似:用 HttpClient 发 GET 请求,拿到响应后交给 Jsoup 解析。重点不在用哪个库,而在于你能否把抓取流程拆成“请求、解析、清洗”三层。我当时还把清洗做了扩展,把 script、style、noscript 标签全部去掉,再按空行切分文本,这样提取出的正文信息密度更高。
4.2 MCP Client 与 LLM 连接:理解“工具调用”比写代码更重要
最后一道编程题跟 MCP Client 有关,我看到题目时确实愣了一下。MCP(Model Context Protocol)是模型上下文协议的简称,它在 LLM 应用与外部工具、数据源之间定义了一个标准通信协议。MCP Client 的角色相当于一个连接器:一端对接 LLM,一端对接工具或资源,让模型可以调用真实世界的函数来回答问题。
笔试不会要求你完整实现一个生产可用的 MCP 服务器,而是会给你一段简化描述,让你写一个客户端逻辑,打通“LLM 请求工具调用”这条链路。核心流程大概是:客户端启动时与 MCP Server 建立连接,通过 initialize 完成协议握手;随后列出可用工具,比如 tools/list;当 LLM 决定调用某个工具时,客户端通过 tools/call 把参数传给服务端,并把执行结果返回给 LLM。
如果要用伪代码示意,大概是这个样子:
class MCPClient: def __init__(self, server, llm): self.server = server self.llm = llm def chat(self, user_input): tools = self.server.tools_list() # 把工具描述交给 LLM,让它决定是否需要调用 response = self.llm.complete(user_input, tools=tools) if response.tool_call: result = self.server.tools_call( response.tool_name, response.tool_args ) # 把工具结果返回给 LLM,生成最终回答 return self.llm.complete( user_input, tool_result=result ) return response.text这段代码真正想体现的是你对 function calling 机制的熟悉程度。LLM 本身不会真的去查数据库或抓网页,它只能生成一个“调用请求”,真正执行的是客户端。所以 MCP Client 的本质就是:读取模型输出、识别工具调用意图、调用外部函数、把结果回传给模型。想提前准备这类题的同学,可以去读一下 MCP 协议里 initialize、tools/list、tools/call 这几个核心方法,理解它们各自的作用即可。
4.3 为什么这类新协议值得关注
笔试考 MCP 不代表你必须已经用过这套协议,而是考察你面对一个新协议时能不能快速理解它的核心交互模型。方法其实通用:先看两端是什么,再看消息格式,最后看生命周期。MCP 的两端是 LLM 和工具,消息格式是 JSON-RPC,生命周期是 initialize 到 shutdown。有了这三层框架,就算遇到没见过的协议,也能写出像样的设计方案。我当时在编程题里没有把代码写得很复杂,而是把注释写得很清楚,说明每个阶段在干什么,最后这部分得分应该不低。
5. 备考复盘:我踩过的坑和后续建议
5.1 考场上的三个真实教训
第一个教训是时间分配。我刚开始做客观题时太较真,在一道版本兼容题上花了不少时间想“为什么 maximum supported api version 是 1.43 而不是 1.50”,浪费了后面编程题的时间。后来我意识到,笔试的关键是先把所有题过一遍,把能拿的分先拿到,再回头抠有疑问的题目。Client 方向的知识面本身就宽,不可能每道题都满分。
第二个教训是复习时不能只背结论。比如 MySQL 认证协议不兼容,如果我背的是“改成 mysql_native_password 就行”,那题目换成“最安全的方案”我肯定选错。真正理解了 caching_sha2_password 和 mysql_native_password 的区别,知道升级驱动才是最优解,才能应对多角度的追问。秋招笔试里的选择题经常把“正确做法”和“临时方案”混在一起,你需要有能力分辨哪个是最佳实践,哪个只是短期规避。
第三个教训是动手实践比看文档有用。Oracle Instant Client 的环境变量、Redis 连接池参数、Kafka 的 broker 列表,这些内容如果只看资料,印象很浅。我在准备阶段用 Docker 搭过 Kafka 和 Redis,故意把 bootstrap.servers 写错,观察报错信息,再逐步修正。这个过程中积累下来的报错敏感度,笔试时是真的能转化为分数的。
5.2 给下一届同学的备考清单
结合这次笔试,我给准备 Client 方向秋招的同学列了一份复习清单,按优先级排:
- HTTP/HTTPS 与 TLS/mTLS:重点是 HTTPS 握手流程、客户端证书场景、TLS 版本协商。
- API 版本兼容:理解服务端维护的最低/最高支持版本,能区分客户端升级和服务端升级两种处理方向。
- 数据库客户端连接:MySQL 8 认证插件兼容、Oracle Instant Client 环境变量、连接串字符集。
- 中间件客户端参数:Redis 连接池和超时、Kafka bootstrap servers 与认证配置。
- 编程落地能力:用一门语言实现 HTTP 客户端、解析网页、处理编码和异常。
- 新协议学习能力:理解 MCP、LSP、JSON-RPC 这类协议的基本交互流程。
如果时间有限,前三条优先,因为它们更常出现在客观题里,投入产出比最高。编程题则要保证至少能实现一个健壮的“请求-解析-清洗”链路,语言不重要,思路完整才重要。
5.3 备考资料与模拟方式
我不太推荐一上来就刷大量面试题。更有效的方式是把自己想象成一个“客户端排障工程师”,每天处理一个连接报错。比如今天解决 MySQL 认证协议问题,明天解决 Kafka 无可用 broker,后天解决 Oracle Instant Client 的动态库加载错误。每个问题都记录三件事:报错原文、根因、解决步骤。秋招前把这些记录翻一遍,基本能应付大部分客户端链路相关的题目。
也可以自己写一个小项目做模拟:用语言内置 HTTP 客户端抓取一个网页,解析正文,然后试图把抓到的内容通过一个极简 MCP Client 暴露给本地 LLM。虽然真正生产环境用的框架会更复杂,但这个最小链路能帮你打通“HTTP 客户端、解析、协议理解、LLM 工具调用”四个关键点,和这次笔试的考点高度契合。
最后再分享一个工具:建立自己的“报错日志”
整场提前批笔试给我的最大体会是:知识面是一方面,排障思路是另一方面,两者可以同时通过“积累报错日志”来训练。我准备了一个文档,专门记录各类客户端报错原文,按数据库、消息队列、API 网关、安全认证分类。每条记录后面跟着根因和解决办法,比如“MySQL does not support authentication protocol requested → 驱动太老,升级驱动或切换认证插件”“client version too new → 客户端版本超过服务端支持上限,需要降级客户端或升级服务端”。笔试复习到最后,不用抱着大厚书翻,看这些日志就够了。
一个小技巧:每次看到报错,不要急着搜结果,先自己猜一下根因。哪怕猜错也没关系,再看答案时记忆会深刻很多。这个习惯帮我在笔试里快速定位了好几道题,也希望对你明年秋招有用。