在Springboot項目部署時遇到,centos服務器上,curl請求目標地址不通 ,curl -x 可以請求通的解決辦法

在甲方服務器部署項目時,通常遇到需要開通外網權限的問題,有的是直接給開通服務器的白名單,就可以直接訪問白名單外網地址了。也有的是通過網絡轉發,將url前面的部分替換,可以進行網絡請求。有一次遇到一個罕見的,對方應是使用squid進行代理的。直接curl外網地址是不通的,使用curl -x 代理服務器ip:端口 目標地址可以訪問通。針對此種場景,測試了以下配置代方法

1. 全局環境變量配置

在centos中配置當前用戶或者全局環境變量,是可行的,配置完成后,curl命令后不用-x就可以直接訪問了。但是這種方法,本服務器上部署的java和nginx確是無效的

# 編輯配置文件vim ~/.bashrc # 或 ~/.bash_profile 
# 添加以下內容(替換為您的代理服務器信息) 
export http_proxy=http://10.10.10.61:8080 
export https_proxy=http://10.10.10.61:8080 
# 設置 NO_PROXY 變量,指定哪些域名不需要通過代理(逗號分隔,支持通配符) 
export no_proxy="localhost,127.0.0.1,192.168.1.0/24,.example.com" 
# 使配置生效 
source ~/.bashrc

2. springboot web服務內,httpClient配置

在使用1中的方法,配置環境變量后,發現使用Springboot服務請求時,還是不通。提示域名無法解析。

使用了網上的方法,在啟動jar包時,配置如下的啟動參數或者環境變量依然無效。

java -Dhttp.proxyHost=10.20.102.61 -Dhttp.proxyPort=8080 -Dhttps.proxyHost=10.20.102.61 -Dhttps.proxyPort=8080  -Dsun.net.spi.nameservice.provider.1=dns,sun -Djava.net.preferIPv4Stack=true -jar

最后使用了在代碼里統一配置httpClient的方式實現

依賴

        <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version></dependency>
  • HttpProxyClientUtil.java
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** Apache HttpClient 4.x 實現的 HTTP 請求工具類(支持代理、SSL 繞過、多種請求體)*/
public class HttpProxyClientUtil {// -------------------- 基礎配置 --------------------// 連接超時(毫秒)private static final int CONNECT_TIMEOUT = 5000;// 讀取超時(毫秒)private static final int READ_TIMEOUT = 5000;// -------------------- 代理配置 --------------------// 代理主機(需替換為實際代理 IP/域名)private static final String PROXY_HOST = "10.10.10.61";// 代理端口(需替換為實際代理端口)private static final int PROXY_PORT = 8080;// -------------------- 構建 HttpClient(支持代理、SSL 繞過) --------------------public static CloseableHttpClient createHttpClient(boolean ignoreSsl) {try {// 1. 構建 SSL 上下文(可選:繞過證書校驗)SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (chain, authType) -> true) // 信任所有證書.build();SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext,NoopHostnameVerifier.INSTANCE // 跳過主機名校驗);// 2. 構建請求配置(含代理)RequestConfig.Builder requestConfigBuilder = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(READ_TIMEOUT).setProxy(new org.apache.http.HttpHost(PROXY_HOST, PROXY_PORT)); // 設置代理// 3. 構建 HttpClientCloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(ignoreSsl? sslSocketFactory : SSLConnectionSocketFactory.getSystemSocketFactory()).setDefaultRequestConfig(requestConfigBuilder.build()).build();return httpClient;} catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {throw new RuntimeException("構建 HttpClient 失敗", e);}}// -------------------- GET 請求 --------------------/*** 發送 GET 請求(支持代理、SSL 繞過)* @param url       請求地址* @param ignoreSsl 是否忽略 SSL 證書校驗(生產環境慎用)* @return 響應內容(字符串)*/public static String doGet(String url, boolean ignoreSsl) {CloseableHttpClient httpClient = createHttpClient(ignoreSsl);HttpGet httpGet = new HttpGet(url);// 可在此處添加請求頭(示例)httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");try (CloseableHttpResponse response = httpClient.execute(httpGet)) {HttpEntity entity = response.getEntity();if (entity != null) {return EntityUtils.toString(entity, StandardCharsets.UTF_8);}return "";} catch (IOException e) {throw new RuntimeException("GET 請求失敗: " + url, e);} finally {try {httpClient.close();} catch (IOException e) {e.printStackTrace();}}}// -------------------- POST 表單請求 --------------------/*** 發送 POST 表單請求(application/x-www-form-urlencoded)* @param url       請求地址* @param params    表單參數(key-value)* @param ignoreSsl 是否忽略 SSL 證書校驗(生產環境慎用)* @return 響應內容(字符串)*/public static String doPostForm(String url, Map<String, String> params, boolean ignoreSsl) {CloseableHttpClient httpClient = createHttpClient(ignoreSsl);HttpPost httpPost = new HttpPost(url);// 構建表單參數List<NameValuePair> formParams = new ArrayList<>();params.forEach((k, v) -> formParams.add(new BasicNameValuePair(k, v)));httpPost.setEntity(new UrlEncodedFormEntity(formParams, StandardCharsets.UTF_8));// 設置請求頭(表單默認 Content-Type)httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");try (CloseableHttpResponse response = httpClient.execute(httpPost)) {HttpEntity entity = response.getEntity();if (entity != null) {return EntityUtils.toString(entity, StandardCharsets.UTF_8);}return "";} catch (IOException e) {throw new RuntimeException("POST 表單請求失敗: " + url, e);} finally {try {httpClient.close();} catch (IOException e) {e.printStackTrace();}}}// -------------------- POST JSON 請求 --------------------/*** 發送 POST JSON 請求(application/json)* @param url       請求地址* @param jsonBody  JSON 字符串* @param ignoreSsl 是否忽略 SSL 證書校驗(生產環境慎用)* @return 響應內容(字符串)*/public static String doPostJson(String url, String jsonBody, boolean ignoreSsl) {CloseableHttpClient httpClient = createHttpClient(ignoreSsl);HttpPost httpPost = new HttpPost(url);// 設置請求頭(JSON 場景)httpPost.setHeader("Content-Type", "application/json");httpPost.setEntity(new org.apache.http.entity.StringEntity(jsonBody, StandardCharsets.UTF_8));try (CloseableHttpResponse response = httpClient.execute(httpPost)) {HttpEntity entity = response.getEntity();if (entity != null) {return EntityUtils.toString(entity, StandardCharsets.UTF_8);}return "";} catch (IOException e) {throw new RuntimeException("POST JSON 請求失敗: " + url, e);} finally {try {httpClient.close();} catch (IOException e) {e.printStackTrace();}}}// -------------------- 測試示例(main 方法) --------------------public static void main(String[] args) {// 1. GET 請求示例(帶代理、忽略 SSL 校驗)String getUrl = "https://www.example.com/api/get";String getResponse = doGet(getUrl, true);System.out.println("GET 響應: " + getResponse);}
}
  • HttpClientConfig.java
package com.test.demo.config;import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class HttpClientConfig {@Beanpublic CloseableHttpClient httpClient() {// 這里可復用上面的 createHttpClient 邏輯,或直接構建帶代理的 HttpClientreturn HttpProxyClientUtil.createHttpClient(true);}
}
  • ProxyHttpService.java
package com.test.demo.demos.web;import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;@Service
public class ProxyHttpService {private final HttpClient httpClient;public ProxyHttpService(HttpClient httpClient) {this.httpClient = httpClient;}/*** 發送GET請求*/public String sendGetRequest(String url) throws IOException, ParseException {HttpGet httpGet = new HttpGet(url);try (CloseableHttpResponse response = (CloseableHttpResponse)httpClient.execute(httpGet)) {return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);} catch (IOException e) {e.printStackTrace();throw new RuntimeException("請求失敗", e);}}/*** 發送POST請求*/public String sendPostRequest(String url, Map<String, String> params) throws IOException, ParseException {HttpPost httpPost = new HttpPost(url);// 設置POST參數if (params != null && !params.isEmpty()) {List<NameValuePair> formParams = new ArrayList<>();for (Map.Entry<String, String> entry : params.entrySet()) {formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));}httpPost.setEntity(new UrlEncodedFormEntity(formParams));}try (CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(httpPost)) {HttpEntity entity = response.getEntity();return EntityUtils.toString(entity);}}
}
  • ProxyHttpController.java
package com.test.demo.demos.web;import org.springframework.web.bind.annotation.*;import java.io.IOException;
import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("/proxy/api/http")
public class ProxyHttpController {private final ProxyHttpService proxyHttpService;public ProxyHttpController(ProxyHttpService proxyHttpService) {this.proxyHttpService = proxyHttpService;}/*** 通過代理發送GET請求*/@GetMapping("/get")public String sendGet() {try {return proxyHttpService.sendGetRequest("https://api.test.com.cn/sys/getCaptchaBase64");} catch (Exception e) {e.printStackTrace();return "Error: " + e.getMessage();}}/*** 通過代理發送POST請求*/@PostMapping("/post")public String sendPost(@RequestParam("url") String url,@RequestBody(required = false) Map<String, String> params) {try {return proxyHttpService.sendPostRequest(url, params);} catch (Exception e) {return "Error: " + e.getMessage();}}
}

3. SpringGateWay配置轉發

方法2,對原項目代理改動還是比較大的,如果你使用的不是httpclient的請求方式,基于gateway批量轉發,也是一個不錯的選擇。

  • 依賴
        <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>io.projectreactor.netty</groupId><artifactId>reactor-netty-http</artifactId></dependency>
  • GatewayProxyConfig.java
package com.example.gateway.demos.web;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.gateway.config.HttpClientCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.netty.http.client.HttpClient;
import reactor.netty.transport.ProxyProvider;import javax.net.ssl.SSLException;
import java.util.Arrays;@Configuration
public class GatewayProxyConfig {@Beanpublic HttpClientCustomizer proxyCustomizer(ProxyProperties proxyProperties) {return httpClient -> {// 使用最新的 ProxyProvider APIreturn httpClient.proxy(proxy -> {ProxyProvider.Builder builder = proxy.type(ProxyProvider.Proxy.HTTP).host(proxyProperties.getHost()).port(proxyProperties.getPort());// 如果需要代理認證if (proxyProperties.getUsername() != null) {builder.username(proxyProperties.getUsername()).password(s -> proxyProperties.getPassword());}//                    // 設置無需代理的主機列表
//                    if (proxyProperties.getNonProxyHosts() != null) {
//                        String[] nonProxyHosts = proxyProperties.getNonProxyHosts()
//                                .split(",");
//                        builder.nonProxyHosts(Arrays.toString(nonProxyHosts));
//                    }});};}@Beanpublic HttpClientCustomizer sslCustomizer() {return httpClient -> {// 創建信任所有證書的 SSLContext(測試環境)// 生產環境建議使用合法證書或自定義 TrustManagerreturn httpClient.secure(spec -> {try {spec.sslContext(buildInsecureSslContext());} catch (SSLException e) {e.printStackTrace();throw new RuntimeException(e);}});};}private io.netty.handler.ssl.SslContext buildInsecureSslContext() throws SSLException {return io.netty.handler.ssl.SslContextBuilder.forClient().trustManager(io.netty.handler.ssl.util.InsecureTrustManagerFactory.INSTANCE).build();}@Bean@ConfigurationProperties(prefix = "spring.cloud.gateway.httpclient.proxy")public ProxyProperties proxyProperties() {return new ProxyProperties();}// 代理配置屬性類public static class ProxyProperties {private String host;private int port;private String username;private String password;private String nonProxyHosts;public String getHost() { return host; }public void setHost(String host) { this.host = host; }public int getPort() { return port; }public void setPort(int port) { this.port = port; }public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getPassword() { return password; }public void setPassword(String password) { this.password = password; }public String getNonProxyHosts() { return nonProxyHosts; }public void setNonProxyHosts(String nonProxyHosts) { this.nonProxyHosts = nonProxyHosts; }}
}
  • yml配置
# 應用服務 WEB 訪問端口
server:port: 7777# application.yml
spring:cloud:gateway:httpclient:pool:max-connections: 500    # 最大連接數acquire-timeout: 45000  # 獲取連接超時時間(毫秒)proxy:host: 10.10.10.61port: 8080# 如果需要認證# username: username# password: password# 非代理主機列表non-proxy-hosts: "localhost,127.0.0.1,*.local"routes:# 路由 ID,唯一標識- id: api2# 匹配的路徑,所有以 /api/ 開頭的請求都會被路由uri: https://api.api2.compredicates:- Path=/api2/**# 重寫路徑,去除 /api 前綴filters:- RewritePath=/api2/(?<segment>.*), /$\{segment}# 路由 ID,唯一標識- id: api1# 匹配的路徑,所有以 /api/ 開頭的請求都會被路由uri: https://api1.com.cnpredicates:- Path=/api1/**# 重寫路徑,去除 /api 前綴filters:- RewritePath=/api1/(?<segment>.*), /$\{segment}

4. Nginx配置轉發

nginx配置這塊,測試了很多方法,也沒有非常有效的,最后放棄了

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/88145.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/88145.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/88145.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python異步爬蟲編程技巧:從入門到高級實戰指南

Python異步爬蟲編程技巧&#xff1a;從入門到高級實戰指南 &#x1f680; &#x1f4da; 目錄 前言&#xff1a;為什么要學異步爬蟲異步編程基礎概念異步爬蟲核心技術棧入門實戰&#xff1a;第一個異步爬蟲進階技巧&#xff1a;并發控制與資源管理高級實戰&#xff1a;分布式…

JMeter-SSE響應數據自動化3.0

背景 此次因為多了一些需要過濾排除的錯誤(數量很少)&#xff0c;還需要修改下JMeter的jtl文件輸出數據&#xff08;后續統計數據需要&#xff09; 所以只涉及到JSR腳本的一些改動(此部分改動并不會影響到JMeter的HTML報告) 改動 主要通過設置JMeter中prev輸出數據變量threadN…

012 進程狀態和優先級

&#x1f984; 個人主頁: 小米里的大麥-CSDN博客 &#x1f38f; 所屬專欄: Linux_小米里的大麥的博客-CSDN博客 &#x1f381; GitHub主頁: 小米里的大麥的 GitHub ?? 操作環境: Visual Studio 2022 文章目錄 進程狀態和優先級一、進程狀態分類特殊狀態說明 二、如何查看進程…

React JSX原理

JSX本質 實質上是React.createElement()的語法糖

Java-51 深入淺出 Tomcat 手寫 Tomcat 類加載機制 雙親委派機制 生命周期 插件化

點一下關注吧&#xff01;&#xff01;&#xff01;非常感謝&#xff01;&#xff01;持續更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持續更新中&#xff01;&#xff08;長期更新&#xff09; 目前2025年06月13日更新到&#xff1a; AI煉丹日志-28 - Aud…

從C++編程入手設計模式——責任鏈模式

從C編程入手設計模式——責任鏈模式 ? 當我們的一個請求需要多個對象去處理&#xff0c;但具體由誰來處理&#xff0c;是根據情況動態決定的。例如&#xff0c;一個日志系統中&#xff0c;可能希望把錯誤信息寫入文件&#xff0c;把提示信息輸出到控制臺&#xff0c;而不是每…

泛型方法調用需要顯示指定泛型類型的場景

泛型類型的推斷確定 一般來說&#xff0c;泛型類型的推斷可以由以下幾個場景確定&#xff1a; 變量定義指定類型 List<String> strList new ArrayList<>();ArrayList的泛型類型是依據變量的類型確定的。 方法返回值確定 Overridepublic Function<List<I…

Deep Research:開啟深度研究的智能新時代

在當今信息爆炸的時代&#xff0c;人們面臨著海量的信息&#xff0c;無論是專業人士還是普通消費者&#xff0c;都迫切需要一種高效、精準的方式來獲取和分析信息。OpenAI 推出的 Deep Research&#xff0c;宛如一顆璀璨的新星&#xff0c;在知識的海洋中為我們導航&#xff0c…

曼昆《經濟學原理》第九版 宏觀經濟學 第二十四章失業與自然失業率

以下是曼昆《經濟學原理》第九版宏觀經濟學第二十四章**“失業與自然失業率”**的詳細講解&#xff0c;從零基礎開始構建知識框架&#xff0c;結合中國實際案例與生活化比喻&#xff0c;幫助小白系統理解核心概念&#xff1a; 一、知識框架&#xff1a;失業的“全景圖” 1. 核…

【軟考高級系統架構論文】論軟件系統架構風格

論文真題 請以“軟件系統架構風格”為論題,依次從以下三個方面進行論述: 1、概要敘述你參與分析和開發的軟件系統開發項目以及你所擔任的主要工作。 2、分析軟件系統開發中常用的軟件系統架構風格有哪些?詳細闡述每種風格的具體含義。 3、詳細說明在你所參與的軟件系統開發項…

LeetCode--35.搜索插入位置

解題思路&#xff1a; 1.獲取信息&#xff1a; 給定一個升序排列的數組和一個整數&#xff0c;要求查找該整數應該在數組中插入的位置 限制條件是&#xff0c;要求時間復雜度為O(log N) 2.分析題目&#xff1a; 時間復雜度要求O(log N)&#xff0c;那么就使用二分查找法&#x…

Unix、Linux、POSIX、Minix 區別與聯系

一、Unix&#xff1a;現代操作系統的技術原型 誕生&#xff1a;1969年貝爾實驗室&#xff0c;用C語言重寫后實現跨平臺&#xff08;1973年&#xff09;。核心設計&#xff1a; 一切皆文件&#xff08;設備/進程均抽象為文件&#xff09;。管道&#xff08;|&#xff09;和文本…

python計算長方形的周長 2025年3月青少年電子學會等級考試 中小學生python編程等級考試一級真題答案解析

python計算長方形的周長 2025年3月 python編程等級考試一級編程題 博主推薦 所有考級比賽學習相關資料合集【推薦收藏】 1、Python比賽 信息素養大賽Python編程挑戰賽 藍橋杯python選拔賽真題詳解 藍橋杯python省賽真題詳解 藍橋杯python國賽真題詳解 2、Python考級 p…

使用 RedisVL 進行復雜查詢

一、前置條件 在開始之前&#xff0c;請確保&#xff1a; 已安裝 redisvl 并激活相應的 Python 環境。運行 Redis 實例&#xff0c;且 RediSearch 版本 > 2.4。 二、初始化與數據加載 我們將使用一個包含用戶信息的數據集&#xff0c;字段包括 user、age、job、credit_s…

「Linux文件及目錄管理」vi、vim編輯器

知識點解析 vi/vim編輯器簡介 vi:Linux默認的文本編輯器,基于命令行操作,功能強大。vim:vi的增強版,支持語法高亮、多窗口編輯、插件擴展等功能。vi/vim基本模式 命令模式:默認模式,用于移動光標、復制、粘貼、刪除等操作。插入模式:按i進入,用于輸入文本。末行模式:…

電容器保護測控裝置如何選型?

在電力系統的無功補償環節&#xff0c;?電容器保護測控裝置是保障并聯電容器組安全穩定運行的核心設備。其選型需綜合考量保護需求、系統環境及擴展功能。以下是關鍵選型要素分析&#xff1a; ?一、明確核心功能需求? 電容器保護測控裝置&#xff0c;選型時需匹配電容器組實…

最近小峰一直在忙國際化項目,確實有點分身乏術... [特殊字符] 不過! 我正緊鑼密鼓準備一系列干貨文章/深度解析

本人詳解 大家晚上好呀&#xff01;&#x1f319; 最近小峰一直在忙國際化項目&#xff0c;確實有點分身乏術... &#x1f605; 不過&#xff01; 我正緊鑼密鼓準備一系列干貨文章/深度解析&#xff08;選一個更符合你內容的詞&#xff09;&#xff0c;很快就會和大家見面啦&am…

OpenCV CUDA模塊設備層-----設備端(GPU)線程塊級別的一個內存拷貝工具函數blockCopy()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 在同一個線程塊&#xff08;thread block內&#xff0c;將 [beg, end) 范圍內的數據并行地復制到 out 開始的位置。 它使用了 CUDA 線程協作機制…

https沒有證書可以訪問嗎?外網怎么訪問內網?

沒有SSL證書的網站無法正常通過HTTPS協議訪問?。HTTPS的實現必須依賴有效的SSL證書完成加密握手&#xff0c;否則瀏覽器會直接阻斷連接或顯示嚴重的安全警告。?? 一、技術實現層面? ?HTTPS協議強制要求證書?。 HTTPS基于SSL/TLS協議實現加密通信&#xff0c;而SSL證書是…

Python pytesseract【OCR引擎庫】 簡介

想全面了解DeepSeek的看過來 【包郵】DeepSeek全攻略 人人需要的AI通識課 零基礎掌握DeepSeek的實用操作手冊指南【限量作者親筆簽名版售完即止】 玩轉DeepSeek這本就夠了 【自營包郵】DeepSeek實戰指南 deepseek從入門到精通實用操作指南現代科技科普讀物AI普及知識讀物人工智…