>  기사  >  웹 프론트엔드  >  Node로 정적 파일 제공

Node로 정적 파일 제공

不言
不言원래의
2018-07-07 17:18:211197검색

이 글은 주로 Node를 사용하여 특정 참고 가치를 지닌 정적 파일 서비스를 소개합니다. 필요한 친구들이 참고할 수 있습니다.

머리말#🎜🎜 ## 🎜🎜#웹 애플리케이션의 경우 정적 파일(CSS, JavaScript, 이미지) 서비스를 제공해야 하는 경우가 많습니다. 이 기사에서는 자신만의 정적 파일 서버를 만드는 방법을 소개합니다.

정적 파일 서버 만들기

각 정적 파일 서버에는 파일 서비스를 제공하는 기본 디렉터리인 루트 디렉터리가 있습니다. 따라서 생성하려는 서버에서 정적 파일 서버의 루트 디렉터리 역할을 할 루트 변수를 정의해야 합니다.

var http = require('http')
var join = require('path').join
var fs = require('fs')

var root = __dirname

__dirname은 Node의 마법 변수이며 해당 값 is 파일이 있는 디렉터리의 경로입니다. 이 예에서 서버는 이 스크립트가 있는 디렉터리를 정적 파일의 루트 디렉터리로 사용합니다. 根目录,也就是提供文件服务的基础目录。所以我们要在即将创建的服务器上定义一个root变量,它将作为我们这个静态文件服务器的根目录:

var server = http.createServer(function(req, res){
  let path = join(root, req.url)
  let stream = fs.createReadStream(path)
  stream.on('data', function(chunk){
    res.write(chunk)
  })
  stream.on('end', function(){
    res.end()
  })
})

server.listen(3000)

__dirname 在Node中是一个神奇的变量,它的值是该文件所在目录的路径。在本例中,服务器会将这个脚本所在的目录作为静态文件的根目录。

有了文件的路径,还需要传输文件的内容。
这可以用fs.ReadStream完成,它是Node中Stream类之一。成功调用 fs.createReadStream() 会返回一个新的 fs.ReadStream 对象。
下面的代码实现了一个简单但功能完备的文件服务器。

var server = http.createServer(function(req, res){
  let path = join(root, req.url)
  let stream = fs.createReadStream(path)
  stream.pipe(res)
})

server.listen(3000)

这个文件服务器大体能用,但还有很多细节需要考虑。接下来我们要优化数据的传输,同时也精简一下服务器的代码。

用STREAM.PIPE()优化数据传输

虽然上面的代码看上去还不错,但Node还提供了更高级的实现机制:Stream.pipe()。用这个方法可以极大简化服务器的代码。 优化后代码如下:

ReadableStream.pipe(WritableStream)

这种写法,是不是更简单,更清晰了呢?

理解流和管道

流是Node中很重要的一个概念,你可以把Node中的管道想象成水管,如果你想让某个源头(比如热水器)流出来的水流到一个目的地(比如厨房的水龙头),可以在中间加一个管道把它们连起来,这样水就会顺着管道从源头流到目的地。
Node中的管道也是这样,但其中流动的不是水,而是来自源头(即ReadableStream)的数据,管道可以让它们“流动”到某个目的地(即WritableStream)。你可以用pipe方法把管道连起来:

let readStream = fs.createReadStream('./original.txt') 
let writeStream = fs.createWriteStream('./copy.txt') 
readStream.pipe(writeStream)

读取一个文件(ReadableStream)并把其中的内容写到另一个文件中(WritableStream)用的就是管道:

req.pipe(fs.createWriteStream('./req-body.txt'))

所有ReadableStream都能接入任何一个WritableStream。比如HTTP请求(req)对
象就是ReadableStream,你可以让其中的内容流动到文件中:

  stream.on('error', function(err){
    res.statusCode = 500
    res.end('服务器内部错误')
  })

运行

现在我们来运行上面的代码,我们在根目录下放一张图片,比如peiqi.jpg。
在浏览器中输入http://127.0.0.1:3000/peiqi.jpg,发现可爱的peiqi已经出现在你的面前了。peiqi.jpg被当作响应主体从http服务器送到了客户端(浏览器)。
Node로 정적 파일 제공

虽然已经品尝到了成功的滋味,但这个静态文件服务器还不够完整,因为它很容易出错。想象一下,如果用户不小心输入了一个并不存在的资源,比如abc.html,服务器就会马上崩掉。所以我们还得给这个文件服务器加上错误处理机制,让它足够健壮

处理服务器错误

在Node中,所有继承了EventEmitter的类都可能会发出error事件。为了监听错误,在fs.ReadStream上注册一个error事件处理器(比如下面这段代码),返回响应状态码500表明有服务器内部错误:

var server = http.createServer(function(req, res){
  let path = join(root, req.url)

  fs.stat(path, function(err, stat) {
    if (err) {
      if ('ENOENT' == err.code) {
        res.statusCode = 404
        res.end('Not Found')
      } else {
        res.statusCode = 500
        res.end('服务器内部错误')
      }
    } else { // 有该文件
      res.setHeader('Content-Length', stat.size)
      var stream = fs.createReadStream(path)
      stream.pipe(res)

      stream.on('error', function(err) { // 如果读取文件出错
        res.statusCode = 500
        res.end('服务器内部错误')
      })
    }
  })
})

server.listen(3000)

用fs.stat()实现错误处理

我们可以用fs.stat()来获取文件的相关信息,如果文件不存在,fs.stat()会在err.code中放入ENOENT
파일 경로와 함께 파일 내용도 함께 전송해야 합니다.

이 작업은 Node.js의 Stream 클래스 중 하나인 fs.ReadStream을 사용하여 수행할 수 있습니다. fs.createReadStream()에 대한 성공적인 호출은 새로운 fs.ReadStream 객체를 반환합니다.

아래 코드는 간단하지만 완전한 기능을 갖춘 파일 서버를 구현합니다.

rrreee

이 파일 서버는 일반적으로 작동하지만 고려해야 할 세부 사항이 많습니다. 다음으로 데이터 전송을 최적화하고 서버 코드를 간소화해야 합니다.

STREAM.PIPE()를 사용하여 데이터 전송 최적화

위 코드가 좋아 보이지만 Node에서는 더욱 고급 구현 메커니즘도 제공합니다: Stream.pipe(). 이 방법을 사용하면 서버 코드를 크게 단순화할 수 있습니다. 최적화된 코드는 다음과 같습니다.

rrreee

이렇게 작성하는 방법이 더 간단하고 명확할까요?

스트림 및 파이프 이해

Flow는 Node에서 매우 중요한 개념입니다. 특정 소스(예: 물 파이프)를 원할 경우 Node의 파이프를 생각할 수 있습니다. 온수기) ) 물이 목적지(예: 주방 수도꼭지)로 흘러나갑니다. 중간에 파이프를 추가하여 연결하면 물이 소스에서 목적지까지 파이프를 따라 흐를 수 있습니다.

Node의 파이프도 마찬가지지만 그 안에 흐르는 것은 물이 아니라 소스(예: ReadableStream)의 데이터입니다. 특정 대상(예: WritableStream) 파이프 방법을 사용하여 파이프를 연결할 수 있습니다:

rrreee

파일을 읽고(ReadableStream) 내용을 다른 파일에 쓰는 경우(WritableStream) 파이프를 사용합니다:

rrreee All ReadableStreams 모든 WritableStream에 연결될 수 있습니다. 예를 들어, HTTP 요청(req) 객체 는 ReadableStream이며 콘텐츠가 파일로 흐르도록 할 수 있습니다.
rrreee

Run #🎜🎜##🎜🎜#이제 실행해 보겠습니다. 위 코드에서는 peiqi.jpg와 같은 루트 디렉터리에 그림을 넣습니다. #🎜🎜#브라우저에 http://127.0.0.1:3000/peiqi.jpg를 입력하면 귀여운 페이치가 눈앞에 나타난 것을 확인할 수 있습니다. peiqi.jpg는 http 서버에서 클라이언트(브라우저)로 응답 본문으로 전송됩니다. #🎜🎜#405061481-5b3e2651bac82_articlex[1] .jpg#🎜🎜##🎜🎜#성공을 맛봤지만 이 정적 파일 서버는 오류가 발생하기 쉬우므로 완전하지 않습니다. 사용자가 실수로 abc.html과 같이 존재하지 않는 리소스를 입력하면 서버가 즉시 중단된다고 상상해 보십시오. 따라서 우리는 이 파일 서버를 충분히 견고하게 만들기 위해 오류 처리 메커니즘을 추가해야 합니다. #🎜🎜##🎜🎜#서버 오류 처리#🎜🎜##🎜🎜#Node에서 EventEmitter를 상속하는 모든 클래스는 오류 이벤트를 발생시킬 수 있습니다. 오류를 모니터링하려면 fs.ReadStream에 오류 이벤트 핸들러(예: 다음 코드)를 등록하고 응답 상태 코드 500을 반환하여 내부 서버 오류를 나타냅니다. #🎜🎜#rrreee#🎜🎜# fs.stat로 구현됨 () 오류 처리#🎜🎜##🎜🎜#fs.stat()를 사용하여 파일에 대한 관련 정보를 얻을 수 있습니다. 파일이 존재하지 않으면 fs.stat()가 해당 파일을 저장합니다. 응답으로 err.code ENOENT에서 오류 코드 404를 반환하여 클라이언트에 파일을 찾을 수 없음을 나타낼 수 있습니다. fs.stat()가 다른 오류 코드를 반환하는 경우 일반 오류 코드 500을 반환할 수 있습니다. #🎜🎜#리팩터링된 코드는 다음과 같습니다. #🎜🎜#rrreee#🎜🎜#Note#🎜🎜##🎜🎜#이 섹션에서 구축된 파일 서버는 단순화된 버전입니다. 이를 프로덕션 환경에 적용하려면 입력의 유효성을 더욱 철저하게 확인하여 사용자가 열려고 하지 않은 디렉터리 탐색 공격을 통해 콘텐츠의 일부에 액세스하는 것을 방지해야 합니다. #🎜🎜##🎜🎜#Summary#🎜🎜##🎜🎜#이 글을 읽고 나면 당신은 똑똑하고 Node를 사용하여 정적 서버를 만드는 방법을 마스터했다고 믿습니다. 다음 기사에서는 그 방법을 소개하겠습니다. Node를 사용하여 사용자를 처리하려면 파일을 업로드하고 서버에 저장하세요. #🎜🎜##🎜🎜#위 내용은 모두의 학습에 도움이 되기를 바랍니다. 더 많은 관련 내용은 PHP 중국어 홈페이지를 주목해주세요! #🎜🎜##🎜🎜#관련 권장 사항: #🎜🎜##🎜🎜##🎜🎜#Node를 사용하여 파일 업로드 처리#🎜🎜##🎜🎜##🎜🎜#

ES6 작성 방법을 사용하여 Redux 소스 코드의 일부 해석

위 내용은 Node로 정적 파일 제공의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.