中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

網(wǎng)站如何調(diào)用手機(jī)淘寶做淘寶客最近新聞?wù)?0字

網(wǎng)站如何調(diào)用手機(jī)淘寶做淘寶客,最近新聞?wù)?0字,營銷推廣策劃,電子商務(wù)網(wǎng)站營銷方案前言 大家好,我是老馬。很高興遇到你。 我們?yōu)?java 開發(fā)者實(shí)現(xiàn)了 java 版本的 nginx https://github.com/houbb/nginx4j 如果你想知道 servlet 如何處理的,可以參考我的另一個(gè)項(xiàng)目: 手寫從零實(shí)現(xiàn)簡易版 tomcat minicat 手寫 nginx 系列 …

前言

大家好,我是老馬。很高興遇到你。

我們?yōu)?java 開發(fā)者實(shí)現(xiàn)了 java 版本的 nginx

https://github.com/houbb/nginx4j

如果你想知道 servlet 如何處理的,可以參考我的另一個(gè)項(xiàng)目:

手寫從零實(shí)現(xiàn)簡易版 tomcat minicat

手寫 nginx 系列

如果你對(duì) nginx 原理感興趣,可以閱讀:

從零手寫實(shí)現(xiàn) nginx-01-為什么不能有 java 版本的 nginx?

從零手寫實(shí)現(xiàn) nginx-02-nginx 的核心能力

從零手寫實(shí)現(xiàn) nginx-03-nginx 基于 Netty 實(shí)現(xiàn)

從零手寫實(shí)現(xiàn) nginx-04-基于 netty http 出入?yún)?yōu)化處理

從零手寫實(shí)現(xiàn) nginx-05-MIME類型(Multipurpose Internet Mail Extensions,多用途互聯(lián)網(wǎng)郵件擴(kuò)展類型)

從零手寫實(shí)現(xiàn) nginx-06-文件夾自動(dòng)索引

從零手寫實(shí)現(xiàn) nginx-07-大文件下載

從零手寫實(shí)現(xiàn) nginx-08-范圍查詢

從零手寫實(shí)現(xiàn) nginx-09-文件壓縮

從零手寫實(shí)現(xiàn) nginx-10-sendfile 零拷貝

從零手寫實(shí)現(xiàn) nginx-11-file+range 合并

從零手寫實(shí)現(xiàn) nginx-12-keep-alive 連接復(fù)用

從零手寫實(shí)現(xiàn) nginx-13-nginx.conf 配置文件介紹

從零手寫實(shí)現(xiàn) nginx-14-nginx.conf 和 hocon 格式有關(guān)系嗎?

從零手寫實(shí)現(xiàn) nginx-15-nginx.conf 如何通過 java 解析處理?

從零手寫實(shí)現(xiàn) nginx-16-nginx 支持配置多個(gè) server

從零手寫實(shí)現(xiàn) nginx-17-nginx 默認(rèn)配置優(yōu)化

從零手寫實(shí)現(xiàn) nginx-18-nginx 請(qǐng)求頭響應(yīng)頭的處理

背景

最初感覺范圍處理和文件的處理不是相同的邏輯,所以做了拆分。

但是后來發(fā)現(xiàn)有很多公共的邏輯。

主要兩種優(yōu)化方式:

  1. 把范圍+文件合并到同一個(gè)文件中處理。添加各種判斷代碼

  2. 采用模板方法,便于后續(xù)拓展修改。

這里主要嘗試下第 2 種,便于后續(xù)的拓展。

代碼的相似之處

首先,我們要找到二者的相同之處。

range 主要其實(shí)是開始位置和長度,和普通的處理存在差異。

基礎(chǔ)文件實(shí)現(xiàn)

我們對(duì)常見的部分抽象出來,便于子類拓展

/*** 文件** @since 0.10.0* @author 老馬笑西風(fēng)*/
public class AbstractNginxRequestDispatchFile extends AbstractNginxRequestDispatch {/*** 獲取長度* @param context 上下文* @return 結(jié)果*/protected long getActualLength(final NginxRequestDispatchContext context) {final File targetFile = context.getFile();return targetFile.length();}/*** 獲取開始位置* @param context 上下文* @return 結(jié)果*/protected long getActualStart(final NginxRequestDispatchContext context) {return 0L;}protected void fillContext(final NginxRequestDispatchContext context) {long actualLength = getActualLength(context);long actualStart = getActualStart(context);context.setActualStart(actualStart);context.setActualFileLength(actualLength);}/*** 填充響應(yīng)頭* @param context 上下文* @param response 響應(yīng)* @since 0.10.0*/protected void fillRespHeaders(final NginxRequestDispatchContext context,final HttpRequest request,final HttpResponse response) {final File targetFile = context.getFile();final long fileLength = context.getActualFileLength();// 文件比較大,直接下載處理if(fileLength > NginxConst.BIG_FILE_SIZE) {logger.warn("[Nginx] fileLength={} > BIG_FILE_SIZE={}", fileLength, NginxConst.BIG_FILE_SIZE);response.headers().set(HttpHeaderNames.CONTENT_DISPOSITION, "attachment; filename=\"" + targetFile.getName() + "\"");}// 如果請(qǐng)求中有KEEP ALIVE信息if (HttpUtil.isKeepAlive(request)) {response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);}response.headers().set(HttpHeaderNames.CONTENT_TYPE, InnerMimeUtil.getContentTypeWithCharset(targetFile, context.getNginxConfig().getCharset()));response.headers().set(HttpHeaderNames.CONTENT_LENGTH, fileLength);}protected HttpResponse buildHttpResponse(NginxRequestDispatchContext context) {HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);return response;}/*** 是否需要壓縮處理* @param context 上下文* @return 結(jié)果*/protected boolean isZipEnable(NginxRequestDispatchContext context) {return InnerGzipUtil.isMatchGzip(context);}/*** gzip 的提前預(yù)處理* @param context  上下文* @param response 響應(yīng)*/protected void beforeZip(NginxRequestDispatchContext context, HttpResponse response) {File compressFile = InnerGzipUtil.prepareGzip(context, response);context.setFile(compressFile);}/*** gzip 的提前預(yù)處理* @param context  上下文* @param response 響應(yīng)*/protected void afterZip(NginxRequestDispatchContext context, HttpResponse response) {InnerGzipUtil.afterGzip(context, response);}protected boolean isZeroCopyEnable(NginxRequestDispatchContext context) {final NginxConfig nginxConfig = context.getNginxConfig();return EnableStatusEnum.isEnable(nginxConfig.getNginxSendFileConfig().getSendFile());}protected void writeAndFlushOnComplete(final ChannelHandlerContext ctx,final NginxRequestDispatchContext context) {// 傳輸完畢,發(fā)送最后一個(gè)空內(nèi)容,標(biāo)志傳輸結(jié)束ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);// 如果不支持keep-Alive,服務(wù)器端主動(dòng)關(guān)閉請(qǐng)求if (!HttpUtil.isKeepAlive(context.getRequest())) {lastContentFuture.addListener(ChannelFutureListener.CLOSE);}}@Overridepublic void doDispatch(NginxRequestDispatchContext context) {final FullHttpRequest request = context.getRequest();final File targetFile = context.getFile();final ChannelHandlerContext ctx = context.getCtx();logger.info("[Nginx] start dispatch, path={}", targetFile.getAbsolutePath());// 長度+開始等基本信息fillContext(context);// 響應(yīng)HttpResponse response = buildHttpResponse(context);// 添加請(qǐng)求頭fillRespHeaders(context, request, response);//gzipboolean zipFlag = isZipEnable(context);try {if(zipFlag) {beforeZip(context, response);}// 寫基本信息ctx.write(response);// 零拷貝boolean isZeroCopyEnable = isZeroCopyEnable(context);if(isZeroCopyEnable) {//zero-copydispatchByZeroCopy(context);} else {// 普通dispatchByRandomAccessFile(context);}} finally {// 最后處理if(zipFlag) {afterZip(context, response);}}}/*** Netty 之 FileRegion 文件傳輸: https://www.jianshu.com/p/447c2431ac32** @param context 上下文*/protected void dispatchByZeroCopy(NginxRequestDispatchContext context) {final ChannelHandlerContext ctx = context.getCtx();final File targetFile = context.getFile();// 分塊傳輸文件內(nèi)容final long actualStart = context.getActualStart();final long actualFileLength = context.getActualFileLength();try {RandomAccessFile randomAccessFile = new RandomAccessFile(targetFile, "r");FileChannel fileChannel = randomAccessFile.getChannel();// 使用DefaultFileRegion進(jìn)行零拷貝傳輸DefaultFileRegion fileRegion = new DefaultFileRegion(fileChannel, actualStart, actualFileLength);ChannelFuture transferFuture = ctx.writeAndFlush(fileRegion);// 監(jiān)聽傳輸完成事件transferFuture.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture future) {try {if (future.isSuccess()) {writeAndFlushOnComplete(ctx, context);} else {// 處理傳輸失敗logger.error("[Nginx] file transfer failed", future.cause());throw new Nginx4jException(future.cause());}} finally {// 確保在所有操作完成之后再關(guān)閉文件通道和RandomAccessFiletry {fileChannel.close();randomAccessFile.close();} catch (Exception e) {logger.error("[Nginx] error closing file channel", e);}}}});// 記錄傳輸進(jìn)度(如果需要,可以通過監(jiān)聽器或其他方式實(shí)現(xiàn))logger.info("[Nginx] file process >>>>>>>>>>> {}", actualFileLength);} catch (Exception e) {logger.error("[Nginx] file meet ex", e);throw new Nginx4jException(e);}}// 分塊傳輸文件內(nèi)容/*** 分塊傳輸-普通方式* @param context 上下文*/protected void dispatchByRandomAccessFile(NginxRequestDispatchContext context) {final ChannelHandlerContext ctx = context.getCtx();final File targetFile = context.getFile();// 分塊傳輸文件內(nèi)容long actualFileLength = context.getActualFileLength();// 分塊傳輸文件內(nèi)容final long actualStart = context.getActualStart();long totalRead = 0;try(RandomAccessFile randomAccessFile = new RandomAccessFile(targetFile, "r")) {// 開始位置randomAccessFile.seek(actualStart);ByteBuffer buffer = ByteBuffer.allocate(NginxConst.CHUNK_SIZE);while (totalRead <= actualFileLength) {int bytesRead = randomAccessFile.read(buffer.array());if (bytesRead == -1) { // 文件讀取完畢logger.info("[Nginx] file read done.");break;}buffer.limit(bytesRead);// 寫入分塊數(shù)據(jù)ctx.write(new DefaultHttpContent(Unpooled.wrappedBuffer(buffer)));buffer.clear(); // 清空緩沖區(qū)以供下次使用// process 可以考慮加一個(gè) listenertotalRead += bytesRead;logger.info("[Nginx] file process >>>>>>>>>>> {}/{}", totalRead, actualFileLength);}// 最后的處理writeAndFlushOnComplete(ctx, context);} catch (Exception e) {logger.error("[Nginx] file meet ex", e);throw new Nginx4jException(e);}}}

這樣原來的普通文件類只需要直接繼承。

范圍類重置如下方法即可:

/*** 文件范圍查詢** @since 0.7.0* @author 老馬嘯西風(fēng)*/
public class NginxRequestDispatchFileRange extends AbstractNginxRequestDispatchFile {private static final Log logger = LogFactory.getLog(AbstractNginxRequestDispatchFullResp.class);@Overrideprotected HttpResponse buildHttpResponse(NginxRequestDispatchContext context) {long start = context.getActualStart();// 構(gòu)造HTTP響應(yīng)HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,start < 0 ? HttpResponseStatus.OK : HttpResponseStatus.PARTIAL_CONTENT);return response;}@Overrideprotected void fillContext(NginxRequestDispatchContext context) {final long fileLength = context.getFile().length();final HttpRequest httpRequest = context.getRequest();// 解析Range頭String rangeHeader = httpRequest.headers().get("Range");logger.info("[Nginx] fileRange start rangeHeader={}", rangeHeader);long[] range = parseRange(rangeHeader, fileLength);long start = range[0];long end = range[1];long actualLength = end - start + 1;context.setActualStart(start);context.setActualFileLength(actualLength);}protected long[] parseRange(String rangeHeader, long totalLength) {// 簡單解析Range頭,返回[start, end]// Range頭格式為: "bytes=startIndex-endIndex"if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {String range = rangeHeader.substring("bytes=".length());String[] parts = range.split("-");long start = parts[0].isEmpty() ? totalLength - 1 : Long.parseLong(parts[0]);long end = parts.length > 1 ? Long.parseLong(parts[1]) : totalLength - 1;return new long[]{start, end};}return new long[]{-1, -1}; // 表示無效的范圍請(qǐng)求}}

小結(jié)

模板方法對(duì)于代碼的復(fù)用好處還是很大的,不然后續(xù)拓展特性,很多地方都需要修改多次。

下一節(jié),我們考慮實(shí)現(xiàn)一下 HTTP keep-alive 的支持。

我是老馬,期待與你的下次重逢。

開源地址

為了便于大家學(xué)習(xí),已經(jīng)將 nginx 開源

https://github.com/houbb/nginx4j

http://www.risenshineclean.com/news/5803.html

相關(guān)文章:

  • 常州市中大建設(shè)工程有限公司網(wǎng)站百度應(yīng)用商店app下載安裝
  • 班服定制網(wǎng)站百度發(fā)布信息的免費(fèi)平臺(tái)
  • 網(wǎng)站建設(shè)高端crm網(wǎng)站
  • 網(wǎng)站素材免費(fèi)網(wǎng)站seo優(yōu)化效果
  • 申請(qǐng)網(wǎng)頁空間的網(wǎng)站長沙本地推廣平臺(tái)
  • 網(wǎng)站設(shè)計(jì)公司 上seo賺錢方法大揭秘
  • 裝飾公司怎樣做網(wǎng)站交換友情鏈接的渠道
  • 通達(dá)oa 做網(wǎng)站企業(yè)培訓(xùn)權(quán)威機(jī)構(gòu)
  • 恐怖小說網(wǎng)站怎么做小廣告模板
  • 新媒體公司網(wǎng)站怎么做2345網(wǎng)址導(dǎo)航瀏覽器下載
  • 仿網(wǎng)站建設(shè)免費(fèi)b2b網(wǎng)站有哪些
  • 汕頭人才招聘網(wǎng)最新招聘信息北京seo全網(wǎng)營銷
  • 用c 做的網(wǎng)站怎么打開域名免費(fèi)注冊0元注冊
  • 攝影師簽約有哪些網(wǎng)站線上宣傳渠道
  • 成都娛樂場所關(guān)閉最新消息武漢建站優(yōu)化廠家
  • 中糧網(wǎng)站是哪個(gè)公司做的上海高端seo公司
  • 長春二道網(wǎng)站建設(shè)百度明星搜索量排行榜
  • 響應(yīng)式網(wǎng)站wordpress攝影家居seo整站優(yōu)化方案
  • 網(wǎng)站開發(fā)量計(jì)算百度一下你就知道移動(dòng)官網(wǎng)
  • 如何做商業(yè)推廣網(wǎng)站提高關(guān)鍵詞排名的軟文案例
  • 網(wǎng)站站點(diǎn)文件夾權(quán)限設(shè)置青島網(wǎng)站關(guān)鍵詞優(yōu)化公司
  • 中國做網(wǎng)站推廣哪家好武漢外包seo公司
  • 浦東新區(qū)消息今天淘寶seo什么意思
  • 網(wǎng)站怎么做三級(jí)的游戲優(yōu)化大師
  • 建行網(wǎng)站登錄不了荊門網(wǎng)絡(luò)推廣
  • 深圳網(wǎng)站制作必選祥奔科技域名訪問網(wǎng)站怎么進(jìn)入
  • 長沙理財(cái)網(wǎng)站建設(shè)魔方優(yōu)化大師官網(wǎng)
  • 網(wǎng)站做推廣頁需要什么軟件注冊公司
  • 在putty上怎樣安裝wordpress刷關(guān)鍵詞優(yōu)化排名
  • 如何給網(wǎng)站做301重定向搜索引擎有哪幾個(gè)網(wǎng)站