http 协议之 Content-Type

article/2025/9/12 6:11:27

        Content-Type 字段是 http 服务端返回给客户端时,head 里面带上的,这个字段表明服务端返回给客户端的 body 是什么类型的,然后客户端就可以根据这个类型进行文件处理。如浏览器客户端,针对 text/html 类型时,是直接显示或解析成网页进行展示,针对 image/jpg 时,浏览器会展示成图片,针对 audio/mpeg 类型时,就当成音频播放,针对 video/mp4 类型时,就当成视频来播放。以下操作都是在 Chrome 浏览里进行。

1,Content-Type: text/html

此类型即为可读类型,text 文本时,直接显示,html 时,网页显示。

 当点击 readme.txt 文件时,显示的内容:

但是当 text 不是ASCII 字符码时, 需要指定字符集,否则可能会出现乱码,如:

此时需要在 Content-Type: text/plain 后加上对应的字符集,如: Content-Type: text/plain;charset=utf-8

 

当点击 upload.html 文件时,显示的就是一个网页:

2, Content-Type: image/jpeg

 当点击 cpp.jpeg 图片时,浏览器里显示出一张图片:

 3,Content-Type: audio/mpeg

当点击 wangjie.mp3 文件时,浏览器变成了一个音频播放器:

 4,Content-Type: video/mp4

当点击 WeChat_20211225182819.mp4 文件时,浏览器变成了视频播放器:

5,Content-Type: application/octet-stream 

若是不知道具体类型,或是不想判断是具体类型,可以一律按 application/octet-stream 进行处理,这样的话,点击文件就会进行下载操作。

这里只是演示一些最基本的一些类型操作,目前程序还是有问题的,比如 目录和大文件,这两个后续研究再更新一下。 

附上 main.cpp 源码,全部源码 这里 可以找到。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <map>
#include <mutex>
#include "../webServer/mongoose.h"
#include "json/json.h"
#include "../webServer/webServer.h"
#include "networkAPI.h"
#include "comm/log.h"
#include "Base64.h"void eventHandler(struct mg_connection *nc, int event, void *eventData);
void handleRequest(struct mg_connection *connection, int32_t event, void *data);
void httpResponse(struct mg_connection *connection, Json::Value &body);
void httpFileResponse(struct mg_connection *con, const char *fileName);
bool hasHeader(const char *header);
void setHeader(const char *header, const char *value);
void* addConnection(struct mg_connection *nc);
void delConnection(void *usrData);
void webStart();
void fileUpload(mg_connection* nc, const int ev, void* data);
bool isFile(const char *file);enum FileType
{FILE_TYPE_UNKNOW = 0, //没有后缀按二进制文件对待FILE_TYPE_REGULAR,    //普通文本文件FILE_TYPE_MP3,FILE_TYPE_JPEG,FILE_TYPE_PNG,FILE_TYPE_MP4,FILE_TYPE_MAX
};const char *fileTypeStr[] = {"application/octet-stream","text/html","audio/mpeg","image/jpeg","image/png","video/mp4"
};struct userData
{int index;
};struct FileInfo
{FILE *fp;char fileName[32];char filePath[32];size_t size;
};std::map<std::string, std::string> g_headerMap;
std::map<int, void *> g_connectionMap; //连接映射表,当多线程时,用于找到对应连接进行应答
std::string g_protocol; //协议,如http /1.1
std::string g_stateStr; //状态描述,用于返回应答int g_status = 200;  //应答状态
int g_connectId = 0; //连接id的分配std::mutex g_mutex;//用postman 测试,linux需要关闭防火墙,否则收不到数据
int main(int argc, char *argv[])
{   if(argc < 2){errorf("Usage: %s port\n", argv[0]);return 1;}int port = atoi(argv[1]);// webStart();struct userData uData{100};struct mg_mgr mgr;//mgr里的user_data指针将会指向第二个参数,当有连接过来时//mg_connection中的mgr中的user_data指向的就是第二个参数mg_mgr_init(&mgr, &uData);char buf[32] = {0};snprintf(buf, sizeof(buf), "%d", port);struct mg_connection *con = mg_bind(&mgr, buf, eventHandler);if(con == NULL) {errorf("mg_bind fail\n");return -1;}mg_set_protocol_http_websocket(con);uData.index = 200;infof("listen ip[%s], port[%d]....\n", inet_ntoa(con->sa.sin.sin_addr), port);//uri是/fileUpload 时调用函数fileUpload// mg_register_http_endpoint(con, "/fileUpload", fileUpload);while (1){mg_mgr_poll(&mgr, 100);}mg_mgr_free(&mgr);return 0;
}void fileUpload(mg_connection* nc, const int ev, void* data)
{struct FileInfo *userData = (struct FileInfo*)(nc->user_data);//当事件ev是MG_EV_HTTP_MULTIPART_REQUEST时,data类型是http_messagestruct http_message *hp = (struct http_message*)data;//当事件ev是MG_EV_HTTP_PART_BEGIN/MG_EV_HTTP_PART_DATA/MG_EV_HTTP_PART_END时,data类型是mg_http_multipart_partstruct mg_http_multipart_part *mp = (struct mg_http_multipart_part*)data;std::string value;switch(ev) {case MG_EV_HTTP_MULTIPART_REQUEST:{   ///query_string为请求地址中的变量std::string queryStr(hp->query_string.p, hp->query_string.len);infof("upload file request, queryStr = %s\n", queryStr.c_str());char fileName[32];std::string key("file_name");if(mg_get_http_var(&hp->query_string, key.c_str(), fileName, sizeof(fileName)) > 0) {infof("upload file request, %s = %s\n", key.c_str(), fileName); }mg_str *var;userData = (struct FileInfo *)malloc(sizeof(struct FileInfo));var = mg_get_http_header(hp, "Content-Length");std::string fileLen(var->p, var->len);tracef("userData = %p\n", userData);userData->size = std::atoi(fileLen.c_str());nc->user_data = (void *)userData;}break;case MG_EV_HTTP_PART_BEGIN:  ///这一步获取文件名tracef("upload file begin!\n");if(mp->file_name != NULL && strlen(mp->file_name) > 0) {infof("input fileName = %s, userData->filePath = %s\n", mp->file_name, userData->filePath);snprintf(userData->fileName, sizeof(userData->fileName), "%s", mp->file_name);userData->fp = fopen(userData->fileName, "wb+");if(userData->fp == NULL) {mg_printf(nc, "%s", "HTTP/1.1 500 file fail\r\n""Content-Length: 25\r\n""Connection: close\r\n\r\n""Failed to open a file\r\n");nc->flags |= MG_F_SEND_AND_CLOSE;free(userData);       return;}}break;case MG_EV_HTTP_PART_DATA:tracef("upload file push data!\n");if(mp->file_name != NULL && strlen(mp->file_name) > 0) {if(userData != NULL && userData->fp != NULL) {if(fwrite(mp->data.p, 1, mp->data.len, userData->fp) != mp->data.len) {mg_printf(nc, "%s","HTTP/1.1 500 write fail\r\n""Content-Length: 29\r\n\r\n""Failed to write to a file\r\n");nc->flags |= MG_F_SEND_AND_CLOSE;return;}                } else {mg_printf(nc, "%s","HTTP/1.1 500 write fail\r\n""Content-Length: 29\r\n\r\n""Failed to write to a file\r\n");errorf("send response to client in push data\n");          }///var_name 为form-data类型时的key, data里就为key对应的value} else if(mp->var_name != NULL && strlen(mp->var_name) > 0 && strcmp(mp->var_name, "path") == 0) {std::string filePath(mp->data.p, mp->data.len);infof("var_name = %s, value = %s\n", mp->var_name, filePath.c_str());snprintf(userData->filePath, sizeof(userData->filePath), "%s", filePath.c_str());}nc->flags |= MG_F_SEND_AND_CLOSE;break;case MG_EV_HTTP_PART_END:infof("file transfer end!\n");break;case MG_EV_HTTP_MULTIPART_REQUEST_END:if(userData != NULL && userData->fp != NULL) {mg_printf(nc,"HTTP/1.1 200 OK\r\n""Content-Type: text/plain\r\n""Connection: close\r\n\r\n""Written %ld of POST data to a file\n\n",(long)ftell(userData->fp));nc->flags |= MG_F_SEND_AND_CLOSE;fclose(userData->fp);tracef("upload file end, free userData(%p)\n", userData);free(userData);nc->user_data = NULL;           }        default:break;}
}bool isFile(const char *file) 
{if(file == nullptr) {errorf("file is null\n");return false;}const char *pFile = file + 1;FILE *fp = nullptr;fp = fopen(pFile, "rb");if(fp == nullptr) {errorf("no such file of %s\n", pFile);return false;}fclose(fp);return true;
}//把处理类加到webServer里
void webStart()
{std::shared_ptr<CNetworkAPI> network(new CNetworkAPI);CWebServer::instance()->addController(network);
}void eventHandler(struct mg_connection *nc, int event, void *eventData)
{switch (event){case MG_EV_ACCEPT:// tracef("a new accept!!\n");// nc->user_data = addConnection(nc); //delConnection时用uc进行connctionID的传递break;case MG_EV_HTTP_REQUEST:// tracef("a new http request!!\n");      handleRequest(nc, event, eventData);break;case MG_EV_CLOSE:// tracef("request close!!\n");delConnection(nc->user_data);nc->user_data = nullptr;break;default:break;}
}// 添加一个连接
void* addConnection(struct mg_connection *nc)
{userData *data = new userData; //此内存在delConnection时进行释放std::lock_guard<std::mutex> lockGuard(g_mutex);g_connectId += 1;data->index = g_connectId;g_connectionMap.insert(std::pair<int, void*>(g_connectId, nc));return data;
}// 删除一个连接
void delConnection(void *usrData)
{userData *data = (userData*)usrData;if(data == NULL){return;}if(g_connectionMap.find(data->index) != g_connectionMap.end()){tracef("delete connection id: %d\n", data->index);g_connectionMap.erase(data->index);}delete data; //释放addConnection时申请的内存
}void handleRequest(struct mg_connection *connection, int32_t event, void *data)
{struct http_message* msg = (struct http_message*)data;//请求正文std::string body(msg->body.p, msg->body.len);if(body.length() > 0){tracef("body size: %u, %s\n", body.length(), body.c_str());}//请求的地址,不包括ip地址和端口号std::string uri(msg->uri.p, msg->uri.len);// tracef("connect from ip: %s, uri = %s\n", inet_ntoa(connection->sa.sin.sin_addr), uri.c_str());//设置资源根目录if(uri == "/"){// tracef("url size: %lu, %s\n", uri.length(), url.c_str());struct mg_serve_http_opts opts;memset(&opts, 0, sizeof(opts));opts.enable_directory_listing = "yes";opts.document_root = "./";mg_serve_http(connection, msg, opts);}//请求的方法,GET、POST、PUT等std::string method(msg->method.p, msg->method.len);tracef("request method: %s\n", method.c_str());if(connection->mgr->user_data != NULL){struct userData *data = (userData*)connection->mgr->user_data;// tracef("mgr->user_data is not null, content = %d\n", data->index);}//保存头部信息,用于应答for (int32_t index = 0; index < MG_MAX_HTTP_HEADERS; ++index) {if (msg->header_names[index].p == nullptr || msg->header_names[index].len == 0) {continue;}std::string header(msg->header_names[index].p, msg->header_names[index].len);std::string value(msg->header_values[index].p, msg->header_values[index].len);// infof("head[%s] - value[%s]\n", header.c_str(), value.c_str());g_headerMap.insert(std::pair<std::string, std::string>(header, value));}//添加版本信息,应答使用g_headerMap.insert(std::pair<std::string, std::string>("web", "1.0"));//保存协议信息g_protocol = std::string(msg->proto.p, msg->proto.len);if(uri.length() > 1 && method == "GET" && isFile(uri.c_str())) {std::string file;// file.assign(uri, );httpFileResponse(connection, uri.c_str());} else {//尝试用webServer处理,获取处理结果进行返回Json::Value bodyData;controllerPtr handler = CWebServer::instance()->getController(uri);if(handler != nullptr){handler->process(method.c_str(), uri.c_str(), bodyData);}else{tracef("no find route[%s]\n", uri.c_str());bodyData["data"] = "404";}//应答httpResponse(connection, bodyData);        }}void setContent(Json::Value &content)
{Json::Value msg;msg["code"] = "0000111";msg["message"] = "success";msg["data"]["httpPort"] = 8080;msg["data"]["httpsPort"] = 8090;msg["data"]["rtspPort"] = 554;content = msg;
}/*严格按照http应答头格式进行填写:如果有正文,需要在头部字段里写明** 协议版本|空格|状态码|空格|状态码描述|回车|换行
** 头部字段名|冒号|字段值|回车|换行
** 头部字段名|冒号|字段值|回车|换行
** 头部字段名|冒号|字段值|回车|换行
** .....
** 回车|换行
** 响应正文*/
void httpResponse(struct mg_connection *connection, Json::Value &body) 
{std::string head(g_protocol);head.append(" ").append(std::to_string(g_status)).append(" ");if(g_stateStr.empty()){g_stateStr = mg_status_message(g_status); //获取对应的状态描述符}head.append(g_stateStr).append("\r\n");// Json::Value data;// setContent(data); std::string content = body.toStyledString();//添加响应报文长度,以让客户端快速读取消息setHeader("Content-Length", std::to_string(content.length()).c_str());//添加头部for(auto ite = g_headerMap.begin(); ite != g_headerMap.end(); ite++){head.append(ite->first).append(":").append(ite->second).append("\r\n");}//添加正文head.append("\r\n").append(content).append("\r\n");// tracef("send response: \n%s\n", head.c_str());mg_send(connection, head.c_str(), head.length());
}bool parseFileType(const char *fileName, std::string &fileType)
{char command[32] = {0};snprintf(command, sizeof(command), "%s %s", "file", fileName);FILE *fp = popen(command, "r");if(fp != NULL){char buf[1024] = {0};fread(buf, sizeof(buf) - 1 , 1, fp);// infof("buf string: %s\n", buf);int len = strlen(buf);if(len == 0){return false;}std::string parseStr(buf, len);if(parseStr.find("text") != std::string::npos){fileType = "text/html";}else if(parseStr.find("ELF") != std::string::npos ||parseStr.find("PE32") != std::string::npos){fileType = "application/octet-stream";}else if(parseStr.find("image") != std::string::npos){fileType = "image";if(parseStr.find("PNG") != std::string::npos){fileType.append("/png");}else if(parseStr.find("JPEG") != std::string::npos){fileType.append("/jpeg");}}else if(parseStr.find("bitmap") != std::string::npos){fileType = "image/bmp";}else if(parseStr.find("MPEG") != std::string::npos){fileType = "audio/mpeg";}else if(parseStr.find("MPEG v4") != std::string::npos){fileType = "video/mp4";}else  //默认为不确定的格式进行处理{fileType = "application/octet-stream";}pclose(fp);return true;}return false;
}int getFileType(const char *fileName)
{if(fileName == nullptr){return -1;}std::string parseStr(fileName);if(parseStr.find(".") == std::string::npos){return FILE_TYPE_UNKNOW;}else if(parseStr.find(".mp3") != std::string::npos){return FILE_TYPE_MP3;}else if(parseStr.find(".mp4") != std::string::npos){return FILE_TYPE_MP4;}else if(parseStr.find(".jpg") != std::string::npos || parseStr.find(".jpeg") != std::string::npos){return FILE_TYPE_JPEG;}else if(parseStr.find(".png") != std::string::npos){return FILE_TYPE_PNG;}else if(parseStr.find(".txt") != std::string::npos || parseStr.find(".html") != std::string::npos){return FILE_TYPE_REGULAR;}return FILE_TYPE_UNKNOW;
}void httpFileResponse(struct mg_connection *con, const char *fileName) {std::string head(g_protocol);head.append(" ").append(std::to_string(g_status)).append(" ");if(g_stateStr.empty()){g_stateStr = mg_status_message(g_status); //获取对应的状态描述符}head.append(g_stateStr).append("\r\n");//正文std::string content;const char *pFile = fileName + 1;FILE *fp = nullptr;fp = fopen(pFile, "r");if(fp == nullptr) {errorf("no such file of %s\n", pFile);setHeader("Content-Length", std::to_string(0).c_str());} else {fseek(fp, 0, SEEK_END);size_t len = ftell(fp);fseek(fp, 0, SEEK_SET);char *buffer = new char[len];fread(buffer, len, 1, fp);content.assign(buffer, len);//添加响应报文长度,以让客户端快速读取消息setHeader("Content-Length", std::to_string(len).c_str());delete []buffer;}//添加头部for(auto ite = g_headerMap.begin(); ite != g_headerMap.end(); ite++){head.append(ite->first).append(":").append(ite->second).append("\r\n");}int type = 0;std::string contentType;//可能没有 file 命令if(parseFileType(pFile, contentType)){head.append("Content-Type: ").append(contentType).append("\r\n");}else if((type = getFileType(pFile)) != -1){head.append("Content-Type: ").append(fileTypeStr[type]).append("\r\n");}else{errorf("no such file or directory!\n");return; }//添加正文head.append("\r\n").append(content).append("\r\n");mg_send(con, head.c_str(), head.length());
}bool hasHeader(const char *header)
{return g_headerMap.find(header) != g_headerMap.end();
}void setHeader(const char *header, const char *value)
{g_headerMap[header] = value;
}


http://chatgpt.dhexx.cn/article/GX97K9Ee.shtml

相关文章

Http中的Content-Type详解

Content-Type Content-Type&#xff08;MediaType&#xff09;&#xff0c;即是Internet Media Type&#xff0c;互联网媒体类型&#xff0c;也叫做MIME类型。在互联网中有成百上千中不同的数据类型&#xff0c;HTTP在传输数据对象时会为他们打上称为MIME的数据格式标签&#x…

HTTP(S)协议详解

1 什么是协议 协议&#xff0c;网络协议的简称&#xff0c;网络协议是通信计算机双方必须共同遵从的一组约定。如怎么样建立连接、怎么样互相识别等。只有遵守这个约定&#xff0c;计算机之间才能相互通信交流。 粗俗理解协议就是 比如你的电脑和我的电脑要通信&#xff0c;&a…

详解Http的Content-Type

目录 1.概述 2.常用类型 2.1.application/x-www-form-urllencoded 2.2.application/json 3.Spring MVC支持的编码 3.1.实验 3.2.适配器 3.3.自定义适配器 1.概述 HTTP&#xff08;HyperText Transfer Protocol&#xff09;&#xff0c;超文本传输协议。超文本&#xf…

Http协议之Content-Type理解

Content-Type&#xff0c;翻译过来就是”内容类型“&#xff0c;在互联网中就是”互联网媒体类型“。 在互联网中&#xff0c;两台计算机经常会传输数据&#xff0c;客户端会给服务器发数据&#xff0c;服务器也会给客户端发数据。数据的类型也是有很多种的&#xff0c;我们把所…

tomcat修改jdk配置两种方法

由于一个电脑多个项目,可能会使用多个版本的jdk,所以在跑tomcat的时候,可以自定义配置的各项目所使用的jdk 配置步骤(window设置): 1. 在catalina.bat找到如下代码: echo Using JAVA_HOME: “%JAVA_HOME%” 替换成 echo Using JAVA_HOME: “E:\Company\Tool\jdk1.7.0_13” 如…

linux下jdk配置

一、jdk下载 jdk下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads/ 二、配置环境变量 1、解压 tar -xvf jdk-11.0.13_linux-x64_bin.tar.gz 2、配置环境变量 修改/etc/profile文件 vim /etc/profile 文件末尾添加 #jdk JAVA_HOME/usr/local/a…

Mac多JDK配置

Mac多JDK配置 开发环境有时候需要配置多个JDK&#xff0c;Windows下配置比较方便&#xff0c;Mac环境下稍微有点曲折 下载对于的JDK 这里我以JDK8、JDK11为例&#xff0c;可以从oracle官网下载&#xff0c;也可以从国内源下载,比如华为源 直接安装后 执行如下命令可以快速…

eclipse及jdk配置

JDK(Java Development Kit)是Sun Microsystems针对Java开发员的产品。自从Java推出以来&#xff0c;JDK已经成为使用最广泛的Java SDK。JDK 是整个Java的核心&#xff0c;包括了Java运行环境&#xff0c;Java工具和Java基础的类库。JDK是学好Java的第一步。而专门运行在x86平台…

JDK配置Path的详细教程(包教包会)

在教程之前,先提示一下,新版本的JDK(比如17)是不需要我们配置的,因为我们在下载的时候已经自动给我们配置了,但是老版本(比如JDK8)是需要我们自己去配置的 OK,进入正题,我们先来说一下为什么要给jdk配置path环境? 首先,我们需要清楚的是jdk是java的开发工具,运行一个java程序…

多jdk配置

1.这里默认安装好jdk8和对应的环境变量,本文我们把jdk8的环境修改为jdk17(安装jdk17&#xff0c;下载安装版jdk17一直点下一步就行&#xff0c;没有好讲的) 2.系统CLASSPATH变量值为(下面都是在系统变量位置进行操作): .;%JAVA_HOME%\bin;%JAVA_HOME%\lib\tools.jar;%JAVA_HO…

Mac开发环境jdk配置

第一步&#xff1a; 下载JDK oracle 官网下载jdk版本 阿里云分享了已经在官方下载好的jdk8 阿里云盘分享https://www.aliyundrive.com/s/pNhjrrG3Pxf密码&#xff1a;8q8f 第二步骤&#xff1a;打开终端 第三步骤 &#xff1a;执行命令 查看JDK下载路径 执行命令&#xff1a;…

java中的jdk配置详解:

java中的jdk配置详解&#xff1a; 1.配值系统变量"JAVA_HOME" 变量名JAVA_HOME: 指向&#xff1a;JDK(java开发工具包)的安装路径 目的&#xff1a;使用JDK安装目录时&#xff0c;可以直接通过”%JAVA_HOME%“访问&#xff0c;避免路径过长麻烦 归一原则&#xff…

JAVA-JDK配置说明

JDK开发环境配置说明 JDK原理 JDK配置JDK与JRE区别 JDK下载地址 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html (注意查看本地电脑的版本&#xff0c;对应相同的系统&#xff0c;选择下载jdk) 目录 JDK开发环境配置说明 JDK下载地址…

jdk配置环境变量(win10)

jdk配置环境变量(win10) jdk跟环境变量的配置是学习java的必经之路&#xff01;你是否已经掌握呢&#xff1f; 1.下载安装jdk 官网下载&#xff1a;https://www.oracle.com/cn/java/technologies/downloads/#java8-windows 如果是要下载1.8版本的话&#xff0c;也可以用百度云…

linux JDK配置

1.JDK安装与配置 一般而言&#xff0c;Ubuntu系统会自带JDK&#xff0c;如果没有或者版本不合要求&#xff0c;可按以下步骤进行安装。步骤1 安装JDK。 步骤1 安装JDK。 将下载的.bin文件复制到Linux的某个目录下&#xff0c;比如/usr/lib/jvm/&#xff0c;然后在Shell中执行…

eclipse安装及jdk配置

一&#xff1a;eclipse的下载与安装 1、首先我们进入eclipse下载官网进行下载&#xff0c;链接为&#xff1a; Eclipse Downloads | The Eclipse Foundation 2、我们点击Download Packages选择其他类型的下载包&#xff1a; 3、Eclipse IDE for Java Developers 该版本适合Ja…

jdk配置环境变量

1.安装jdk&#xff0c;从官网下就行&#xff0c;我的是把原来的做了个备份&#xff0c;直接解压的。如下图 2.记录下你要配置的jdk路径。右键此电脑&#xff0c;属性&#xff0c;点击高级系统设置&#xff0c;选择环境变量。 3.现在就可以新建环境变量了。点击新建&#xff0c;…

JDK的安装与配置(含配置多个JDK)

对于Java学习者来说&#xff0c;一台电脑拿到手肯定要配置JDK&#xff0c;但是对于新手来说还是容易出错&#xff0c;我也是在安装了好几次之后才熟练&#xff0c;最近已经不满足JDK8了&#xff0c;想要配置多个JDK切换使用&#xff0c;所以写篇文章记录一下&#xff0c;希望也…

JDK的配置(附多个JDK配置方法)

第一步&#xff1a;下载并安装JDK 一、下载&#xff1a; JDK7和JDK8的安装包&#xff1a; https://pan.baidu.com/s/1nXOQ5KBJeA7YpllSX7spAQ 提取码&#xff1a;1201 二、安装&#xff1a; 安装一路next就完事了&#xff08;安装在便于寻找的文件夹下&#xff09; 注意&…

Jdk环境配置

以jdk8为例 1.打开jdk下载官网&#xff0c;下载jdk安装程序 https://www.oracle.com/java/technologies/downloads/#java8-windowsh 或者直接在此地址下载jdk8&#xff08;0积分&#xff09; jdk8安装包jdk-8u45-windows-x64-Java文档类资源-CSDN下载 2.打开安装程序 第一…