网络摄像头项目(Windows系统运行效果)
网络摄像头项目(Android系统运行效果)
网络摄像头项目(Linux系统运行效果)
这是基于C++(QT框架)设计的网络摄像头项目,本篇文章介绍的网络摄像头项目并不是采用RTMP或者RTSP推流编码的网络摄像头产品,而是采用HTTP协议推送图片流的方式,采用浏览器访问查看摄像头画面。
项目源码下载地址: https://download.csdn.net/download/xiaolong1126626497/21232910
这是软件运行截图:
这是浏览器访问截图:
项目运行的效果:
软件打开之后,先点击刷新信息,程序会扫描当前设备的摄像头和IP地址信息;并将访问的地址打印了出来,然后点击开启摄像头,界面就实时显示选择的摄像头画面。 在局域网内,其他设备打开浏览器,输入下面提示的地址访问,输入用户名和密码,即可查看到摄像头画面。程序里处理浏览器的请求是采用多线程方式,可以支持多个浏览器同时访问。
代码思路
代码采用的是C++(QT框架)编写,代码本身主要是分为两个部分:
1. 绑定指定端口号,创建TCP服务器,用来响应客户端的请求(浏览器)
2. 摄像头画面采集部分,摄像头数据采集采用单独的线程,采集之后将图像传递给界面刷新显示,并将图像填充到全局缓冲区,方便客户端处理线程将图像再传递给浏览器。
每当有新的浏览器访问进来,就会单独开辟一个线程,去处理这个浏览器接下来的通信交互,浏览器断开连接之后,线程自动销毁;图像缓冲区是一个公共的缓冲区,摄像头图像采集线程向该缓冲区填充数据,与浏览器通信的线程就从这个缓冲区读取数据,采用的是条件变量+互斥锁同步访问。
项目里用到的知识点主要是摄像头采集,线程处理、网络编程,HTTP协议等知识点。
如果是搞QT开发,都可以当做入门学习参考;如果想要用其他语言实现,思路搞清楚也很容易。 标准C语言。
在Linux下如果不需要界面,可以直接使用C语言完成项目效果,摄像头采集采用Linux下标准V4L2框架,线程就采用pthread_create创建,互斥锁、条件变量这些Linux都有,只要把程序思路搞清楚,实现起来还是很容易。
代码是采用QT框架编写,所以支持跨平台编译运行;目前代码在Android、Linux、windows系统上都编译运行通过,达到相同效果;由于身边没有苹果设备,暂时未做测试。
不同系统间代码上还是有少许区别,代码里通过宏的方式区分了,不同的系统运行不同的部分代码。
如果要编译QT的代码在Android设备上运行,得先搭建对应的开发环境;如果不会环境搭建,可以参考下面链接。
(1). Linux(ubuntu)下搭建QT Android开发环境
https://blog.csdn.net/xiaolong1126626497/article/details/117256660
(2). windows(win10 64bit)下搭建QT Android开发环境
https://blog.csdn.net/xiaolong1126626497/article/details/117254453
(3). windows下Qt + VS2017 环境安装
https://blog.csdn.net/xiaolong1126626497/article/details/112402861
QT版本: 5.12.6
编译器: MinGW 32
系统: Win10 Ubuntu18.04
程序运行时,需要用到一些资源文件,这些资源文件在程序的源码目录下,名称是: www。
如果是windows、Linux系统环境,需要把资源目录拷贝到程序运行的同级目录下。
如果是Android系统,这些资源文件需要在编译的时候打包进APK里,在工程目录下的Android目录里创建一个assets目录,将资源文件全部拷贝到assets目录下;程序编译的时候会自动将assets目录打包进apk,到时候Android程序运行时就可以直接去assets目录下获取资源文件。
当apk生成之后,可以解压出来看看,assets目录打包成功没有。
检查了下,打包成功的,这样Android程序运行时,访问的路径就没有问题。
由于我测试的环境是在虚拟机里运行ubuntu系统,要在ubuntu里访问摄像头,需要先把摄像头挂载到虚拟机,才能访问。如果打开虚拟机发现右下角托盘里摄像头图标都没有,说明托盘程序可能被360、电脑管家之类的安全软件禁止了,需要开启自动启动,重启VM虚拟机软件再测试。
直接挂载进来可能遇到摄像头打开了,但是图像无法获取的情况,这个问题可能是USB协议版本引起的。
可以在这里切换USB协议测试,我的笔记本电脑是USB3.0才可以正常使用。
代码开发时,主要是针对在windows平台运行的,所有程序里很多都是偏向于windows环境的设计。
构造函数里去除了系统原窗口标题栏,自定义了自己的标题;QT隐藏标题栏之后,是不能拖动拉伸的,需要自己实现,我这里采用的是GitHUB上开源的一个示例代码实现的这部分功能,效果不错,达到了想要的效果。剩下代码里初始化了托盘系统,方便程序最小化时,隐藏在windows系统的托盘图标栏里,其他的代码就是做写基本的初始化,信号槽的连接,IP地址、摄像头信息刷新等。
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//自定义标题栏
FramelessHelper *pHelper = new FramelessHelper(this);
setWindowFlags(Qt::FramelessWindowHint);
pHelper->activateOn(this); //激活当前窗体
//pHelper->setTitleHeight(m_pTitleBar->height()); //设置窗体的标题栏高度
pHelper->setWidgetMovable(true); //设置窗体可移动
pHelper->setWidgetResizable(true); //设置窗体可缩放
// pHelper->setRubberBandOnMove(true); //设置橡皮筋效果-可移动
// pHelper->setRubberBandOnResize(true); //设置橡皮筋效果-可缩放
/*基本设置*/
this->setWindowIcon(QIcon(":/log.ico")); //设置图标
this->setWindowTitle("网络摄像头");
//打开的窗口在屏幕中间
QDesktopWidget *widget= QApplication::desktop();
move((widget->width()-this->width())/2,(widget->height()-this->height())/2);
//刷新摄像头与IP地址信息
on_pushButton_config_clicked();
//刷新在线人数
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(timer_update()));
timer->start(1000);
tray= new QSystemTrayIcon(this);//初始化托盘对象tray
connect(tray,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(show_Widget(QSystemTrayIcon::ActivationReason)));
tray->setIcon(QIcon(QPixmap(":/log.png")));//设定托盘图标,引号内是自定义的png图片路径
tray->setToolTip("网络摄像头"); //提示文字
restoreAction = new QAction("打开", this);
connect(restoreAction, SIGNAL(triggered()), this, SLOT(show()));
quitAction = new QAction("退出", this);
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
trayMenu = new QMenu(this);
trayMenu->addAction(restoreAction);
trayMenu->addSeparator();
trayMenu->addAction(quitAction);
tray->setContextMenu(trayMenu);
work_class=new VideoReadThread_0;
work_thread=new QThread;
//启动摄像头的信号
connect(this,SIGNAL(StartWorkThread()),work_class,SLOT(run()));
//释放资源-释放摄像头
connect(this,SIGNAL(Stop_VideoAudioEncode_0()),work_class,SLOT(stop()));
//连接摄像头采集信号,在主线程实时显示视频画面
connect(work_class,SIGNAL(VideoDataOutput(QImage)),this,SLOT(VideoDataDisplay_0(QImage)));
//将类移动到子线程工作
work_class->moveToThread(work_thread);
}
摄像头采集采用的是QCamera + QVideoProbe实现。
初始化代码示例: 初始化代码里完成摄像头的一些参数,捕获模式,槽函数关联等设置。
初始化代码默认设置输出的图像格式是YUYV,在windows和Linux系统上是支持的,这个可能与摄像头有关,实际需要测试调整;Android系统上只支持NV21格式,如果是Android系统上运行,要记得修改格式。
void VideoReadThread_0::Camear_Init()
{
/*创建摄像头对象,根据选择的摄像头打开*/
camera = new QCamera(videoaudioencode_0.camera);
m_pProbe = new QVideoProbe;
if(m_pProbe != nullptr)
{
m_pProbe->setSource(camera); // Returns true, hopefully.
connect(m_pProbe, SIGNAL(videoFrameProbed(QVideoFrame)),this, SLOT(slotOnProbeFrame(QVideoFrame)), Qt::QueuedConnection);
}
else
{
qDebug()<<"m_pProbe == nullptr";
}
/*配置摄像头捕 QCamera *camera;
QVideoProbe *m_pProbe;获模式为帧捕获模式*/
camera->setCaptureMode(QCamera::CaptureVideo); //如果在Linux系统下运行就这样设置
//camera->setCaptureMode(QCamera::CaptureVideo);//如果在android系统下运行就这样设置
/*设置摄像头的采集帧率和分辨率*/
QCameraViewfinderSettings settings;
settings.setPixelFormat(QVideoFrame::Format_YUYV); //设置像素格式 Android上只支持NV21格式
settings.setResolution(QSize(VIDEO_WIDTH,VIDEO_HEIGHT)); //设置摄像头的分辨率
camera->setViewfinderSettings(settings);
/*启动摄像头*/
camera->start();
}
捕获到摄像头的图像数据之后,QVideoProbe会发出videoFrameProbed信号,在关联的槽函数里完成数据处理。
处理代码如下:
void VideoReadThread_0::slotOnProbeFrame(const QVideoFrame &frame)
{
// qDebug()<<"开始采集.";
QVideoFrame cloneFrame(frame);
cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
// qDebug()<<"height:"<<cloneFrame.height();
// qDebug()<<"width:"<<cloneFrame.width();
// qDebug()<<"bytesPerLine:"<<cloneFrame.bytesPerLine();
// qDebug()<<"mappedBytes:"<<cloneFrame.mappedBytes();
// qDebug()<<"pixelFormat:"<<cloneFrame.pixelFormat();
unsigned char rgb_buffer[VIDEO_WIDTH*VIDEO_HEIGHT*3];
if(cloneFrame.pixelFormat()==QVideoFrame::Format_YUYV)
{
yuyv_to_rgb(cloneFrame.bits(),rgb_buffer,cloneFrame.width(),cloneFrame.height());
}
else if(cloneFrame.pixelFormat()==QVideoFrame::Format_NV21)
{
NV21_TO_RGB24(cloneFrame.bits(),rgb_buffer,cloneFrame.width(),cloneFrame.height());
}
else
{
qDebug()<<"当前格式编码为%1,暂时不支持转换.\n";
return;
}
cloneFrame.unmap();
//加载图片数据
QImage image(rgb_buffer,
cloneFrame.width(),
cloneFrame.height(),
QImage::Format_RGB888);
//绘制图片水印
QDateTime dateTime(QDateTime::currentDateTime());
//时间效果: 2020-03-05 16:25::04 周一
QString qStr="";
qStr+=dateTime.toString("yyyy-MM-dd hh:mm:ss ddd");
QPainter pp(&image);
QPen pen = QPen(Qt::white);
pp.setPen(pen);
pp.setFont(QFont("宋体",20));
pp.drawText(QPointF(0,40),qStr);
mutex.lock();
QBuffer buff;
image.save(&buff,"jpg",80); // 30表示压宿率,值从0 – 100, 值越小表示编码出来的图像文件就越小,当然也就越不清晰
lcd_image_data=buff.data();
cond_wait.wakeAll();
mutex.unlock();
emit VideoDataOutput(image); //发送信号
}
代码里区分了数据格式,如果是YUYV就调用对应的转换函数将数据转为RGB格式,如果是NV21也是一样,调用对应的转换函数将数据转为RGB格式后续再做其他处理。
图像格式转换的代码如下:
/*
函数功能: 将YUV数据转为RGB格式
函数参数:
unsigned char *yuv_buffer: YUV源数据
unsigned char *rgb_buffer: 转换之后的RGB数据
int iWidth,int iHeight : 图像的宽度和高度
*/
void yuyv_to_rgb(unsigned char *yuv_buffer,unsigned char *rgb_buffer,int iWidth,int iHeight)
{
int x;
int z=0;
unsigned char *ptr = rgb_buffer;
unsigned char *yuyv= yuv_buffer;
for (x = 0; x < iWidth*iHeight; x++)
{
int r, g, b;
int y, u, v;
if (!z)
y = yuyv[0] << 8;
else
y = yuyv[2] << 8;
u = yuyv[1] - 128;
v = yuyv[3] - 128;
r = (y + (359 * v)) >> 8;
g = (y - (88 * u) - (183 * v)) >> 8;
b = (y + (454 * u)) >> 8;
*(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);
*(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);
*(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);
if(z++)
{
z = 0;
yuyv += 4;
}
}
}
void NV21_TO_RGB24(unsigned char *yuyv, unsigned char *rgb, int width, int height)
{
const int nv_start = width * height ;
int index = 0, rgb_index = 0;
uint8_t y, u, v;
int r, g, b, nv_index = 0,i, j;
for(i = 0; i < height; i++){
for(j = 0; j < width; j ++){
//nv_index = (rgb_index / 2 - width / 2 * ((i + 1) / 2)) * 2;
nv_index = i / 2 * width + j - j % 2;
y = yuyv[rgb_index];
u = yuyv[nv_start + nv_index ];
v = yuyv[nv_start + nv_index + 1];
r = y + (140 * (v-128))/100; //r
g = y - (34 * (u-128))/100 - (71 * (v-128))/100; //g
b = y + (177 * (u-128))/100; //b
if(r > 255) r = 255;
if(g > 255) g = 255;
if(b > 255) b = 255;
if(r < 0) r = 0;
if(g < 0) g = 0;
if(b < 0) b = 0;
index = rgb_index % width + (height - i - 1) * width;
//rgb[index * 3+0] = b;
//rgb[index * 3+1] = g;
//rgb[index * 3+2] = r;
//颠倒图像
//rgb[height * width * 3 - i * width * 3 - 3 * j - 1] = b;
//rgb[height * width * 3 - i * width * 3 - 3 * j - 2] = g;
//rgb[height * width * 3 - i * width * 3 - 3 * j - 3] = r;
//正面图像
rgb[i * width * 3 + 3 * j + 0] = b;
rgb[i * width * 3 + 3 * j + 1] = g;
rgb[i * width * 3 + 3 * j + 2] = r;
rgb_index++;
}
}
}
图像格式转换完成之后,下面就加载到QImage里,绘制上时间水印,将数据填充到缓冲区,然后再唤醒等待的线程,最后在传递一份数据给UI界面完成渲染显示。
如果使用过程中,摄像头支持的是其他格式,那么这里需要自己增加对应的转换函数。
这里是TCP客户端处理数据的线程,每当连接一个新的客户端,就会开辟一个新的线程独立运行。
线程里完成浏览器请求的处理,回应,交互。
完整的响应代码如下:
void TcpServerThread::run()
{
qDebug()<<"TcpServerThread_子线程run槽函数的ID:"<<QThread::currentThreadId();
QTcpSocket *tcpSocket;
tcpSocket=new QTcpSocket;
/*使用socketDescriptor套接字初始化QAbstractSocket*/
if(!tcpSocket->setSocketDescriptor(socketDescriptor))
{
return;
}
//读取接收的数据
QString text;
if(tcpSocket->waitForReadyRead())
{
text=tcpSocket->readAll();
}
//处理浏览器的请求
if(text.contains("GET / HTTP/1.1", Qt::CaseInsensitive))
{
//如果是Android系统
#ifdef Q_OS_ANDROID
text="assets:/login.html";
#else
text=QCoreApplication::applicationDirPath();
text+="/www/login.html";
#endif
SendFileData(buff,text,"text/html",tcpSocket);
}
else if(text.contains("GET /image.jpg HTTP/1.1", Qt::CaseInsensitive))
{
SendImageData(buff,tcpSocket);
}
else if(text.contains("GET /favicon.ico HTTP/1.1", Qt::CaseInsensitive))
{
#ifdef Q_OS_ANDROID
text="assets:/logo.ico";
#else
text=QCoreApplication::applicationDirPath();
text+="/www/logo.ico";
#endif
SendFileData(buff,text,"image/x-icon",tcpSocket);
}
else if(text.contains("GET /three.min.js", Qt::CaseInsensitive))
{
#ifdef Q_OS_ANDROID
text="assets:/three.min.js";
#else
text=QCoreApplication::applicationDirPath();
text+="/www/three.min.js";
#endif
SendFileData(buff,text,"application/x-javascript",tcpSocket);
}
else if(text.contains("GET /style.css", Qt::CaseInsensitive))
{
#ifdef Q_OS_ANDROID
text="assets:/style.css";
#else
text=QCoreApplication::applicationDirPath();
text+="/www/style.css";
#endif
SendFileData(buff,text,"text/css",tcpSocket);
}
else if(text.contains("GET /Stats.min.js", Qt::CaseInsensitive))
{
#ifdef Q_OS_ANDROID
text="assets:/Stats.min.js";
#else
text=QCoreApplication::applicationDirPath();
text+="/www/Stats.min.js";
#endif
SendFileData(buff,text,"application/x-javascript",tcpSocket);
}
else if(text.contains("GET /logo.png HTTP/1.1", Qt::CaseInsensitive))
{
#ifdef Q_OS_ANDROID
text="assets:/logo.png";
#else
text=QCoreApplication::applicationDirPath();
text+="/www/logo.png";
#endif
SendFileData(buff,text,"image/png",tcpSocket);
}
else if(text.contains("userName=admin&passWord=12345678", Qt::CaseInsensitive))
{
#ifdef Q_OS_ANDROID
text="assets:/index.html";
#else
text=QCoreApplication::applicationDirPath();
text+="/www/index.html";
#endif
SendFileData(buff,text,"text/html",tcpSocket);
}
//卸载连接的套接字
fd_list.Del_fd(socketDescriptor);
//关闭连接
tcpSocket->close();
delete tcpSocket;
}
/**
* 向浏览器响应请求数据
*/
int TcpServerThread::SendFileData(char *buff, QString file_path, const char *type, QTcpSocket *tcpSocket)
{
qint64 size=0;
/*1. 读取文件*/
QFile file(file_path);
if(file.open(QIODevice::ReadOnly)!=true)
{
qDebug()<<"文件不存在:"<<file_path<<endl;
return -1;
}
size=file.size(); //得到文件大小
QByteArray byte=file.readAll(); //读取所有数据
file.close();//关闭文件
/*2. 构建响应格式字符串*/
sprintf(buff,"HTTP/1.1 200 OK\r\n"
"Content-type:%s\r\n"
"Content-Length:%lld\r\n"
"\r\n",type,size);
/*3. 向客户端发送响应请求*/
if(tcpSocket->write(buff,strlen(buff))<=0)return -2;
tcpSocket->waitForBytesWritten(); //等待写
/*4. 向客户端发送响应实体数据*/
if(tcpSocket->write(byte)<=0)return -3;
tcpSocket->waitForBytesWritten(); //等待写
return 0;
}
/*
向客户端循环发送图片数据流
*/
int TcpServerThread::SendImageData(char *buff, QTcpSocket *tcpSocket)
{
/*1. 构建响应格式字符串*/
sprintf(buff,"HTTP/1.0 200 OK\r\n"
"Server: wbyq\r\n"
"Content-Type:multipart/x-mixed-replace;boundary=boundarydonotcross\r\n"
"\r\n"
"--boundarydonotcross\r\n");
/*2. 向客户端发送响应请求*/
if(tcpSocket->write(buff,strlen(buff))<=0)return -2;
tcpSocket->waitForBytesWritten(); //等待写
/*3. 循环发送数据*/
while(thread_run_flag)
{
//从全局缓冲区取数据
mutex.lock();
cond_wait.wait(&mutex);
QByteArray image_data; //保存一帧图像数据
image_data=lcd_image_data;
mutex.unlock();
// QBuffer data_buff;
// QPixmap pixmap;
// QScreen *screen = QGuiApplication::primaryScreen();
// pixmap=screen->grabWindow(0); //获取当前屏幕的图像
// //缩放图像
// pixmap = pixmap.scaled(lcd_image_w,lcd_image_h, Qt::KeepAspectRatio);
// pixmap.save(&data_buff,"jpg",image_val);
// QByteArray image_data1=data_buff.data();
/*4. 向浏览器发送响应头*/
sprintf(buff,"Content-type:image/jpeg\r\n"
"Content-Length:%d\r\n"
"\r\n",image_data.size());
if(tcpSocket->write(buff,strlen(buff))<=0)break;
tcpSocket->waitForBytesWritten(); //等待写
/*5. 发送实体数据*/
if(tcpSocket->write(image_data)<=0)break;
tcpSocket->waitForBytesWritten(); //等待写
/*6. 发送边界符*/
sprintf(buff,"\r\n--boundarydonotcross\r\n");
if(tcpSocket->write(buff,strlen(buff))<=0)break;
tcpSocket->waitForBytesWritten(); //等待写
//等待一段时间
msleep(5);
}
return 0;
}
当密码、账号验证通过之后,服务器就与浏览器建立长连接,循环发送图片流数据,浏览器完成连续刷新显示。 里面实现的思路,就是基本的TCP网络编程代码。
这个网络摄像头项目主要是与浏览器交互的,要完成浏览器的交互,首先得知道HTTP协议的报文格式,如何响应,下面只是介绍当前项目里用到的部分知识,方便理解第三章的浏览器交互代码。
HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,服务器传输超文本到本地浏览器的传送协议。 HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。
HTTP是无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
HTTP协议工作于客户端-服务端架构上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。
客户端请求消息 客户端发送一个HTTP请求到服务器的请求消息包括以下格式:请求行(request line)、请求头部(header)、空行和请求数据四个部分组成,下图给出了请求报文的一般格式。
服务器响应消息 HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。
HTTP协议常用的2种请求方法: GET, POST 方法。
1 | GET | 请求指定的页面信息,并返回实体主体。 |
---|---|---|
2 | POST | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 |
HTTP请求头提供了关于请求,响应或者其他的发送实体的信息。
应答头 | 说明 |
---|---|
Allow | 服务器支持哪些请求方法(如GET、POST等)。 |
Content-Encoding | 文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。Java的GZIPOutputStream可以很方便地进行gzip压缩,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet应该通过查看Accept-Encoding头(即request.getHeader("Accept-Encoding"))检查浏览器是否支持gzip,为支持gzip的浏览器返回经gzip压缩的HTML页面,为其他浏览器返回普通页面。 |
Content-Length | 表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。如果你想要利用持久连接的优势,可以把输出文档写入 ByteArrayOutputStream,完成后查看其大小,然后把该值放入Content-Length头,最后通过byteArrayStream.writeTo(response.getOutputStream()发送内容。 |
Content-Type | 表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置Content-Type,因此HttpServletResponse提供了一个专用的方法setContentType。 |
Date | 当前的GMT时间。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。 |
Expires | 应该在什么时候认为文档已经过期,从而不再缓存它? |
Last-Modified | 文档的最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置。 |
Location | 表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。 |
Refresh | 表示浏览器应该在多少时间之后刷新文档,以秒计。除了刷新当前文档之外,你还可以通过setHeader("Refresh", "5; URL=http://host/path")让浏览器读取指定的页面。 注意这种功能通常是通过设置HTML页面HEAD区的<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path">实现,这是因为,自动刷新或重定向对于那些不能使用CGI或Servlet的HTML编写者十分重要。但是,对于Servlet来说,直接设置Refresh头更加方便。 注意Refresh的意义是"N秒之后刷新本页面或访问指定页面",而不是"每隔N秒刷新本页面或访问指定页面"。因此,连续刷新要求每次都发送一个Refresh头,而发送204状态代码则可以阻止浏览器继续刷新,不管是使用Refresh头还是<META HTTP-EQUIV="Refresh" ...>。 注意Refresh头不属于HTTP 1.1正式规范的一部分,而是一个扩展,但Netscape和IE都支持它。 |
Server | 服务器名字。Servlet一般不设置这个值,而是由Web服务器自己设置。 |
Set-Cookie | 设置和页面关联的Cookie。Servlet不应使用response.setHeader("Set-Cookie", ...),而是应使用HttpServletResponse提供的专用方法addCookie。参见下文有关Cookie设置的讨论。 |
WWW-Authenticate | 客户应该在Authorization头中提供什么类型的授权信息?在包含401(Unauthorized)状态行的应答中这个头是必需的。例如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"")。 注意Servlet一般不进行这方面的处理,而是让Web服务器的专门机制来控制受密码保护页面的访问(例如.htaccess)。 |
当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。
当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头(server header)用以响应浏览器的请求。
HTTP状态码的英文为HTTP Status Code。
下面是常见的HTTP状态码: 200 - 请求成功 301 - 资源(网页等)被永久转移到其它URL 404 - 请求的资源(网页等)不存在 500 - 内部服务器错误
Content-Type,内容类型,一般是指网页中存在的Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,这就是经常看到一些Asp网页点击的结果却是下载到的一个文件或一张图片的原因。
HTTP content-type 对照表:
文件扩展名 | Content-Type(Mime-Type) | 文件扩展名 | Content-Type(Mime-Type) |
---|---|---|---|
.*( 二进制流,不知道下载文件类型) | application/octet-stream | .tif | image/tiff |
.001 | application/x-001 | .301 | application/x-301 |
.323 | text/h323 | .906 | application/x-906 |
.907 | drawing/907 | .a11 | application/x-a11 |
.acp | audio/x-mei-aac | .ai | application/postscript |
.aif | audio/aiff | .aifc | audio/aiff |
.aiff | audio/aiff | .anv | application/x-anv |
.asa | text/asa | .asf | video/x-ms-asf |
.asp | text/asp | .asx | video/x-ms-asf |
.au | audio/basic | .avi | video/avi |
.awf | application/vnd.adobe.workflow | .biz | text/xml |
.bmp | application/x-bmp | .bot | application/x-bot |
.c4t | application/x-c4t | .c90 | application/x-c90 |
.cal | application/x-cals | .cat | application/vnd.ms-pki.seccat |
.cdf | application/x-netcdf | .cdr | application/x-cdr |
.cel | application/x-cel | .cer | application/x-x509-ca-cert |
.cg4 | application/x-g4 | .cgm | application/x-cgm |
.cit | application/x-cit | .class | java/* |
.cml | text/xml | .cmp | application/x-cmp |
.cmx | application/x-cmx | .cot | application/x-cot |
.crl | application/pkix-crl | .crt | application/x-x509-ca-cert |
.csi | application/x-csi | .css | text/css |
.cut | application/x-cut | .dbf | application/x-dbf |
.dbm | application/x-dbm | .dbx | application/x-dbx |
.dcd | text/xml | .dcx | application/x-dcx |
.der | application/x-x509-ca-cert | .dgn | application/x-dgn |
.dib | application/x-dib | .dll | application/x-msdownload |
.doc | application/msword | .dot | application/msword |
.drw | application/x-drw | .dtd | text/xml |
.dwf | Model/vnd.dwf | .dwf | application/x-dwf |
.dwg | application/x-dwg | .dxb | application/x-dxb |
.dxf | application/x-dxf | .edn | application/vnd.adobe.edn |
.emf | application/x-emf | .eml | message/rfc822 |
.ent | text/xml | .epi | application/x-epi |
.eps | application/x-ps | .eps | application/postscript |
.etd | application/x-ebx | .exe | application/x-msdownload |
.fax | image/fax | .fdf | application/vnd.fdf |
.fif | application/fractals | .fo | text/xml |
.frm | application/x-frm | .g4 | application/x-g4 |
.gbr | application/x-gbr | . | application/x- |
.gif | image/gif | .gl2 | application/x-gl2 |
.gp4 | application/x-gp4 | .hgl | application/x-hgl |
.hmr | application/x-hmr | .hpg | application/x-hpgl |
.hpl | application/x-hpl | .hqx | application/mac-binhex40 |
.hrf | application/x-hrf | .hta | application/hta |
.htc | text/x-component | .htm | text/html |
.html | text/html | .htt | text/webviewhtml |
.htx | text/html | .icb | application/x-icb |
.ico | image/x-icon | .ico | application/x-ico |
.iff | application/x-iff | .ig4 | application/x-g4 |
.igs | application/x-igs | .iii | application/x-iphone |
.img | application/x-img | .ins | application/x-internet-signup |
.isp | application/x-internet-signup | .IVF | video/x-ivf |
.java | java/* | .jfif | image/jpeg |
.jpe | image/jpeg | .jpe | application/x-jpe |
.jpeg | image/jpeg | .jpg | image/jpeg |
.jpg | application/x-jpg | .js | application/x-javascript |
.jsp | text/html | .la1 | audio/x-liquid-file |
.lar | application/x-laplayer-reg | .latex | application/x-latex |
.lavs | audio/x-liquid-secure | .lbm | application/x-lbm |
.lmsff | audio/x-la-lms | .ls | application/x-javascript |
.ltr | application/x-ltr | .m1v | video/x-mpeg |
.m2v | video/x-mpeg | .m3u | audio/mpegurl |
.m4e | video/mpeg4 | .mac | application/x-mac |
.man | application/x-troff-man | .math | text/xml |
.mdb | application/msaccess | .mdb | application/x-mdb |
.mfp | application/x-shockwave-flash | .mht | message/rfc822 |
.mhtml | message/rfc822 | .mi | application/x-mi |
.mid | audio/mid | .midi | audio/mid |
.mil | application/x-mil | .mml | text/xml |
.mnd | audio/x-musicnet-download | .mns | audio/x-musicnet-stream |
.mocha | application/x-javascript | .movie | video/x-sgi-movie |
.mp1 | audio/mp1 | .mp2 | audio/mp2 |
.mp2v | video/mpeg | .mp3 | audio/mp3 |
.mp4 | video/mpeg4 | .mpa | video/x-mpg |
.mpd | application/vnd.ms-project | .mpe | video/x-mpeg |
.mpeg | video/mpg | .mpg | video/mpg |
.mpga | audio/rn-mpeg | .mpp | application/vnd.ms-project |
.mps | video/x-mpeg | .mpt | application/vnd.ms-project |
.mpv | video/mpg | .mpv2 | video/mpeg |
.mpw | application/vnd.ms-project | .mpx | application/vnd.ms-project |
.mtx | text/xml | .mxp | application/x-mmxp |
.net | image/pnetvue | .nrf | application/x-nrf |
.nws | message/rfc822 | .odc | text/x-ms-odc |
.out | application/x-out | .p10 | application/pkcs10 |
.p12 | application/x-pkcs12 | .p7b | application/x-pkcs7-certificates |
.p7c | application/pkcs7-mime | .p7m | application/pkcs7-mime |
.p7r | application/x-pkcs7-certreqresp | .p7s | application/pkcs7-signature |
.pc5 | application/x-pc5 | .pci | application/x-pci |
.pcl | application/x-pcl | .pcx | application/x-pcx |
application/pdf | application/pdf | ||
.pdx | application/vnd.adobe.pdx | .pfx | application/x-pkcs12 |
.pgl | application/x-pgl | .pic | application/x-pic |
.pko | application/vnd.ms-pki.pko | .pl | application/x-perl |
.plg | text/html | .pls | audio/scpls |
.plt | application/x-plt | .png | image/png |
.png | application/x-png | .pot | application/vnd.ms-powerpoint |
.ppa | application/vnd.ms-powerpoint | .ppm | application/x-ppm |
.pps | application/vnd.ms-powerpoint | .ppt | application/vnd.ms-powerpoint |
.ppt | application/x-ppt | .pr | application/x-pr |
.prf | application/pics-rules | .prn | application/x-prn |
.prt | application/x-prt | .ps | application/x-ps |
.ps | application/postscript | .ptn | application/x-ptn |
.pwz | application/vnd.ms-powerpoint | .r3t | text/vnd.rn-realtext3d |
.ra | audio/vnd.rn-realaudio | .ram | audio/x-pn-realaudio |
.ras | application/x-ras | .rat | application/rat-file |
.rdf | text/xml | .rec | application/vnd.rn-recording |
.red | application/x-red | .rgb | application/x-rgb |
.rjs | application/vnd.rn-realsystem-rjs | .rjt | application/vnd.rn-realsystem-rjt |
.rlc | application/x-rlc | .rle | application/x-rle |
.rm | application/vnd.rn-realmedia | .rmf | application/vnd.adobe.rmf |
.rmi | audio/mid | .rmj | application/vnd.rn-realsystem-rmj |
.rmm | audio/x-pn-realaudio | .rmp | application/vnd.rn-rn_music_package |
.rms | application/vnd.rn-realmedia-secure | .rmvb | application/vnd.rn-realmedia-vbr |
.rmx | application/vnd.rn-realsystem-rmx | .rnx | application/vnd.rn-realplayer |
.rp | image/vnd.rn-realpix | .rpm | audio/x-pn-realaudio-plugin |
.rsml | application/vnd.rn-rsml | .rt | text/vnd.rn-realtext |
.rtf | application/msword | .rtf | application/x-rtf |
.rv | video/vnd.rn-realvideo | .sam | application/x-sam |
.sat | application/x-sat | .sdp | application/sdp |
.sdw | application/x-sdw | .sit | application/x-stuffit |
.slb | application/x-slb | .sld | application/x-sld |
.slk | drawing/x-slk | .smi | application/smil |
.smil | application/smil | .smk | application/x-smk |
.snd | audio/basic | .sol | text/plain |
.sor | text/plain | .spc | application/x-pkcs7-certificates |
.spl | application/futuresplash | .spp | text/xml |
.ssm | application/streamingmedia | .sst | application/vnd.ms-pki.certstore |
.stl | application/vnd.ms-pki.stl | .stm | text/html |
.sty | application/x-sty | .svg | text/xml |
.swf | application/x-shockwave-flash | .tdf | application/x-tdf |
.tg4 | application/x-tg4 | .tga | application/x-tga |
.tif | image/tiff | .tif | application/x-tif |
.tiff | image/tiff | .tld | text/xml |
.top | drawing/x-top | .torrent | application/x-bittorrent |
.tsd | text/xml | .txt | text/plain |
.uin | application/x-icq | .uls | text/iuls |
.vcf | text/x-vcard | .vda | application/x-vda |
.vdx | application/vnd.visio | .vml | text/xml |
.vpg | application/x-vpeg005 | .vsd | application/vnd.visio |
.vsd | application/x-vsd | .vss | application/vnd.visio |
.vst | application/vnd.visio | .vst | application/x-vst |
.vsw | application/vnd.visio | .vsx | application/vnd.visio |
.vtx | application/vnd.visio | .vxml | text/xml |
.wav | audio/wav | .wax | audio/x-ms-wax |
.wb1 | application/x-wb1 | .wb2 | application/x-wb2 |
.wb3 | application/x-wb3 | .wbmp | image/vnd.wap.wbmp |
.wiz | application/msword | .wk3 | application/x-wk3 |
.wk4 | application/x-wk4 | .wkq | application/x-wkq |
.wks | application/x-wks | .wm | video/x-ms-wm |
.wma | audio/x-ms-wma | .wmd | application/x-ms-wmd |
.wmf | application/x-wmf | .wml | text/vnd.wap.wml |
.wmv | video/x-ms-wmv | .wmx | video/x-ms-wmx |
.wmz | application/x-ms-wmz | .wp6 | application/x-wp6 |
.wpd | application/x-wpd | .wpg | application/x-wpg |
.wpl | application/vnd.ms-wpl | .wq1 | application/x-wq1 |
.wr1 | application/x-wr1 | .wri | application/x-wri |
.wrk | application/x-wrk | .ws | application/x-ws |
.ws2 | application/x-ws | .wsc | text/scriptlet |
.wsdl | text/xml | .wvx | video/x-ms-wvx |
.xdp | application/vnd.adobe.xdp | .xdr | text/xml |
.xfd | application/vnd.adobe.xfd | .xfdf | application/vnd.adobe.xfdf |
.xhtml | text/html | .xls | application/vnd.ms-excel |
.xls | application/x-xls | .xlw | application/x-xlw |
.xml | text/xml | .xpl | audio/scpls |
.xq | text/xml | .xql | text/xml |
.xquery | text/xml | .xsd | text/xml |
.xsl | text/xml | .xslt | text/xml |
.xwd | application/x-xwd | .x_b | application/x-x_b |
.sis | application/vnd.symbian.install | .sisx | application/vnd.symbian.install |
.x_t | application/x-x_t | .ipa | application/vnd.iphone |
.apk | application/vnd.android.package-archive | .xap | application/x-silverlight-app |